edo1z blog

プログラミングなどに関するブログです

EC2をAutoスケール・自動デプロイさせる

ALBにつなげるEC2を自動スケールさせます。またデプロイは複数のEC2に自動でデプロイしたいので、CodeDeployを使ってみました。CodeDeployは、S3にプッシュして、それを利用してデプロイするようにしました。CodeDeployが自動デプロイする際、プロジェクトルートにある appspac.yml というファイルの内容に従います。下記のような感じにしましした。

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/app/hoge
permissions:
  - object: /home/ec2-user/app/hoge
    pattern: "**"
    owner: ec2-user
    group: ec2-user
hooks:
  BeforeInstall:
    - location: deploy/remove.sh
      timeout: 30
      runas: ec2-user
  AfterInstall:
    - location: deploy/set_env.sh
      timeout: 5
      runas: ec2-user
  ApplicationStart:
    - location: deploy/reload_pm2.sh
      timeout: 60
      runas: ec2-user

ちなみに、app/hoge 配下にでデプロイするプログラムはAdonis.jsのアプリです。CodeDeployは、デプロイ先にファイルがあるとエラーになるようです。ですので、BeforeInstall 時にapp/hoge内を空にしてます。set_env.shでは、下記のような感じで、環境に応じて.envファイルを作成しています。ApplicationStart時に、pm2 resurrectを実行して、Adonis.jsアプリを起動しています。ただ、結構デプロイ完了までに時間がかかりますね。特にテスト環境では頻繁にgit pullしたくなりそうなので、テスト環境では基本的にはgitを使うことになるのかなと思いました。

#!/bin/bash
Pro="hoge"
Region="us-east-1"
InstanceID=`curl -s http://169.254.169.254/latest/meta-data/instance-id/`
TagName=`aws ec2 describe-instances --region ${Region} --instance-ids ${InstanceID} --query 'Reservations[].Instances[].Tags[?Key==\`Name\`].Value' --output text`
cd /home/ec2-user/app/hoge
rm .env
if [ $TagName = $Pro ]; then
  ln -s .env.pro .env
else
  ln -s .env.dev .env
fi

あとはプライベートIPアドレスが、デプロイの度に変わります。Blue/Greenデプロイを利用しなければ変わらないで済むかもしれませんが、Blue/Greenの方が安全そうだし、ロールバックできるしいいかなと思いました。あとは自動スケール設定にするとどちらにしても、IPアドレスは変わるのかなと思います。基本的に変わっても全く問題ないのですが、sshの際にちょっとめんどくさいかなと思ったので、下記も作りました。

#/bin/bash
Region="us-east-1"
TagNameOfPro="pro-hoge"
TagNameOfDev="dev-hoge"
HostOfPro="pro-hoge"
HostOfDev="dev-hoge"

if [ $1 = "pro" ]; then
  echo "Env: pro"
  TagName=$TagNameOfPro
  Host=$HostOfPro
else
  echo "Env: dev"
  TagName=$TagNameOfDev
  Host=$HostOfDev
fi

echo TagName: $TagName
echo Host: $Host

IP=`aws ec2 describe-instances --region ${Region} --query 'Reservations[].Instances[].[PrivateIpAddress][0][0]' --filters "Name=tag:Name,Values=${TagName}" "Name=instance-state-code,Values=16"`
echo IP: $IP
ssh -o HostName=${IP} ${Host}

上記の$Hostは、./ssh/configで設定しているHostになります。例えば下記のようになっています。

Host pro-hoge
  HostName 192.168.0.0
  User ec2-user
  ProxyCommand ssh -W %h:%p bastion
  Port 22
  IdentityFile ~/.ssh/pro-hoge.pem
  LocalForward 3337 pro-hoge-cluster.cluster-***********.us-east-1.rds.amazonaws.com:3306

ssh接続する際に基本的にはこの設定を使いつつ、-oオプションを使って、HostName(IPアドレス)だけは、コマンド実行時に直接指定するようにしています。そのIPアドレスを、現在稼働中の環境から取得しています。 ec2 describe-instancesfiltersinstance-state-code というのは、稼働中とか停止中とかを数値で表しているものだそうです。稼働中の場合は16だそうです。

デプロイコマンド

S3にプッシュして、その後でデプロイを開始します。

#/bin/bash
if [ $1 = "pro" ]; then
  aws deploy push --application-name hoge-pro --s3-location s3://hoge-revision/hoge-pro.zip --source .
  aws deploy create-deployment --application-name hoge-pro --deployment-group-name hoge-pro --s3-location bucket=hoge-revision,key=hoge-pro.zip,bundleType=zip
else
  aws deploy push --application-name hoge-dev --s3-location s3://hoge-revision/hoge-dev.zip --source .
  aws deploy create-deployment --application-name hoge-dev --deployment-group-name hoge-dev --s3-location bucket=hoge-revision,key=hoge-dev.zip,bundleType=zip
fi