elastic beanstalkをimmutableに運用する
AWSのelastic beanstalkはURLスワップ機能やauto scalingによるインスタンス増減機能があるため、immutable infrastructureやblue-green deploymentの文脈で語られることが多いかと思いますが、実際に運用しようとすると考えなければいけないことがたくさんあります。
ちょうど今elastic beanstalkの運用を行なっていて安定してきたので、elastic beanstalkでimmutable infrastructureに運用するためにはどうすればいいのか?というのをまとめてみます。
目的
- elastic beanstalkの環境構築とデプロイを自動化し、immutableに運用できる環境を作る
デプロイ
デプロイする方法はいくつかありますが、今回はeb
コマンドを利用します。
ebコマンドを使う理由は以下の通り。
- 操作が簡単
- gitのリポジトリが簡単にデプロイできる
optionsettings
やebextensions
を利用すれば設定をコードとして管理できる
通常は対話式で入力していくことになるのですが、以下のような適当なシェススクリプトを作成するだけでコマンドによる自動化も簡単です。
GIT_BRANCH='master' ENV_NAME=`date +"%Y%m%d-%H%M%S"` # parse opts while getopts b:e:r: OPT do case $OPT in b) GIT_BRANCH=$OPTARG ;; e) ENV_NAME=$OPTARG ;; esac done # checkout git checkout ${GIT_BRANCH} git pull origin ${GIT_BRANCH} # create new eb environment expect -c " spawn eb branch expect \"Enter an AWS Elastic Beanstalk environment name (auto-generated value is *):\" { send \"${ENV_NAME}\n\" } expect \"Do you want to copy the settings from environment * for the new branch?\" { send \"y\n\" } expect \"Would you like to deploy the latest Git commit to your environment?\" { send \"y\n\" } " # deploy to aws eb start && git aws.push --environment ${ENV_NAME} # clean up git reset --hard HEAD git clean -f
以下、eb
コマンドでのデプロイを前提に進めます。
URL
ebコマンドでenvironmentを作成すると、デフォルトで<environment名>-<ハッシュ>.elasticbeanstalk.com
というURLがそれぞれのenvironmentに付与されます。
独自ドメインで運用する場合はこのURLに向けてCNAMEを張って、environmentのswapで切り替えていくことになるので、公開中のenvironmentであることがわかる名前がいいと思います。ちなみに自分の環境では本番用URLが割り当てられるenvironment名はproduction
としてあります。
(ちなみにルートドメインの場合はCNAMEを張れません。Route53の場合も同様で、AレコードのエイリアスにELBを設定するためURLは関係なくなります。)
また、公開中のURLに紐付かないenvironmentは継続的デプロイで自動作成してステージング相当の環境として利用すると思うので、
- 機械的に採番できる
- 推測しにくい
- URLスワップしても意味がわかる
environment名が望ましいと思います。自分の環境では上のデプロイスクリプトにあるようにyyyymmdd-hhmiss
というenvironment名をデフォルトにしてます。
プロビジョニング
基本はoptionsettingsやebextensionsを利用してenvironmentやインスタンスの作成時に設定などを行う運用になると思います。
- optionsettings
- ebextensions
またこれらのファイルはeb init
によって.gitignore
に追加されているのですが、gitの管理下に置くことで設定やリソースなどをコードとして管理することができます。
しかし、もともと遅いelastic beanstalkのセットアップに加えて追加のパッケージのインストールなどを都度行っているとさらに時間がかかってしまうため、Auto Scalingで頻繁にインスタンスが増加する場合には設定済みのAMI用意する必要が出てくると思います。
ちなみに自分の環境ではchef+berkshelf+packerでAMI作成を自動化していますが、少し前にelastic beanstalkがdockerコンテナに対応したので、dockerを使うのもアリだと思います。
DB
当たり前の話ですが、immutableに運用するためにはDBは外出ししなければいけません。
RDSを利用する場合、optionsettingsで紐付たりebextensionsから作成を行ってしまうとenvironment削除時にRDSのインスタンスも削除されてしまうので、作成は別に行う必要があります。
通知/監視
SNSを利用する場合は、optionsettingsのaws:elasticbeanstalk:sns:topics
で指定したトピックやebextensionsのType: AWS::SNS::Topic
で作成したトピックは環境削除時に削除されてしまいます。
またSNSは、メール通知するアドレスの確認作業がトピック作成を行うたびに必要となってしまいます(メール以外の通知方法に関しては未調査)。
なのでメールアドレスの確認作業が自動化できない場合は、SNSのトピック作成をあらかじめ行うようにして、optionsettingsのaws:elasticbeanstalk:sns:topics
には指定しないようにしましょう。
CloudWatchを利用する場合は、(environment削除時にひもづいているアラームも一緒に削除されてしまうため)ebextensionsのType: AWS::CloudWatch::Alarm
でenvironment毎に作成する必要があります。
アラームが削除されると計測した値も削除されてしまうので、継続的に計測したい場合は別途監視サーバが必要です。
ちなみにType: AWS::CloudWatch::Alarm
のAlarmActions
やInsufficientDataActions
に指定したSNSトピックはenvironment削除時に削除されないので、CloudWatchのアラームはSNSを通して通知可能です。
CloudWatchのAlarm作成は以下が参考になります。
- https://github.com/lapygithub/eb_config_examples
- http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/CW_Support_For_AWS.html
ログ
.elasticbeanstalk/optionsettings
にあるLogPublicationControl
をオンにすることでアプリケーションやWebサーバのログを自動的にS3にアップロードしてくれます。
しかしS3に保存されるログファイルのパスは${environment-id}/${ホスト名}/${ログファイルのパス}.log-${YYYYMMDD}.gz
となっていてenvironmentやホストをたくさん作って捨てる運用方法だと参照がしにくいので、自分の環境ではfluentd(tdagent)を利用しています。
fluentdを利用する場合はauto scalingによってインスタンスが突然死する場合に備えてflush_at_shutdown
とか設定しておくといい感じです。
まとめ
上に挙げた通りenvironmentの削除時に消えてしまうリソースがあるため、そこだけ気をつけていれば基本的には問題ないと思います。 みんなでimmutable infrastructureなelastic beanstalkを満喫しましょう!