Amazon ECS の動的な Network port mapping について

Dockerは docker run する時に、-P フラグを立てると、Dockerホストの、自動的にランダムにエフェメラルポートレンジの中のhigh port(well knownじゃないヤツ)に割り当てを行います。 これはDockerのドキュメントの Linking Containers Together(https://docs.docker.com/userguide/dockerlinks/) に書いてあって、 ↓のようにDockerコンテナの5000番ポートが、Dockerホストの49155番ポートにマッピングされてる例とか。

$ sudo docker ps nostalgic_morse
CONTAINER ID  IMAGE                   COMMAND       CREATED        STATUS        PORTS                    NAMES
bc533791f3f5  training/webapp:latest  python app.py 5 seconds ago  Up 2 seconds  0.0.0.0:49155->5000/tcp  nostalgic_morse

  Amazon ECSでは、DockerホストであるEC2と、Dockerコンテナのポートのマッピングに関しては、 ↓のドキュメントのようにTaskのパラメータとして定義します。タスクって?って感じですが、要はコンテナの定義のことです。 http://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html

"portMappings": [
    {
        "containerPort": integer,
        "hostPort": integer
    }
    ...
]

  EC2上に複数のDockerのコンテナを立ち上げて、例えばそれらがxxポートをリスンするものだったとして、 ユーザーとしてはホスト側のポートは上記のように、よしななポートをマッピングして欲しいですね、と。   コチラに関しては、上記のドキュメントの中には↓のように記載されています。

If you want an automatically assigned host port, use the following syntax:
"portMappings": [
    {
        "containerPort": integer
    }
    ...
]

ただ、書かなければ良いって話なのですね、と。   ということで、さっそく試してみたいと思います。     ■ Docker Imageの作成とDocker Hubへのアップロード   ECSのドキュメントのDocker Basicsの"To create a Docker image of a PHP web application"に沿って やっていきたいと思います。   まずはギッハブからコピってきます。

$ git clone https://github.com/awslabs/ecs-demo-php-simple-app
Cloning into 'ecs-demo-php-simple-app'...
remote: Counting objects: 71, done.
remote: Total 71 (delta 0), reused 0 (delta 0), pack-reused 71
Unpacking objects: 100% (71/71), done.
Checking connectivity... done.

  Dockerfileを見ると、UbuntuApacheとかPHPとかインストールして、80番ポートでリスン的なのが分かります。

$ cat Dockerfile
FROM ubuntu:12.04

# Install dependencies
RUN apt-get update -y
RUN apt-get install -y git curl apache2 php5 libapache2-mod-php5 php5-mcrypt php5-mysql

# Install app
RUN rm -rf /var/www/*
ADD src /var/www

# Configure apache
RUN a2enmod rewrite
RUN chown -R www-data:www-data /var/www
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2

EXPOSE 80

CMD ["/usr/sbin/apache2", "-D",  "FOREGROUND"]

  私のMacの環境でDocker imageを作ります。 boot2docker startで仮想マシンを立ち上げて、環境変数をホゲホゲって話は ↓この辺を参考になさっていただければ、と。 https://docs.docker.com/installation/mac/   しばらくボケっとしながらビルドが終わるのを待ちます。

$ docker build -t shinodogg/amazon-ecs-sample .
Sending build context to Docker daemon 363.5 kB
Sending build context to Docker daemon
Step 0 : FROM ubuntu:12.04
Pulling repository ubuntu
〜略〜
tep 11 : CMD ["/usr/sbin/apache2", "-D",  "FOREGROUND"]
 ---> Running in d855e0fc614e
 ---> adfdd9bcf446
Removing intermediate container d855e0fc614e
Successfully built adfdd9bcf446
$ echo $?
0

  では走らせてみましょう。

$ docker run -p 80:80 shinodogg/amazon-ecs-sample

  アドレスは↓よん、って事ですので、、

$ boot2docker ip

The VM's Host only interface IP address is: 192.168.59.103

  ↓のように、良さ気でございます。   ってことで、Docker ImageをDocker Hubへ。コマンドラインでログインして、

$ docker login
Username: shinodogg
Password:
Email: xxxx@gmail.com
Login Succeeded

  Docker Hubにpushします。貧弱な回線だとちょいちょい時間かかりますね。。

$ docker push shinodogg/amazon-ecs-sample
The push refers to a repository [shinodogg/amazon-ecs-sample] (len: 1)
Sending image list
Pushing repository shinodogg/amazon-ecs-sample (1 tags)
〜略〜
adfdd9bcf446: Image successfully pushed
Pushing tag for rev [adfdd9bcf446] on {https://cdn-registry-1.docker.io/v1/repositories/shinodogg/amazon-ecs-sample/tags/latest}

    ■ ECS用のEC2インスタンスを起動   MarketplaceからAMIを持ってくるのも良いのですが、実際にどんなものか知りたいので、 EC2をAmazon Linuxで普通に立てて、そこに諸々インストールしていきたいと思います。 ↓に沿ってやっていきます。 Installing the Amazon ECS Container Agent   EC2はt2.mediumにしてみます。   EC2からECSをホゲホゲ出来るようにIAM Roleを付けてあげます。↓をまんまです。 http://docs.aws.amazon.com/AmazonECS/latest/developerguide/IAM_policies.html#instance_IAM_role

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecs:CreateCluster",
        "ecs:RegisterContainerInstance",
        "ecs:DeregisterContainerInstance",
        "ecs:DiscoverPollEndpoint",
        "ecs:Submit*",
        "ecs:Poll"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

  ポートはアレがアレで、一旦、自分のIPで全開放してみます。   EC2が立ち上がったら、dockerコマンドをインストールして、Dockerのサービスを立ち上げます。

$ sudo yum install docker -y
$ sudo service docker start
Starting cgconfig service:                                 [  OK  ]
Starting docker:                                       [  OK  ]

ECSエージェントをインストールします。 ココでクラスタ名(shinodoggって書いてある太字のところ)が聞かれるのは理由があって、 この時点でClusterが起動していないと↓のようなエラーが出て止まってしまうので、 ECSのクラスタを作ってから叩きましょう。 msg="Error registering" module=main err="Cluster not found."

$ sudo docker run --name ecs-agent -d 
> -v /var/run/docker.sock:/var/run/docker.sock 
> -v /var/log/ecs/:/log -p 127.0.0.1:51678:51678 
> -v /var/lib/ecs/data:/data 
> -e ECS_LOGFILE=/log/ecs-agent.log 
> -e ECS_LOGLEVEL=info 
> -e ECS_DATADIR=/data 
> -e ECS_CLUSTER=shinodogg 
> amazon/amazon-ecs-agent:latest
Unable to find image 'amazon/amazon-ecs-agent:latest' locally
Pulling repository amazon/amazon-ecs-agent
68db83900ab7: Download complete
86ae36d94914: Download complete
b39579a0c13b: Download complete
36d93670e9b5: Download complete
Status: Downloaded newer image for amazon/amazon-ecs-agent:latest
ac73fd6a55f02a6c0b7251d09cdc8700d4c89a7e00aae4ff42bf7575dd90bddc

    ■ ECSを使ってEC2上にコンテナを2つデプロイ   ココからは、Management Consoleを使っていきます。   まずはTaskの定義からしていきます。タスクって用語がややこしいのですが、そのDockerインスタンスに どんなリソース(CPUとかメモリとか)割り当てるか〜とか、ポートどうするー?とか、そういうヤツです。   タスクの定義自体はECSのドキュメントのDocker Basicsにあるので、それをそのまま使います。   JSONタブにそのままコピペすると、   Builderタブでイイ感じに見えます。ついでなのでCPUとメモリの値をイジったりしつつ、   意図的にホスト側のポートの設定を削除します。   で、このTaskからServiceを作ります。これも名前がややこしいですが、 Scheduling Amazon ECS Tasksのページをみると(スケジューリングって言葉も慣れない人にはアレですね、、笑) ・Create Service: The service scheduler is ideally suited for long running stateless services and applications. ・Run Task: The RunTask action is ideally suited for processes such as batch jobs that perform work and then stop. って事なので、今回はWebなアプリケーションなので、Create Serviceの方で、Clusterを shinodogg という名前で作ります。   この状態で上記のECSエージェントを走らせると、ログがイイ感じにズコズコ流れるかな、と。 あ、ちなみにECSエージェントのログファイルは /var/log/ecs/ecs-agent.log にあります。   マネージメントコンソールではServiceのStatusがActiveになっていてTaskが2つRUNNINGになっています。 (Taskのリビジョンが3に上がってるのは気にしないでください…笑)   EC2で docker ps を叩くと、ちょーっと見づらいですが、 ↓のようにホストの49155番ポートと49156番ポートがそれぞれ立ち上げたDockerコンテナの 80番ポートにマッピングされているのが分かります ・0.0.0.0:49156->80/tcp0.0.0.0:49155->80/tcp

$ sudo docker ps
CONTAINER ID        IMAGE                                COMMAND                CREATED             STATUS              PORTS                        NAMES
43280236f478        busybox:buildroot-2014.02            ""sh -c '/bin/sh -c   4 minutes ago       Up 4 minutes                                     ecs-console-sample-app-3-busybox-e8b18898b7af93ddaa01
4137bedb3bcd        shinodogg/amazon-ecs-sample:latest   "/usr/sbin/apache2 -   4 minutes ago       Up 4 minutes        0.0.0.0:49156->80/tcp        ecs-console-sample-app-3-simple-app-c2da8c81ccb3f2cbdf01
ae6d023c81ba        busybox:buildroot-2014.02            ""sh -c '/bin/sh -c   4 minutes ago       Up 4 minutes                                     ecs-console-sample-app-3-busybox-d488f69e80a6d59edd01
4a7bc27d9de1        shinodogg/amazon-ecs-sample:latest   "/usr/sbin/apache2 -   4 minutes ago       Up 4 minutes        0.0.0.0:49155->80/tcp        ecs-console-sample-app-3-simple-app-dadb83dae896d2afbc01
2d6ea464a2c4        amazon/amazon-ecs-agent:4023248      "/agent"               10 minutes ago      Up 10 minutes       127.0.0.1:51678->51678/tcp   ecs-agent

  では、ブラウザからアクセスしてみましょう。   ・49155番ポート   ・49156番ポート   無事に、よしなにホスト側のポートとマッピングされていることが確認できました(´▽`)ノ ってことで、検証環境はキレイにお掃除しておきます、と。   お仕事でいろんな人とお話させていただいている中でも、最近Dockerがすごい来てる感ありますが、 ↓はプロダクションでDockerを使っている方の記事とかありますね。

WEB+DB PRESS Vol.86
WEB+DB PRESS Vol.86
posted with amazlet at 15.05.05
結城 洋志 沖元 謙治 足永 拓郎 林 健太郎 大竹 智也 内田 誠悟 伊藤 直也 中山 裕司 hiroki.o 泉水 翔吾 佐藤 太一 高橋 俊幸 西尾 泰和 舘野 祐一 中島 聡 橋本 翔 はまちや2 竹原 麻植 泰輔
技術評論社
売り上げランキング: 902

  最後に、本投稿は私が個人的に行ったものであり、所属する企業や団体における公式見解ではございません。