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を見ると、UbuntuにApacheとか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/tcp
0.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

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

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中