Skip to content

Commit

Permalink
Add Packer to build AMI
Browse files Browse the repository at this point in the history
  • Loading branch information
showwin committed Oct 11, 2024
1 parent 0c13169 commit 4ef54ce
Show file tree
Hide file tree
Showing 16 changed files with 356 additions and 35 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ ISUCONは3人チームで取り組むことを基準に課題が作られてい

## 問題詳細
* マニュアル: [ISHOCON1マニュアル](https://github.com/showwin/ISHOCON1/blob/master/doc/manual.md)
* AMI: `ami-0d00b2a9a38084503`
* AMI: `ami-06cda439fc5c0da1b`
* インスタンスタイプ: `c5.xlarge`
* 参考実装言語: Ruby, Go, Python
* メンテナンス外: Node.js(TypeScript), Crystal(by [@Goryudyuma](https://github.com/Goryudyuma)), Scala(by [@Goryudyuma](https://github.com/Goryudyuma))
Expand Down
14 changes: 14 additions & 0 deletions admin/.bashrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export PATH=$PATH:/usr/local/go/bin
export GOROOT=/usr/local/go
export GOPATH=$HOME/.local/go
export PATH="$HOME/.rbenv/bin:$PATH"
command -v rbenv >/dev/null && eval "$(rbenv init -)"
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
command -v pyenv >/dev/null && eval "$(pyenv init -)"

export ISHOCON1_DB_HOST="127.0.0.1"
export ISHOCON1_DB_PORT=3306
export ISHOCON1_DB_USER="ishocon"
export ISHOCON1_DB_PASSWORD="ishocon"
export ISHOCON1_DB_NAME="ishocon1"
File renamed without changes.
3 changes: 3 additions & 0 deletions ami/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
secret_vars.hcl
webapp.tar.gz
benchmarker.tar.gz
25 changes: 25 additions & 0 deletions ami/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[Packer](https://www.packer.io/)を使ってAMIの作成をする。

# How to use

## Prerequisites
* [Session Manager plugin for the AWS CLI](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html)

## Steps

```
$ cd ishocon1/ami
$ cp _secret_vars.hcl secret_vars.hcl
# Update your values at `secret_vars.hcl`
$ cd ../ && tar -zcvf ami/webapp.tar.gz ./webapp && cd ami
$ cd ../admin/ && tar -zcvf ../ami/benchmarker.tar.gz ./benchmarker && cd ../ami
$ packer init .
$ packer validate -var-file=shared_vars.hcl -var-file=secret_vars.hcl .
# This will take around 15 minutes to run
$ packer build -var-file=shared_vars.hcl -var-file=secret_vars.hcl ami.pkr.hcl
# You can see the AMI ID from the output
```
11 changes: 11 additions & 0 deletions ami/_secret_vars.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Subnet where we build AMI
subnet_id = "subnet-xxxxxxxx"

# Security Group ID of the builder EC2 instance
security_group_id = "sg-xxxxxxxx"

# SSH Key Pair name of the builder EC2 instance
ssh_keypair_name = "keypair_name"

# SSH Key file path to connect to the builder EC2 instance
ssh_private_key_file = "/path/to/your/private_key.pem"
168 changes: 168 additions & 0 deletions ami/ami.pkr.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
packer {
required_plugins {
amazon = {
version = ">= 1.2.7"
source = "github.com/hashicorp/amazon"
}
}
}

variable "source_ami" {
description = "The source AMI to use for the builder"
type = string
}

variable "region" {
description = "The region to build the image in"
type = string
default = "ap-northeast-1"
}

variable "security_group_id" {
description = "The ID of the security group Packer will associate with the builder to enable access"
type = string
default = null
}

variable "ssh_keypair_name" {
description = "The name of the SSH keypair to associate with the builder instance"
type = string
default = null
}

variable "ssh_private_key_file" {
description = "The path to the private key file to use for SSH connection to the builder instance"
type = string
default = null
}

variable "subnet_id" {
description = "If using VPC, the ID of the subnet, such as subnet-12345def, where Packer will launch the EC2 instance. This field is required if you are using an non-default VPC"
type = string
default = null
}

variable "instance_type" {
description = "The instance type Packer will use for the builder"
type = string
default = "c7i.xlarge"
}

variable "iam_instance_profile" {
description = "The IAM instance profile to associate with the builder"
type = string
default = null
}

source "amazon-ebs" "ishocon1" {
ami_name = "ishocon1-${formatdate("YYYYMMDD-hhmm", timestamp())}"
instance_type = var.instance_type
region = var.region
security_group_id = var.security_group_id
subnet_id = var.subnet_id
source_ami = var.source_ami

associate_public_ip_address = true
ssh_username = "ubuntu"
ssh_interface = "public_ip"
communicator = "ssh"
ssh_keypair_name = var.ssh_keypair_name
ssh_private_key_file = var.ssh_private_key_file

run_tags = {
Name = "ISHOCON1 AMI builder"
}

tags = {
Name = "ISHOCON1"
base_ami = "{{ .SourceAMI }}"
built_by = "https://github.com/showwin/ISHOCON1/tree/master/ami"
}

launch_block_device_mappings {
device_name = "/dev/sda1"
volume_size = 8
volume_type = "gp3"
delete_on_termination = true
}
}

build {
name = "ishocon1"
sources = [
"source.amazon-ebs.ishocon1"
]

# Init
provisioner "file" {
source = "./scripts/init.sh"
destination = "/tmp/init.sh"
}

provisioner "shell" {
inline = [
"sudo bash /tmp/init.sh"
]
}

# Base
provisioner "file" {
source = "./scripts/base.sh"
destination = "/tmp/base.sh"
}

provisioner "shell" {
inline = [
"sudo -u ishocon -H sh -c 'bash /tmp/base.sh'"
]
}

# WebApp
provisioner "file" {
source = "../admin/.bashrc"
destination = "/tmp/.bashrc"
}

provisioner "file" {
source = "../admin/nginx.conf"
destination = "/tmp/nginx.conf"
}

provisioner "file" {
source = "../admin/ishocon1.dump.tar.gz"
destination = "/tmp/ishocon1.dump.tar.gz"
}

provisioner "file" {
source = "./webapp.tar.gz"
destination = "/tmp/webapp.tar.gz"
}

provisioner "file" {
source = "./scripts/webapp.sh"
destination = "/tmp/webapp.sh"
}

provisioner "shell" {
inline = [
"sudo -u ishocon -H sh -c 'bash /tmp/webapp.sh'"
]
}

# Benchmarker
provisioner "file" {
source = "./benchmarker.tar.gz"
destination = "/tmp/benchmarker.tar.gz"
}

provisioner "file" {
source = "./scripts/benchmarker.sh"
destination = "/tmp/benchmarker.sh"
}

provisioner "shell" {
inline = [
"sudo -u ishocon -H sh -c 'bash /tmp/benchmarker.sh'"
]
}
}
41 changes: 41 additions & 0 deletions ami/scripts/base.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash
set -ex

cd /home/ishocon

# Install MySQL
sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password ishocon1'
sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password ishocon1'
sudo debconf-set-selections <<< 'mysql-service mysql-server/mysql-apt-config string 4'
sudo apt-get install -y mysql-server

# Install Ruby
export RUBY_VERSION=2.7.1
sudo apt-get install -y ruby-dev libmysqlclient-dev libffi-dev libyaml-dev bzip2
sudo apt-get clean
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
rbenv install $RUBY_VERSION && rbenv rehash && rbenv global $RUBY_VERSION

# Install Python
export PYTHON_VERSION=3.8.5
sudo apt-get install -y zlib1g-dev libbz2-dev libffi-dev libsqlite3-dev liblzma-dev libmariadb-dev pkgconf
sudo apt-get clean
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
pyenv install $PYTHON_VERSION && pyenv global $PYTHON_VERSION

# Install Go
export GO_VERSION=1.23.1
export TARGETARCH=amd64
sudo wget -q https://dl.google.com/go/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz
sudo tar -C /usr/local -xzf go${GO_VERSION}.linux-${TARGETARCH}.tar.gz
sudo rm go${GO_VERSION}.linux-${TARGETARCH}.tar.gz
export PATH=$PATH:/usr/local/go/bin
export GOROOT=/usr/local/go
export GOPATH=/home/ishocon/.local/go
export PATH=$PATH:$GOROOT/bin
9 changes: 9 additions & 0 deletions ami/scripts/benchmarker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash
set -ex
sudo su - ishocon
. /home/ishocon/.bashrc

cd /tmp/
tar -zxvf /tmp/benchmarker.tar.gz
cd /tmp/benchmarker
go build -x -o /home/ishocon/benchmark *.go
23 changes: 23 additions & 0 deletions ami/scripts/init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash
set -ex

export LANG=en_US.UTF-8
export LC_ALL=C.UTF-8
export TZ=Asia/Tokyo
sudo ln -snf /usr/share/zoneinfo/$TZ /etc/localtime
echo $TZ | sudo tee /etc/timezone

sudo apt-get update
sudo apt-get install -y sudo wget less vim tzdata nginx \
curl git gcc make libssl-dev libreadline-dev
sudo apt-get clean

# ishocon ユーザ作成
sudo groupadd -g 1001 ishocon
sudo useradd -g ishocon -G sudo -m -s /bin/bash ishocon
# sudo echo 'ishocon:ishocon' | chpasswd
echo 'ishocon ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/ishocon
sudo mkdir -m 775 /home/ishocon/webapp
sudo mkdir -m 777 /home/ishocon/data
sudo chown -R ishocon:ishocon /home/ishocon
sudo chmod 777 /home/ishocon
41 changes: 41 additions & 0 deletions ami/scripts/webapp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash
set -ex

# Move files
cp /tmp/.bashrc /home/ishocon/.bashrc
sudo cp /tmp/nginx.conf /etc/nginx/nginx.conf
cp /tmp/ishocon1.dump.tar.gz /home/ishocon/data/ishocon1.dump.tar.gz
cd /home/ishocon
tar -zxvf /tmp/webapp.tar.gz
chown -R ishocon:ishocon /home/ishocon/webapp

# Load .bashrc
. /home/ishocon/.bashrc

# # Install Ruby libraries
cd /home/ishocon/webapp/ruby
gem install bundler -v "1.16.1"
bundle install

# # Install Python libraries
cd /home/ishocon/webapp/python
sudo apt-get install -y libmysqlclient-dev
pip install -r requirements.txt

# Install Go libraries
ls /home/ishocon
ls /home/ishocon/webapp
cd /home/ishocon/webapp/go
go build -o webapp *.go

# Load data into MySQL
sudo chown -R mysql:mysql /var/lib/mysql
sudo service mysql start
sudo mysql -u root -pishocon1 -e 'CREATE DATABASE IF NOT EXISTS ishocon1;'
sudo mysql -u root -pishocon1 -e "CREATE USER IF NOT EXISTS ishocon IDENTIFIED BY 'ishocon';"
sudo mysql -u root -pishocon1 -e 'GRANT ALL ON *.* TO ishocon;'
tar -zxvf ~/data/ishocon1.dump.tar.gz -C ~/data && sudo mysql -u root -pishocon1 ishocon1 < ~/data/ishocon1.dump

# Nginx
sudo nginx -t
sudo service nginx start
2 changes: 2 additions & 0 deletions ami/shared_vars.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Ubuntu Server 24.04 LTS (HVM)
source_ami = "ami-0b20f552f63953f0e"
Loading

0 comments on commit 4ef54ce

Please sign in to comment.