Amazon ECS CLI を使い Rocket.Chat 環境を compose するには

Amazon ECS CLI を使い Rocket.Chat 環境を compose するには

Amazon ECS CLI を使い Rocket.Chat 環境を compose するには はてなブックマーク - Amazon ECS CLI を使い Rocket.Chat 環境を compose するには


ECS CLI の概要をはじめ、具体的に何ができるのかとして、Docker Compose 形式のファイルを使い、コンテナ群をまとめて起動・停止する方法を整理しました。ドキュメントの Walkthrough (チュートリアル)相当の内容カバーを目指しています。

■ Amazon EC2 Container Service CLI とは

Amazon ECS に関連する機能強化の一環として、新しいコマンドライン・ツール Amazon EC2 Container Service CLI(以下 ECS CLI)がリリースされました。これは従来のコマンドライン・ツールである「aws」コマンドとは別のツールです。あくまでもECS のみを管理する専用コマンド「ecs-cli」として提供されています。

特徴としては、以下の点が挙げられます。

  • ecs-cli の操作は ECS を意識せず、コンテナやサービスの運用に集中できる(従来の aws コマンドで ECS を操作するよりも簡単)
  • Docker Compose のコマンドやコンテナ定義形式(YAML)と互換性がある

これまでの「aws」コマンドになれている方であれば、新しく「ecs-cli」コマンドを覚えるのは多少の手間かもしれません。しかし、これから ECS を使い始める方、特に docker 関連コマンドに慣れ親しんでいる方であれば、比較的取り扱いしやすいものです。

また、Docker Cmpose との互換性という意味では、Docker Hub 上の資産を有効活用できるという利点があります。

機能の比較をしやすいよう、通常の Docker と Amazon ECS を大ざっぱに比較したのが下図です。  Docker Machine による環境構築と、Docker Compose によるコンテナ起動にあたる機能を、ecs-cli コマンドだけで実現できます。さらに、ECS であれば複数の Availability Zone にまたがる管理もできるのがメリットとも言えるでしょう。

compare-amazon-ecs-and-docker

ただし、現時点の ecs-cli には次の課題(仕様)があります。

  • 「Dockerfile」を docker-compose.yml から呼び出せない(`build`ディレクティブを未サポート)
  • コマンドラインのバイナリは、Mac OSX および Linux 向け(現時点では Windows は未提供)

なお、内部の実装としては、バックグラウンドで CloudFourmation を使っていますので、従来の CLI を使う方法、マネジメントコンソール上から操作する方法と変わらないものと思われます(中の人、違っていたらゴメンナサイ)。

それでは、以下で実際に ecs-cli のインストールや、設定ファイルを使った環境構築を試してみます。

■ ecs-cli のセットアップ

まず始めにバイナリをダウンロードします。

Mac OSX の場合:

$ sudo curl -o /usr/local/bin/ecs-cli https://s3.amazonaws.com/amazon-ecs-cli/ecs-cli-darwin-amd64-latest

Linux の場合:

$ sudo curl -o /usr/local/bin/ecs-cli https://s3.amazonaws.com/amazon-ecs-cli/ecs-cli-linux-amd64-latest

次に、「ecs-cli」に実行属性を与えます。

$ sudo chmod +x /usr/local/bin/ecs-cli

正常に実行できるかどうか「ecs-cli -v」と入力し、バージョン番号が表示されるか確認します。

$ ecs-cli -v
ecs-cli version 0.1.0 (*cbdc2d5)

以上でセットアップ完了です。

■ 環境設定

次に設定ファイル「~/.ecs/config」を作成するために「ecs-cli configure」コマンドを実行します。この中で認証情報やリージョン等の情報を指定します。オフィシャルのドキュメントでは「us-west-2」が例示されていますが、せっかく ECS が東京リージョンでも使えるので「ap-northeast-1」を指定することもできます。引数の最後には ECS で管理するクラスタ名を指定します。なお、あらかじめ環境変数でアクセスキーとシークレットキーを定義しているものとします。また、「ecs-cli-demo」というクラスタ名の箇所は、任意の名称を指定できます。

$ ecs-cli configure \
    --region ap-northeast-1 \
    --access-key $AWS_ACCESS_KEY_ID \
    --secret-key $AWS_SECRET_ACCESS_KEY \
    --cluster ecs-cli-demo

コマンドを実行すると「~/.ecs/config」ファイルが作成されます。「cat」コマンドで中をみてみると、クラスタ名(cluster)やリージョン(region)等が記述されていることがわかります。後ほどリージョンやクラスタ名を変えたいときは、直接このファイルを編集しても構いません。

$ cat .ecs/config
[ecs]
cluster = ecs-cli-demo
aws_profile =
region = ap-northeast-1
aws_access_key_id = *********
aws_secret_access_key = *********

なお、セキュリティに関する情報を保持するファイルのため、パーミッションは必要に応じて設定しておく必要があります(例:chmod 600 ~/.ecs/config)。

この時点では、ローカルの環境上に設定ファイルを作成しただけであり、AWS では何ら作業を行っていません。それでは、どのようにコンテナやサービスを起動するかは次節で取り扱います。

■ ECS クラスタの作成

まず始めに行うのは、EC2 インスタンスのクラスタ群を起動することです。「ECS」とは名前の通り「EC2 Container Service」であり、Amazon EC2 インスタンス上に Docker デーモンによるクラスタを形成するものです。ECS でインスタンスを起動すると Docker が自動的にセットアップされるだけでなく、管理用のエージェント(amazon-ecs-agent)がコンテナとして起動します。

ドキュメントに書かれている例を説明します。

$ ecs-cli up --keypair <キーペア名> --capability-iam --size 2 --instance-type t2.medium

「esc-cli up」コマンドが、EC2 インスタンスを起動します。オプションは以下の通りです。

  • 「–keypair」の後には、AWS の対象リージョンで登録しているキーペア名を指定
  • 「–capability-iam」は必須のオプション
  • 「–size 2」とは、インスタンスを2つ起動(オプション)
  • 「–instance-type t2.medium」は t2.medium(2vCPU, 4GiB)のインスタンスを指定(オプション)

《参考:ecs-cli up時の各オプションのヘルプを意訳》

  • –keypair … クラスタの EC2 インスタンスに SSH アクセスするための Amazon EC2 キーペア(既存のもの)
  • –capability-iam … IAM リソースの作成を承認
  • –size … [オプション] クラスタに登録するインスタンス数の指定(デフォルト:1)
  • –azs … [オプション] サブネットを作成する VPC の availability zone をカンマ区切りで記述する(指定する AZ は `available`状態の必要がある )。これは –vpc オプションを指定しない場合に推奨。警告:オプションをブランクに指定した場合、利用出来ない AZ がランダムに選ばれてしまい、インスタンスの起動に失敗する場合がある
  • –security-group … [オプション] コンテナ用インスタンスに対して既存のセキュリティ・グループを割り当てる。デフォルトは新しいものを作成する
  • –cidr … [オプション] クラスタ内のコンテナ用インスタンスが使用するセキュリティ・グループの CIDR/IP アドレス範囲を指定。–security-group が指定されなかった場合のオプションは 0.0.0.0/0
  • –port … [オプション] 既存のセキュリティ・グループが –security-group オプションで指定されなかった場合、新しいセキュリティ・グループで公開するポートを指定(デフォルト:ポート80)
  • –subnets … [オプション] コンテナ用インスタンスが起動する既存の VPC サブネットをカンマ区切りで記述する。-vpc オプションを使用するときに必要
  • –vpc … [オプション] コンテナ用インスタンスを起動する既存の VPC ID を指定。VPC ID を指定しない場合は、2つのサブネットを自動生成
  • –instance-type … [オプション] コンテナ用インスタンスの EC2 インスタンス・タイプを指定(デフォルトは t2.micro)

それでは、試しに起動してみましょう。

$ ecs-cli up --keypair <mypair> --capability-iam --size 1
INFO[0000] Created cluster                               cluster=ecs-cli-demo
INFO[0001] Waiting for your cluster resources to be created
INFO[0001] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
INFO[0061] Cloudformation stack status                   stackStatus=ROLLBACK_IN_PROGRESS
ERRO[0122] Failure event                                 reason=Value (ap-northeast-1a) for parameter availabilityZone is invalid. Subnets can currently only be created in the following availability zones: ap-northeast-1c, ap-northeast-1b. resourceType=AWS::EC2::Subnet
ERRO[0122] Error executing 'up': Cloudformation failure waiting for 'CREATE_COMPLETE'. State is 'ROLLBACK_COMPLETE'

・・・が、おや、エラーが出ました。どういうことでしょうか。これは、東京リージョン(ap-northeast-1)の場合、AZ1 では ECS の環境が対応しておらず、そのためにエラーが出てしまします。北米の場合はランダムにリージョンが選択されますが、東京のように利用可能な環境が限られている場合はエラーになります。

(2015年10月15日;追記,中の人に教えていただき解決)エラーが出たは、「–vpc」オプションを指定しない場合、対象となるリージョンのなかで AZ がランダムに選ばれるためです。そのランダムで選ばれた先が、たまたま「ap-northeast-1a」であり、そこは私のアカウントでは使えないVPC環境だったため、エラーが出てしまっていました。あらかじめ「–vpc」を指定しておけば、発生しないエラーです。特に VPC を指定しない場合は、以下の通りです(追記ここまで)

これを回避するために「–azs」オプションを使います。そして、今度は ECS の挙動を見るために、インスタンスを2つ起動してみます。インスタンス・タイプは指定しませんので、t2.micro インスタンスを2つ起動することになります。

$  ecs-cli up --keypair <mypair> --capability-iam --size 2 -azs ap-northeast-1b,ap-northeast-1c
INFO[0000] Created cluster                               cluster=ecs-cluster
INFO[0001] Waiting for your cluster resources to be created
INFO[0001] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
INFO[0061] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
INFO[0121] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
INFO[0182] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS

これでクラスタが構築されました。マネジメント・コンソールから EC2 インスタンスの情報を確認すると、次のように自動的にインスタンスが2つ起動していることが分かります。

マネジメント・コンソールの EC2 インスタンスの画面からも確認できます。

ecs-ec2-instances

また、ECS の画面からも、コンテナの状態が確認できます。

ecs-cluster

これでコンテナを起動するためのインスタンスの準備が完了です。

■ コンテナとしてRocket.Chat を起動する

それでは、実際にコンテナを立ち上げてみます。ドキュメントに書かれているサンプルの hello-wolrd.yml は WordPress + MySQL コンテナを扱うものでした。

wordpress:
  image: wordpress
  cpu_shares: 100
  mem_limit: 524288000
  ports:
    - "80:80"
  links:
    - mysql
mysql:
  image: mysql
  cpu_shares: 100
  mem_limit: 524288000
  environment:
    MYSQL_ROOT_PASSWORD: password

これはそのまま起動しようとしても面白くないので、Rocket.Chat という Slack のようなオンライン・チャット・プラットフォームを入れてみましょう。これはフロントが Rocket.Chat というチャットシステム用のコンテナで、バックエンドでは MongoDB を使うものです。

任意のディレクトリで rocket-chat.yml 等のファイルを作成します。サンプルを参考に、CPUやメモリの上限を追加しています。「rocketchat」と「mongodb」2つのコンテナを起動し、メモリは 256 MiB、パブリック IP アドレスのポート 80 番をコンテナ内のポート 80 に割り当てる設定等を行っています。

rocketchat:
  image: "rocketchat/rocket.chat"
  cpu_shares: 100
  mem_limit: 262144000
  ports:
    - "80:80"
  links:
    - mongodb
  environment:
    - ROOT_URL=http://localhost:80
    - MONGO_URL=mongodb://mongodb/rocketchat

mongodb:
   image: mongo
  cpu_shares: 100
  mem_limit: 262144000
   ports:
     - 27017

これで準備が整いました。Docker Compose の場合は「docker-compose up」というコマンドを使いましたが、ECS CLI の場合は「ecs-cli compose up」コマンドを使い、コンテナ群を起動します。実際に立ち上げてみましょう。「-f」オプションで先ほどの YAML ファイルを指定します。

$ ecs-cli compose -f rocket-chat.yml up
INFO[0000] Using ECS task definition                     TaskDefinition=ecscompose-ecs:3
INFO[0000] Starting container...                         container=7d3c638c-add9-462c-84d2-8a74f3401a12/rocketchat
INFO[0000] Starting container...                         container=7d3c638c-add9-462c-84d2-8a74f3401a12/mongodb
INFO[0000] Describe ECS container status                 container=7d3c638c-add9-462c-84d2-8a74f3401a12/mongodb desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-ecs:3
INFO[0000] Describe ECS container status                 container=7d3c638c-add9-462c-84d2-8a74f3401a12/rocketchat desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-ecs:3
INFO[0012] Describe ECS container status                 container=7d3c638c-add9-462c-84d2-8a74f3401a12/mongodb desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-ecs:3
INFO[0012] Describe ECS container status                 container=7d3c638c-add9-462c-84d2-8a74f3401a12/rocketchat desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-ecs:3
INFO[0024] Describe ECS container status                 container=7d3c638c-add9-462c-84d2-8a74f3401a12/mongodb desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-ecs:3
INFO[0024] Describe ECS container status                 container=7d3c638c-add9-462c-84d2-8a74f3401a12/rocketchat desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-ecs:3
INFO[0036] Describe ECS container status                 container=7d3c638c-add9-462c-84d2-8a74f3401a12/mongodb desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-ecs:3
INFO[0036] Describe ECS container status                 container=7d3c638c-add9-462c-84d2-8a74f3401a12/rocketchat desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-ecs:3
INFO[0048] Started container...                          container=7d3c638c-add9-462c-84d2-8a74f3401a12/mongodb desiredStatus=RUNNING lastStatus=RUNNING taskDefinition=ecscompose-ecs:3
INFO[0048] Started container...                          container=7d3c638c-add9-462c-84d2-8a74f3401a12/rocketchat desiredStatus=RUNNING lastStatus=RUNNING taskDefinition=ecscompose-ecs:3

暫く間って「Started container…」と表示され、特にエラーが出なければ、コンテナの起動完了です。

先ほど YAML ファイルで定義した rocketchat と mongodb のコンテナが正常に稼働してるか調べるには、「ecs-cli ps」コマンドを使います。

$ ecs-cli ps
Name                                             State    Ports                           TaskDefinition
7d3c638c-add9-462c-84d2-8a74f3401a12/mongodb     RUNNING  54.64.171.210:32768->27017/tcp  ecscompose-ecs:3
7d3c638c-add9-462c-84d2-8a74f3401a12/rocketchat  RUNNING  54.64.171.210:80->80/tcp        ecscompose-ecs:3

State(状態)が「RUNNING」のため、正常に実行していることがわかります。ブラウザから表示されている IP アドレスのポート 80 を開いてみます。今回の例では「http://54.64.171.210」にアクセスします(対象コンテナは停止済みなので、実際にはアクセスできません。皆さんの環境によって異なりますので、都度ご確認ください)。すると、次のような Rocket.Chat 初期画面が表示されました。

Rocket.Chat のセットアップ方法や解説については、Qitia に書いた別記事をご参照願います(用途が違うと思ったので、記事を分けました)。

Rocket.ChatをDocker Composeで使う – Qiita
http://qiita.com/zembutsu/items/eea5c3216911b1ee71e1

ちなみに EC2 インスタンスにログインする事も可能です。今回の例でインスタンスを起動するとポート 80 しか公開していませんので、セキュリティ・グループを調整して SSH で入ることもできます。中身は Amazon Linux AMI ですそうすると、次のように「docker ps」コマンドでコンテナの状態を確認する事もできます(おそらくデバッグ以外では、通常使うことは無いと思います)。

[ec2-user@ip-10-0-0-4 ~]$ docker  ps
CONTAINER ID        IMAGE                            COMMAND                CREATED              STATUS              PORTS                        NAMES
b87b9a714a86        rocketchat/rocket.chat           "/bin/sh -c 'bash $M   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp           ecs-ecscompose-ecs-3-rocketchat-9ab591d1cdbcd7c6b601
5a24a29d9dbe        mongo                            "/entrypoint.sh mong   2 minutes ago        Up 2 minutes        0.0.0.0:32768->27017/tcp     ecs-ecscompose-ecs-3-mongodb-90b1f9dc81d6c6b58101
0f9b939687d9        amazon/amazon-ecs-agent:latest   "/agent"               44 minutes ago       Up 44 minutes       127.0.0.1:51678->51678/tcp   ecs-agent

「amazon/amazon-ecs-agent」は「ecs-cli」コマンドから見えないコンテナです。これは ECS に関するサービスを管理する役割があると思われます。

ちなみに、今回はフロントの rocketchat コンテナは1つでしたが、2台のサーバにスケールすることもできます。それには Docker Compose と同様の「scale」コマンドを使います。

$ ecs-cli compose -f rocket-chat.yml scale 2

再び「ecs-cli ps」を実行すると、コンテナが増えていることがわかります。

$ ecs-cli ps
Name                                             State    Ports                            TaskDefinition
084d9832-b1e5-4f0e-8396-ef435a830e7f/rocketchat  RUNNING  54.64.171.210:80->80/tcp         ecscompose-ecs:3
084d9832-b1e5-4f0e-8396-ef435a830e7f/mongodb     RUNNING  54.64.171.210:32770->27017/tcp   ecscompose-ecs:3
19a8f20e-250c-4f7e-a441-f3abe36605c9/mongodb     RUNNING  54.199.178.167:32770->27017/tcp  ecscompose-ecs:3
19a8f20e-250c-4f7e-a441-f3abe36605c9/rocketchat  RUNNING  54.199.178.167:80->80/tcp        ecscompose-ecs:3

なお、停止するには「ecs-cli compose -f rocket-chat.yml stop」を実行します。

■ タスクとサービス

以上の操作は ECS における「タスク」と呼ばれるもので、コンテナが終了すると、そのまま停止します。ECS にはもう1つ「サービス」という概念があり、ウェブサーバやデータベースなど、継続し続けるものを定義することができます。

一番大きな挙動の違いは、停止時の挙動です。タスクの場合、例えば何らかの理由でコンテナが異常終了したり停止したばあい、そのまま処理が完了します。一方の「サービス」の場合、停止しても別のインスタンスでコンテナを自動的に再開するという違いがあります。

コマンドレベルでの使い分けとしては「service」の有無になります。

タスク
・ecs-cli compose up で起動
・ecs-cli compose stop または down で停止

サービス
・ecs-cli compose service up で起動
・ecs-cli compose service stop または service down で停止

■ インスタンスの削除

EC2 インスタンスは、何もしなければそのまま課金が続きます。使い終わった場合は「ecs-cli down」コマンドを使い、インスタンスごと環境を削除します。

$ ecs-cli down --force

ただし、サービスを全て停止しないとインスタンスも終了できないので注意が必要です。削除できず、コマンドラインの操作で混乱してしまう場合は、マネジメントコンソール上からタスクやサービスを停止すると上手くいきます。

■ まとめ

Docker Machine や Docker Compoes と Amazon ECS CLI を比較すると、利用者視点では非常に機能が似通っていることに気づきます。おそらく、既に Docker を使っている方にとっては、ECS CLI は使いやすいものになるのではないでしょうか。また、ECS を利用されている方にとっても、ECS CLI はブラウザや従来の CLI を使った作業よりも、迅速な作業につながると思われます。

なにより、これまで Docker を触ったことがない方にとって、ECS CLI を使うことで Docker 環境の構築・管理を意識せず、コンテナを使える環境が手に入ったと言えるのではないでしょうか。とりあえず試すための選択肢は増えたとも言えるでしょう。

注意点としては、あくまで今回は「作ってみた」レベルであり、サービスやデータの可用性・冗長性なりは考慮していません。おそらく、様々なサービスと連携するような、いわゆるデザイン・パターン的な考慮が用途に応じて必要です。

■ 参考資料

Using the Amazon ECS Command Line Interface – Amazon EC2 Container Service
http://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_CLI.html

EC2 Container Service Update – Container Registry, ECS CLI, AZ-Aware Scheduling, and More | AWS Official Blog
https://aws.amazon.com/jp/blogs/aws/ec2-container-service-update-container-registry-ecs-cli-az-aware-scheduling-and-more/

Amazon Web Services ブログ: 【AWS発表】EC2 Container Serviceアップデート – Container Registry, ECS CLI, AZを意識したスケジュリング、その他
http://aws.typepad.com/aws_japan/2015/10/ec2-container-service-update-container-registry-ecs-cli-az-aware-scheduling-and-more.html