この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
超おはようございます、暑さにはめっきり弱い城内です。 冬の寒さも苦手ですが、夏の暑さは汗をかくのが嫌ですね。
はじめに
さて、今回は以下の記事に出てきたBeanstalkのアプリケーションデプロイを自動化するスクリプトを紹介したいと思います。
上記で紹介されているものと何が違うかというと、ファイルをトリガーにデプロイを実行するという点です。 今回のスクリプトをEC2上で定期実行しておけば、SSHログインすることなく、SFTP等でトリガーファイルをアップロードするだけでアプリケーションをデプロイできるようになります。
構成図
今回は、以前記事にしたGravを使ったCMSシステムを使用します。もちろん、WordPressでも実装することは可能です。
セットアップ
手順
セットアップ手順は、以下のステップになります。
- MasterサーバにIAMロールを付与する
- BashスクリプトをMasterサーバに配置する
- BashスクリプトをCronに設定する(ここでトリガーファイルの格納先とファイル名が決まる)
- トリガーファイルを作成する
IAMロール
IAMロールのポリシーは、以下の感じになります。 (もっと制限することも可能ですが、Beanstalkの内部処理に関わってきますので、必要なものを洗い出すのは結構大変です)
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"elasticbeanstalk:CreateApplicationVersion",
"elasticbeanstalk:UpdateEnvironment"
],
"Effect": "Allow",
"Resource": [
"arn:aws:elasticbeanstalk:ap-northeast-1:123456789012:applicationversion/grav-test/*",
"arn:aws:elasticbeanstalk:ap-northeast-1:123456789012:environment/grav-test/grav-test-prod"
],
"Condition": {
"StringEquals": {
"elasticbeanstalk:InApplication": [
"arn:aws:elasticbeanstalk:ap-northeast-1:123456789012:application/grav-test"
]
}
}
},
{
"Action": [
"s3:*",
"autoscaling:*",
"cloudformation:*",
"ec2:*",
"elasticloadbalancing:*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
スクリプト
スクリプトは、以下のBashスクリプトになります。前提として、AWS CLIが使用できる(リージョン指定をお忘れなく)ようになってさえいれば、特に変数定義等の必要もなくそのまま使用できるはずです。 これをMasterサーバの任意のディレクトリに配置してください。
eb_auto_deploy.sh
#!/bin/bash
### Variables
label_prefix="grav_"
### Function
function usage {
echo "Usage: ${0##*/} trigger_file"
exit 0
}
function myecho {
echo "${0##*/}: $1"
}
### Main
if [ $# -ne 1 ]; then
usage
fi
trigger_file=$1
if [ ! -f $trigger_file ]; then
myecho "$(date '+%Y/%m/%d %H:%M:%S') [INFO] $trigger_file does not exist."
exit 0
fi
error_file="${trigger_file}.err"
if [ -f $error_file ]; then
myecho "$(date '+%Y/%m/%d %H:%M:%S') [WARNING] The deployment was canceled because an error file existed."
exit 1
fi
myecho "$(date '+%Y/%m/%d %H:%M:%S') [INFO] EB auto deploy start."
grep -ve "^#" -e "^$" $trigger_file |
while read source_dir region s3_path eb_app eb_env pre_cmd
do
export AWS_DEFAULT_REGION=$region
s3_bucket="${s3_path%%/*}"
s3_key="${s3_path#*/}"
if [ "$s3_bucket" = "$s3_key" ]; then
s3_key=""
else
s3_key="${s3_key}/"
fi
if [ "$pre_cmd" ]; then
($pre_cmd)
if [ $? -ne 0 ]; then
myecho "[ERROR] PreExec command failed." | tee -a $error_file
continue
fi
fi
ver_label="${label_prefix}$(date '+%Y%m%d%H%M%S')"
(cd $source_dir && zip -ry /tmp/${ver_label}.zip . 1>/dev/null && aws s3 cp /tmp/${ver_label}.zip s3://${s3_path}/ && rm -f /tmp/${ver_label}.zip)
if [ $? -ne 0 ]; then
myecho "[ERROR] Application upload failed." | tee -a $error_file
continue
fi
aws elasticbeanstalk create-application-version --application-name $eb_app --version-label $ver_label --source-bundle S3Bucket=${s3_bucket},S3Key=${s3_key}${ver_label}.zip
if [ $? -ne 0 ]; then
myecho "[ERROR] EB application regist failed." | tee -a $error_file
continue
fi
aws elasticbeanstalk update-environment --environment-name $eb_env --version-label $ver_label
if [ $? -ne 0 ]; then
myecho "[ERROR] EB application deploy failed." | tee -a $error_file
continue
fi
done
if [ -f $error_file ]; then
rc=1
else
rc=0
rm -f $trigger_file
fi
myecho "$(date '+%Y/%m/%d %H:%M:%S') [INFO] EB auto deploy end.(RC=${rc})"
exit $rc
スクリプトの仕組みとしては、引数に渡されるトリガーファイルを読み込んで、そこに定義されている情報を基に、Beanstalkのデプロイを実行するだけです(トリガーファイルの定義内容は後述します)。 そして、処理が成功した場合は、最後にトリガーファイルが削除されます。もし処理が失敗した場合は、エラーファイルを出力し、次回以降の処理がスキップされるようになっています。トリガーファイルは削除されないため、エラーファイルを削除すれば、次のサイクルから処理が再開されます。
Cron設定
MasterサーバにアップロードしたスクリプトをCronに設定します。 今回はrootユーザに設定しましたが、権限の設定をうまく調整すれば別のユーザでも可能です。
# crontab -e
0,15,30,45 * * * * /root/scripts/eb_auto_deploy.sh /eb_deploy/grav.tsv >> /eb_deploy/logs/eb_auto_deploy_`date "+\%Y\%m\%d"`.log 2>&1
15分毎の実行で、トリガーファイルは/eb_deploy/grav.tsvにしています。あとは、一応ログも出力しておきます。 (今回の設定では、別途ログパージの仕組みが必要になります)
トリガーファイル
トリガーファイルのフォーマットは、タブ区切りで1レコードに以下の項目を記述します。 ※なぜタブ区切りなの!?と思われる方は、スクリプトを修正しちゃってください(笑)。私も気に入ってはいませんので。
- Beanstalkにデプロイするソースディレクトリ(絶対パス)
- リージョン名
- S3バケットの格納先(バケット名を含むパス)
- Beanstalkのアプリケーション名
- Beanstalkの環境名
- 自動デプロイ処理の前に事前実行したいコマンドライン(ワンライナーで)
以下のような内容になります(先頭に「#」でコメントアウトできます)。
# Source directory Region S3 path Elastic Beanstalk application Elastic Beanstalk environment PreExec command
/var/www/html ap-northeast-1 cm-grav-test/resource grav-test grav-test-prod cd /var/www/html && sudo php bin/grav clear-cache --all && aws s3 sync /var/www/html/user/images s3://cm-grav-test/user/images
実行
あとは、grav.tsvファイルを/eb_deployディレクトリにおいて、時を待つだけです。
# ls -l
total 8
-rw-r--r-- 1 root root 291 Jul 29 20:41 grav.tsv
drwxr-xr-x 2 root root 4096 Jul 30 00:00 logs
# date
Thu Jul 30 00:02:40 JST 2015
...
# date
Thu Jul 30 00:18:04 JST 2015
# ls -l
total 4
drwxr-xr-x 2 root root 4096 Jul 30 00:04 logs
# cat logs/eb_auto_deploy_20150730.log
eb_auto_deploy.sh: 2015/07/30 00:00:01 [INFO] /eb_deploy/grav.tsv does not exist.
eb_auto_deploy.sh: 2015/07/30 00:15:01 [INFO] EB auto deploy start.
upload: /tmp/grav_20150730001501.zip to s3://cm-grav-test/resource/grav_20150730001501.zip
{
"ApplicationVersion": {
"ApplicationName": "grav-test",
"VersionLabel": "grav_20150730001501",
"SourceBundle": {
"S3Bucket": "cm-grav-test",
"S3Key": "resource/grav_20150730001501.zip"
},
"DateUpdated": "2015-07-29T15:15:03.857Z",
"DateCreated": "2015-07-29T15:15:03.857Z"
}
}
{
"ApplicationName": "grav-test",
"EnvironmentName": "grav-test-prod",
"VersionLabel": "grav_20150730001501",
"Status": "Updating",
"EnvironmentId": "e-12345abcde",
"EndpointURL": "11.22.33.44",
"SolutionStackName": "64bit Amazon Linux 2015.03 v1.4.3 running PHP 5.6",
"CNAME": "grav-test-prod.elasticbeanstalk.com",
"Health": "Grey",
"AbortableOperationInProgress": true,
"Tier": {
"Version": " ",
"Type": "Standard",
"Name": "WebServer"
},
"DateUpdated": "2015-07-29T15:15:04.535Z",
"DateCreated": "2015-07-26T15:24:02.735Z"
}
eb_auto_deploy.sh: 2015/07/30 00:15:05 [INFO] EB auto deploy end.(RC=0)
上記がサーバ上の実行結果で、以下がマネージメントコンソール上での実行結果です。
うまくデプロイできていますね。
さいごに
そんなに大した仕組みではありませんが、SFTPだけでデプロイができるというのは、Beanstalk利用の敷居を下げられるものだと思っていますので、もしよかったらぜひ使ってみてください!