AWSのコンテナサービスであるECS(EC2 Container Service)を使ってWordPressを公開してみる。ECSは、EC2インスタンスからなるクラスタ上にDockerベースのコンテナをビルド、実行するプラットフォーム。
構成
今回はECSの1クラスタ上にWPのコンテナをデプロイする。DBもコンテナとして立ち上げるのもありだけど、今回はRDSを利用し、WPのコンテナからRDSを参照する形にした。
ECSのセットアップ
Step1:ウィザードでCustomを選択
Step2:Task Definitionをの作成
続いてTask Definitionを作成する。
まずAdd Container DefinitionでContainer Definitionを作成。
- Container name
コンテナ名を設定。(同じTask Definition内のコンテナとリンクする際にも利用可能。) - Image
コンテナが使うイメージを”repository-url/image:tag.”という形式で設定。この設定値がDocker daemonに渡される。デフォルトでDocker Hubを参照しにいく。
今回は、WordPressのイメージはDocker Hubのオフィシャルリポジトリのイメージを利用する。 - Memory
コンテナが使用するメモリを設定(単位はMB)。この設定値を超えるメモリをコンテナが確保しようとするとコンテナが殺される。 - CPU Units
コンテナが使用するCPU Unitsを設定。EC2のクラスタインスタンスのCPU1コアあたり1024 CPU Unitsを持ってる。このパラメータはコンテナが使用する最小単位のCPU量を指定したもので、どのコンテナにも割り当てられてないCPU Unitsを、各コンテナに割り当て済みのCPU Unitsと同じ比率で共有する。 - Essential
チェックを入れておくと、コンテナの起動が失敗すると他のタスクも停止する。チェックを入れてない場合、このコンテナの起動に失敗しても他のコンテナの挙動に影響を与えない。 - Port Mappings
ホストとコンテナ間のポートのマッピングを設定。明示的にポートを指定するか、ポートを指定しない場合はエフェメラルポートレンジのポートが自動的に割り当てられるようになる。今回はホストの80番ポートをWordPressのコンテナの80番ポートにマッピングする。 - Mount points
コンテナ内のデータ領域のマウントポイントを設定。マウントするVolume名、ホストのVolumeにマウントするためのコンテナ上のパス、readOnlyフラグを定義可能。 - Entry Point
コンテナに渡すENTRYPOINT(=DockerのENTRYPOINT)を設定。 - Command
コンテナに渡すCMD(=DockerのCMD)を設定。 - Environment Variables
コンテナに渡す環境変数を設定。 - Links
リンクするンテナを設定。 - Volumes from
他のコンテナからマウントするデータ領域を設定。
続いて、Add vlolumeで永続化するデータボリュームの定義。
- Name
データボリュームの名前を設定。
この設定値が↑のContainer DefinitionのmountPointsのsourcePathパラメータで参照される。 - Source Path
ホストのコンテナインスタンスにストアするデータボリュームのパスを設定。このパスが空だと、Docker daemonがホストのパスを割り当てるが、この場合コンテナを停止した際の永続化は保証されない。
※ECSはコンテナインスタンス間のデータボリュームの同期はしない。
今回のTask Definitionの設定内容をJSONにしたのが↓
{ "family": "wp", "containerDefinitions": [ { "name": "wp", "image": "wordpress:latest", "cpu": "100", "memory": "128", "entryPoint": [], "environment": [ { "name": "WORDPRESS_DB_USER", "value": "wpuser" }, { "name": "WORDPRESS_DB_PASSWORD", "value": "wppass" }, { "name": "WORDPRESS_DB_NAME", "value": "wpdb" }, { "name": "WORDPRESS_DB_HOST", "value": "RDSのエンドポイント" } ], "command": [], "portMappings": [ { "hostPort": 80, "containerPort": 80, "protocol": "tcp" } ], "volumesFrom": [], "links": [], "mountPoints": [ { "sourceVolume": "wpdata", "containerPath": "/var/www/html", "readOnly": false } ], "essential": true } ], "volumes": [ { "name": "wpdata", "host": { "sourcePath": "/var/data" } } ] }
Step3:Schedule Tasksの設定
ここではStep2で定義したTask DefinitionからTaskのスケジュールを設定する。
スケジュール方法として以下の2つから選択する。
- Run Tasks Once
バッチジョブのような動作ののち停止するタイプのタスクを実行する際に利用。 - Create a service
ずっと起動しているアプリケーションを実行する際に利用。Desired number of Tasksで設定した数のコンテナが常時起動する状態になる。
今回はWordPressの公開なのでCreate a serviceを選択。
Step4:クラスタの設定
最後にクラスタの設定を行う。
- Number of Instances
クラスタとして起動するEC2のコンテナインスタンス数を設定。今回は1を設定。 - Instance Type
コンテナインスタンスのインスタンスタイプを選択。今回はt2.microを選択。 - Key pair name
コンテナインスタンスへのSSH接続に利用するキーペアを選択。 - Security Ingress CIDR
インスタンスへのアクセスを制限するCIDRブロックを設定。
デフォルト値(0.0.0.0/0)ではどこからもアクセスフリー。
※ECSはアプリケーションやサービスにアクセスするため自動的に80番ポートを開く。 - ECS instance role
コンテナインスタンスとサービスに適用するIAM Rorleを選択 or 作成。
と一通りの設定が終わればいよいよ起動。
クラスタインスタンスの起動や構成の設定なんかはCloudFormationで作成される。
作成されたコンテナインスタンス↓
実行中のタスク↓
起動したECSインスタンスにSSHでログインしてdocker psを叩くと、
__| __| __| _| ( \__ \ Amazon ECS-Optimized Amazon Linux AMI 2015.03.d ____|\___|____/ For documentation visit, http://aws.amazon.com/documentation/ecs 9 package(s) needed for security, out of 17 available Run "sudo yum update" to apply all updates. [ec2-user@ip-10-0-0-53 ~]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6454c7512a17 wordpress:latest "/entrypoint.sh apac 6 minutes ago Up 6 minutes 0.0.0.0:80->80/tcp ecs-wp-1-wp-a4cc99c8d2d7deefa001 b9c7492d4d4b amazon/amazon-ecs-agent:latest "/agent" 30 minutes ago Up 30 minutes 127.0.0.1:51678->51678/tcp ecs-agent
↑で定義したTaskのコンテナが実行されてる他に、ECSのエージェント自体もコンテナとして動作してることが分かる。
※とここまで終了して気付いたのが、コンテナインスタンスのVPC。
↑のCloudFormation実行時にVPCが新規に作成され、そこにコンテナインスタンスが配置される。現時点では、↑のようにECSのコンソールからインスタンスを起動するとVPCの指定ができないと。また、CloudFormationで同様にAutoScallingが設定されているのでコンテナインスタンスをTerminateしてもちょっとすると新しいコンテナインスタンスが起動してしまう。
DBもコンテナにしてれば問題ないんだけど、既存のRDSが稼働してるVPCではなかったので、コンテナインスタンスを作り直す。
コンテナインスタンスの起動
以下の条件で、普通にEC2のコンソールから起動する。
- AMIの選択
起動する際に使用するイメージはECS Container agentがインストール済みのAmazon ECS-Optimized Amazon Linux AMIを使用する。
コミュニティAMIで東京リージョンの場合は、ami-fa12b7faで検索すると出てくる。 - Public IPの自動割り当てを有効化
- IAM Roleの設定
コンテナインスタンスに以下のポリシーが設定されたIAM Roleを設定する。{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecs:CreateCluster", "ecs:DeregisterContainerInstance", "ecs:DiscoverPollEndpoint", "ecs:Poll", "ecs:RegisterContainerInstance", "ecs:Submit*" ], "Resource": "*" } ] }
- コンテナインスタンスを起動するクラスタを設定
user dataを使って、コンテナコンテナインスタンスを起動するクラスタを指定する。(指定しない場合はdefaultクラスタで起動する)#!/bin/bash echo ECS_CLUSTER=クラスタ名 >> /etc/ecs/ecs.config
- セキュリティグループ
80番ポートを全公開し、22番ポートについて自分がアクセスする環境のIPからのアクセスを許可する。
インスタンスが正常に起動すると、ECSのコンソールで↑のuser dataで指定したクラスタのECS InstancesタブにACTIVEになっているインスタンスが確認できる。
コンテナインスタンスが起動したら、先ほど作成したTaskを展開し、コンテナインスタンスの80番ポートにアクセスするとWordPressが起動しているのが確認できる!
※コンテナインスタンスのライフサイクル
ECS Container agentがインスタンスをクラスタに登録すると、コンテナインスタンスはステータスがACTIVEになり、agentのconnection statusがTRUEになり、コンテナインスタンスはTaskの実行リクエストを受け入れられるようになる。
コンテナインスタンスをStop(Terminateではなく)すると、ステータスはACTIVEのままだが、agentのconnection statusはFALSEになり、コンテナインスタンスで実行されていたタスクは停止する。再度コンテナインスタンスをStartするとContainer agentはECS Serviceに再接続し、再度インスタンス上でタスクの実行が可能になる。
コンテナインスタンスをTerminateもしくは登録解除(deregister)すると、コンテナインスタンスのステータスはINACTIVEに変わり、コンテナインスタンスの一覧には表示されなくなる。(Terminate後1時間以内であればコンテナインスタンスの情報を確認できる。)
まとめ
- Memoryの設定値を超えたアロケーションが発生した場合にコンテナはkillされるので、killされることを念頭においた設計をする必要がある。
- 現時点では、ECSのコンソールからウィザードを使用してコンテナインスタンスを起動すると、VPCの指定やAutoScallingの設定がカスタマイズできないので、ウィザードは使用せずに、EC2のコンソールから起動してクラスタに参加させるかAPI使って起動する方が良い。
- ホストのファイルシステムをコンテナでマウントできるので、WPのディレクトリをまるごとマウントすればデータの永続化ができる。ただ、ホストが変わった場合の考慮は必要。このへんは、EFSが東京リージョンで利用可能になるとポータビリティが更に上がると思う。
- ログの消失を考慮すると別途ログを収集するコンテナとか用意しておいた方がよさそう。