Help us understand the problem. What is going on with this article?

【AWS】Elastic Beanstalkのデプロイ時に docker exec する

先に結論

Elastic Beanstalk のオートスケーリング設定が有効になっている環境で複数の EC2 インスタンスに対してデプロイする際に、どれか一つの EC2 インスタンス上で DB マイグレーションのコマンドを実行したいとします。
その場合、以下のような設定ファイルを追加してデプロイすると実現できます。

.ebextensions/post_migration.config
container_commands:
  01_migrate: # リーダー判定用の一時ファイルを作成
    command: "touch /tmp/leader_only"
    leader_only: true

files:
  "/opt/elasticbeanstalk/hooks/appdeploy/post/10_post_migrate.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/bin/bash -eu
      if [ -f /tmp/leader_only ] # リーダーインスタンスでのみ実行
      then
        # リーダー判定用の一時ファイルを削除する
        rm /tmp/leader_only
        # 最後に起動した Docker コンテナ上で migrate を実行する (CakePHP3の場合)
        docker exec `docker ps -l -q` bin/cake migrations migrate
      fi

上記の説明

上記の方法は container_commands: で直接 migrate せずに files: でシェルスクリプトを作成し、そのスクリプトの中で migrate するという回りくどい手順になっています。その辺りの事情をデプロイの流れと共に説明します。

Elastic Beanstalk (Docker) のデプロイ時の流れ

Elastic Beanstalk には デプロイ処理の各タイミングで任意スクリプトをフック実行する為の仕組み があります。予め決められたディレクトリにシェルスクリプトを置いておくと、ファイル名の辞書順に実行してくれる仕組みです。

このフック実行用のディレクトリには、インスタンスを作成した段階で Elastic Beanstalk を構成するいくつかのスクリプト(以下を参照)が入っていますが、ユーザーが任意のスクリプトを追加することもできます。

1. pre hook スクリプトの実行:

  • 1-1. /opt/elasticbeanstalk/hooks/appdeploy/pre/00clean_dir.sh
    • デプロイの準備。/var/app/current の初期化を行う。
  • 1-2. /opt/elasticbeanstalk/hooks/appdeploy/pre/01unzip.sh
    • アプリケーションを unzip して /var/app/current へ展開する。
  • 1-3. /opt/elasticbeanstalk/hooks/appdeploy/pre/02loopback-check.sh
  • 1-4. /opt/elasticbeanstalk/hooks/appdeploy/pre/03build.sh
    • /var/app/current にある Dockerfile OR Dockerrun.aws.json を元に Docker Image を作成 (docker build OR docker pull) する。

2. .ebextensions の container_commands の実行:

  • 2-1. .ebextensions/*.config に container_commands がある場合、順にそのコマンドを実行する。
    • 既に新バージョンのアプリは既に unzip 済みのため、それらに触れることができる。
    • このとき、新バージョン docker コンテナは まだ起動していない。

参考: .ebextensions の container_commands の挙動メモ - Qiita

3. enact hook スクリプトの実行:

  • 3-1. /opt/elasticbeanstalk/hooks/appdeploy/enact/00run.sh
    • 03build.sh で作成したイメージを docker run -d する。
  • 3-2. /opt/elasticbeanstalk/hooks/appdeploy/enact/01flip.sh
    • staging-appcurrent-app にする。

4. post hook スクリプトの実行:

  • 4-1. /opt/elasticbeanstalk/hooks/appdeploy/post/00_clean_imgs.sh
    • 未使用のイメージやコンテナを削除する。
  • 4-2. /opt/elasticbeanstalk/hooks/appdeploy/post/01_monitor_pids.sh

上記のような流れのため、デプロイ時に docker exec したい場合は 00run.sh 以降で行う必要があります。container_commands のタイミングでは実現できません。

その為 .ebextensions で post hook 用のシェルスクリプトを作成して、その中で docker exec するという方法を取っています。

また、オートスケーリングの設定をしている場合、作成したフックスクリプトはデプロイされる全てのコンテナ上で実行されるため、そのままだとマイグレーションが何度も実行されることになります。

それでは困るのでリーダーインスタンスでのみ事前に /tmp/leader_only のファイルを作成しておき、そのファイルが存在する場合にのみ post hook スクリプトを実行するようにしています。

container_commands の leader_only オプションについて引用:

Elastic Beanstalk によって選択された単一のインスタンスでコマンドを実行するのみです。リーダー専用コンテナコマンドは、他のコンテナコマンドより前に実行されます。

https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/customize-containers-ec2.html#linux-container-commands

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした