Elastic Beanstalkを自分の思うように拡張していく上では、.ebextensions
を調整することが欠かせませんが、書き方を間違えれば正常に動作しない、あるいは反映効率が低下する、というような問題を生じることがあります。
.ebextensionsという黒魔術
Elastic BeanstalkはAWSのEC2で動いていますが、.ebextensions
というかたちで設定ファイルを書けば、EC2で可能なことをなんでもできるようになります。逆を返せば、不適切な設定をしてしまうと環境がめちゃくちゃになる、ということです。
重要になる「冪等性」
こういった環境構築系のツールに共通する話ですが、Elastic Beanstalkは2回目以降の反映の際にもEC2はそのまま流用します。そのため、
- 最初の環境構築…ベースになるEC2の上にアプリケーションごとの設定を実行して反映させていく
- 2回目以降…すでにある環境に対して、設定をさらに反映していく
という違いがあります。.ebextensions
を書く場合には、どちらで実行しても問題なく実行されるような、冪等性が要求されます。
特に気にしなくていい例
packages:
yum:
git: []
パッケージマネージャでインストールを行う場合、パッケージマネージャそのものが冪等性を保ってくれる(2回インストールしても2回目は何もしないだけになる)ので、特に考慮の必要はありません。データベースのシードなども、メカニズムの時点で冪等なものを使えばいいでしょう。
commands:
01-cp-zoneinfo:
command: cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
上記はタイムゾーン設定のために入れてありますが、ファイルコピーでの上書きを複数回行っても、(少々無駄ではありますが)実行される内容に問題はないので、そのまま毎回実行させています。
要注意な場合
設定ファイルを書き換えるような場合、複数回実行するとうまく動かなくなります。「すでに書き換わっているかどうかチェックする」「実行済みのフラグをどこかに記録しておく」などの方法で、複数回の実行を回避するようにしましょう。
commands:
create_post_dir:
command: "mkdir /opt/elasticbeanstalk/hooks/appdeploy/post"
ignoreErrors: true
files:
"/opt/elasticbeanstalk/hooks/appdeploy/post/97_conf_redis.sh":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
if grep -E '^unix' /etc/redis.conf >/dev/null; then
exit
fi
sudo sed -i -e 's/^save /#save /g' /etc/redis.conf
sudo sed -i -e 's/^# unix.*$ //g' /etc/redis.conf
echo 'unixsocket /tmp/redis.sock' | sudo tee -a /etc/redis.conf >/dev/null
echo 'unixsocketperm 777' | sudo tee -a /etc/redis.conf >/dev/null
sudo chkconfig redis on
sudo service redis restart
ここでは、RedisのUnixソケットを入れて、保存を無効化するように/etc/redis.conf
を書き換えていますが1、if
ですでに書き換わっている場合には脱出しています。
気にしなくても動くけど
「リモートからファイルをダウンロードして配置する」ようなものを動かす場合、そのまま何回やっても冪等性という観点では問題ありません。ただ、巨大なファイルで毎回ダウンロードを行えば、回線や時間といったリソースの無駄ですので、「すでにダウンロード済みの場合は処理を飛ばす」ような措置をしておくと、効率化できます。
アップデート時の注意
.ebextensions
を書き換えてアップデートしていくと、古いサーバには前の設定が残ったままとなります。そのため、あるだけで設定すると必要なものが抜けていてうまく動かない、という危険もありますので、ときどきは環境全体を再構築して問題がないか確認しておいたほうがいいかもしれません。
-
なお、この環境は1インスタンスで動かしているので、EB管理のEC2の内部にRedisを立てています。 ↩