AWSのコンテナサービスであるECS(EC2 Container Service)を使ってWordPressを公開してみる。ECSは、EC2インスタンスからなるクラスタ上にDockerベースのコンテナをビルド、実行するプラットフォーム。

構成

今回はECSの1クラスタ上にWPのコンテナをデプロイする。DBもコンテナとして立ち上げるのもありだけど、今回はRDSを利用し、WPのコンテナからRDSを参照する形にした。

ECSのセットアップ

Step1:ウィザードでCustomを選択

step1

Step2:Task Definitionをの作成

続いてTask Definitionを作成する。
まずAdd Container DefinitionでContainer Definitionを作成。

step2

  • 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で永続化するデータボリュームの定義。

volume

  • 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のスケジュールを設定する。

step3

スケジュール方法として以下の2つから選択する。

  • Run Tasks Once
    バッチジョブのような動作ののち停止するタイプのタスクを実行する際に利用。
  • Create a service
    ずっと起動しているアプリケーションを実行する際に利用。Desired number of Tasksで設定した数のコンテナが常時起動する状態になる。

今回はWordPressの公開なのでCreate a serviceを選択。

Step4:クラスタの設定

最後にクラスタの設定を行う。

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で作成される。

created

作成されたコンテナインスタンス↓

container

実行中のタスク↓

task

起動した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が起動しているのが確認できる!

wp

※コンテナインスタンスのライフサイクル

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が東京リージョンで利用可能になるとポータビリティが更に上がると思う。
  • ログの消失を考慮すると別途ログを収集するコンテナとか用意しておいた方がよさそう。

参考