インフラチームによくある極小サーバーやバッチジョブをECSで集約したい

すごい。この記事には文字しかない。

話の発端

ほとんどアクセスが無く、あっても昼間しかなく、しかし消すわけにはいかない社内サービスのようなデモサービスのようなサーバーが豪勢にもEC2単独インスタンスを持っていると、CPUを使わなすぎてリソースがもったいなかったり、たまったCPUクレジットを捨ててしまったりしてもったいない。日時バッチサーバーみたいなものも似たような状況で、バッチ稼働時以外は上と同じ無駄を今も発生させている。

では、全部Elastic Container Serviceでコンテナにしてインスタンスを集約して、昼間ためたクレジットを夜中の日時バッチで使うのはどうか、という手を考えた。外国リージョンではAWS Batchってやつが使えるようになっているので、そいつが東京リージョンに来たときにうまいことECSから移行できると最高に素敵だ。

各ミニサービスのECSへの集約

上述ミニサーバー群はまがいなりにもサーバーで、しかもSSLなので、IPを固定したい。

が、コンテナにEIPを付けることはできず、Global IPを持たせたい場合は、かわりにELBを使うのが定石1

なのだが、さして重要でもないのにELBを使うのはオーバースペック、というかお金の無駄なので、Unmanagedなコンテナインスタンスを作成し、その中でnginxを動かして、コンテナにリバースプロキシすればーーー、ということを考えていた。コンテナインスタンス障害時にはまるごと作り直せばいいようなサービスレベルだし、それが簡単にできちゃうのがコンテナの長所だ。

が、じゃあそもそもnginxもコンテナでよくね、っていうことに気付いた。コンテナ間でリバースプロキシしちゃえばいいじゃん。

ELB無しでSSLできるコンテナインスタンスの作成

つまりコンテナインスタンスにEIPをつけたい、ということ。ECSのウィザードからクラスタを作成する場合、コンテナインスタンスのカスタマイズ可能項目は少ない。カスタム可能 (つまりコンテナインスタンス作成時に指定可能) なものは

  • インスタンスタイプ
  • ディスク容量
  • VPC
  • Security Group

だけで、Public IPとPrivate IPは自動的に割り当てられるため、コンテナインスタンス作成時にIPやEIPの指定はできない。なので、このあとに、作成されたEC2インスタンスに対して

  1. EIPを作成
  2. EIPをコンテナインスタンスのインターフェースに割り当て

ってやるとコンテナインスタンスのIPを安全に固定できる。

実際にEIPを付けた直後からコンテナに疎通可能になっていて、しかもECSから見えるコンテナインスタンス情報も自動で更新され、Global IPは新しいEIPになっていることが確認できる。便利な世の中になったもんだ。

コンテナ間リンク

nginxもコンテナなので、リバースプロキシ先はコンテナのリンクでOK、と思っていたのだが、なんとコンテナのリンクは同じタスク定義に属したコンテナ間のみで可能とのこと2。つまりexternal_linkは書けない。でも今回のユースケースだと、コンテナごとにタスク定義を変えるタイミング (Docker imageの更新とか) は異なるので、コンテナごとにタスク定義を作ることになる。

ってことは、コンテナごとに80:10080443:10443みたいなPort Mappingを書き、nginxはこのポートとコンテナインスタンスのローカルアドレスで、各コンテナへリバースプロキシする。まぁPort Mappingは複数コンテナインスタンスにまたがってコンテナを配置をしたい場合とかに結局必要だよね、たぶん。

Unmanaged Container Instanceを作りたい場合

ちなみに、どうしてもオレオレカスタムなUnmanagedコンテナインスタンスを作りたいときは

  1. 自力でEC2インスタンスを作成する

    • AWSが用意しているECS用のAMIを使う
    • か、それ以外を使う場合は自分でAgentのインストールなどが必要
    • めんどくさいけどEC2でインスタンスをいろいろいじれる
  2. ECSクラスタ作成時に空のクラスタを作る
  3. さっきのインスタンスをクラスタに追加する

という手順で可能らしい3

でもnginxもコンテナにしちゃうなら、ECSウィザード経由でデフォルトのAMI使う方が再作成と運用が楽な気がする。できるだけ外の世界へ出て行こうとしないのがパブリッククラウドの鉄則。

AWS Batch

ドキュメントを†熟読† (3分) した感じ、ECSにジョブキューを付けて、順番やリトライ、キューごとの計算環境の割り当て、実行時間やリソースの制限、優先度とかを定義できるようにしたものっぽい。†熟読†して思ったことは、

  • 要はPBS4サービスみたいなもんじゃね? PBSのインストールと運用は意外にめんどくさいらしい。というか需要がニッチすぎて活発には開発されてないらしい。通常SQSとかAMQPが実装された何かを使うんじゃないかしら。
  • GPUインスタンスが使えたりとか、AWSをスパコン的に使いたい人にはグッとくるのかもしれない5が、いるのかそんな人?並列性能上げると青天井でお金かかるし、1週間かかる機械学習だとやっぱり青天井でお金かかるし、そういう人は京とかどっかのスパコン借りた方が安いんじゃ……ぶつぶつ……

というわけで、AWS Lambdaで時間足りない人向け、という位置づけが現実的。

ECSからAWS Batchへの移行を考える

東京リージョンで今でも使えるECSから、今後東京リージョンにも展開されるであろうAWS Batchへの移行を考えると、既存のECSクラスタをAWS BatchのCompute Environment (CE) に変換できるとうれしいぞ。ドキュメントを読んでみると

By default, AWS Batch managed compute environments use the latest Amazon ECS-optimized AMI for compute resources.6

どうやらCEはECSのAMIをそのまま使うだけっぽいので、ECSクラスタを作ったあとにCEに追加できるのでは?と思ったが、 (画面上からは) ECSクラスタをCEに変換することはできなさそう。逆はできる、つまりCEをECSクラスタとして扱うことはできる。というか、CEを作った時点で空のECSクラスタが作成されている。末尾にUUIDとかついた、とてもゴチャったECSクラスタが作成される。

AWSというサービスの哲学として、Manageされるもの (e.g. ECSクラスタ) はManageするもの (e.g. CE) にはできない。これは言われれば分かるけど、気付かないと「不便だ」と不要な精神の不衛生を招く。

というわけで、ECSからそのままBatchに移行はできなさそうなので、今回のように特定のEIPを使い続けたいような場合、ECSコンテナインスタンスのEIPを、CEから生まれたECSコンテナインスタンスに移行時に付け替えることになる。

API使っても瞬断が出るが、まぁそもそもそこまでサービスレベルは高くない。はずだ。

でもこれって、ECSクラスタ間でコンテナインスタンスの移動ができれば解決するんじゃ?

と思って調べてみると

各コンテナインスタンスには、それぞれに固有の状態情報がコンテナインスタンスにローカルで保存され、Amazon ECS にも保存されているため、コンテナインスタンスを 1 つのクラスターから登録解除して別のクラスターに再登録しないでください。コンテナインスタンスリソースを再配置するには、1 つのクラスターからコンテナインスタンスを終了し、新しいクラスター内の Amazon ECS に最適化された最新の AMI で、新しいコンテナインスタンスを起動することをお勧めします。7

ぐはっ……。

サーバー系はECSに残し、バッチ系だけAWS Batchに、という住み分けが清潔なのかもしれないけど、それじゃ集約にならないなぁ。

Refs.

続きを読む

Mastodonのrake mastodon:dailyをLambdaで定期実行する

ドキュメント
https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Production-guide.md
これやらないとこういうことが起きるので大事。
http://cryks.hateblo.jp/entry/2017/04/18/125351
まさに自分のサーバーで起きて大変だった…。

環境

前回のAWS EC2 Container Service
http://qiita.com/kawax/items/5307b58e549dd9cc3928

これでcronはどうやるんだろうと調べたけど結構簡単だった。

ECSタスク

aws-daily.yml

version: '2'
services:
  web:
    image: {image}
    env_file: .env.production
    command: bundle exec rake mastodon:daily
    mem_limit: 536870912
    ports:
      - "3000"
ecs-cli compose -f aws-daily.yml --project-name mastodon-daily create

Lambda

ランタイム:Node.js 6.10
ブランク関数で新規に作っていく。

トリガーで CloudWatch イベント - スケジュール を選択。
ルール名やルールの説明は適当なものを。
スケジュール式は rate(1 day)

ロールはカスタムロールの作成から新規ロールを作った後で
管理ポリシーAmazonEC2ContainerServiceFullAccessを付ける。
インラインポリシーoneClick_lambda_basic_executionも付いてるはず。
この辺は後でLambda 関数が実行できるポリシーを付ける。

コード

clusterとtaskDefinitionを自分のものに書き換える。

var AWS = require('aws-sdk');
var ecs = new AWS.ECS();

exports.handler = (event, context, callback) => {
    var params = {
        cluster: "mastodon", 
        taskDefinition: "ecscompose-mastodon-daily"
    };
    ecs.runTask(params, function(err, data) {
        if (err) console.log(err, err.stack); // an error occurred
        else     console.log(data);           // successful response
    });
};

テストしてみてエラーが出てなければトリガーを有効化して終わり。
エラーが出てる場合はロールを確認する。

続きを読む

全力AWSでMastodonサーバー立てました chitose.moe

https://chitose.moe/

スポンサーが1社付いてるのですぐに消えたりはしないはず。
メール送信数制限の都合で1日のユーザー登録数には上限がある。
メールが届かない時は暫く待つか24時間後に再送信。
とはいえ5万なので上限になることはないか。

環境

  • AWS
  • EC2 Container Service
  • ecs-cli
  • RDS(PostgreSQL)
  • ElastiCache(Redis)
  • S3
  • CloudFront
  • ALB
  • SES

やれるだけやって分散した。
いくらでもサーバー増やせるけどたぶんそこまで必要にはならない。

最後SESのsandbox解除待ちで時間かかった…。

途中段階の役に立たないメモ

ローカルで動かすだけならVagrantのほうが早い。
最初から管理者アカウントも作られる。

docker-composeはproduction用。

git clone https://github.com/tootsuite/mastodon
cd mastodon
sudo curl -o /usr/local/bin/ecs-cli https://s3.amazonaws.com/amazon-ecs-cli/ecs-cli-darwin-amd64-latest
sudo chmod +x /usr/local/bin/ecs-cli
ecs-cli help
ecs-cli configure -p default --cluster mastodon
ecs-cli up ...
aws ecr get-login
docker login ...
aws ecr create-repository --repository-name mastodon
docker build -t mastodon .
docker tag mastodon:latest ...
docker push ...

docker-compose.ymlを編集
– buildの代わりにimage: mastodon
– DB永続化するためコメントを消す

ecs-cli compose service up

ここで上手く動かなくなった。
Elastic Beanstalkでやろうとしたけどこっちもだめ。
いろいろやってるうちにオリジナルのdocker-compose.ymlが事前に用意したDocker image使うようになってた。
ECS使う方法に戻る…。

assetsを削除して再生成してS3にアップ。
precompileを繰り返すとファイルが増える…?

rm -rf ./public/assets
docker-compose run --rm web rails assets:precompile

aws s3 cp ./public/assets s3://{S3バケット}/assets --recursive --acl public-read --cache-control "max-age=604800"

S3に置くと/public/assets以下がないのでprecompile済みファイルが使われない。
sprockets-manifestが必要。
S3に置くのはやめた。
image: gargron/mastodonは使わず自分でビルドする方法に戻る…。

.dockerignoreを変更してimageにassetsも含まれるように。

#public/assets

docker-compose.ymlをコピーしてaws.ymlを作りこっちを書き換えて行く。
docker-compose.ymlはローカル用に元のまま。
あ、当然gitのブランチは分けてる。

AWSのECSでは

  • buildが使えない
  • volumesで相対パスが使えない

という仕様なのでそれに合わせる。
volumesはよくわからないのでほぼ使わないように…。

ここからも色々苦労したけど細かすぎてもう忘れたのでメモ程度。
AWSのサービスで使えるものは使う。
db,redisはもちろん分離。
S3も当たり前に使う。
nginxは不要だった。nginx使おうとして無駄に混乱…。
ポートマッピングはELB。
httpsへのリダイレクトはCF。

LOCAL_HTTPS=falseでも問題なくhttpsで動くけどメール内のURLだけhttpになる。
リダイレクトされるので妥協。

ecs-cli compose serviceで--load-balancer-name付きで起動だけどうしてもできなかったので諦めた。

/api/v1/streamingはサブドメインにした。
STREAMING_API_BASE_URLで指定すればそれが使われる。
LOCAL_HTTPS=falseだとwebsocketでエラー出てたので無理矢理な対応。

S3_BUCKETS3_HOSTNAMEはS3のドメインそのまま使う用で
自分のサブドメイン使う場合はS3_CLOUDFRONT_HOSTも設定する。
CF使ってるかに関係なく静的ホスティングなら。

nginx使わなくても動いてるけど何か問題あれば後で修正していく。

docker-compose.ymlあるから簡単に動かせるかと思ったけどそんなことはなかった。
EC2上でdocker-compose upすれば簡単だけどそれじゃAWSの意味がない。

ALBの使用

その後調べて分かったので追記。
--load-balancer-nameはClassic Load Balancer用なので違う。
ALBは--target-group-arnを使う。
ただしサービスごとに一つしか設定できないのでサービスを複数作るしかない?

ecs-cli compose -f aws.yml --project-name mastodon-web service create --target-group-arn {web用のターゲットグループ} --container-name web --container-port 3000 --role ecsServiceRole

ecs-cli compose -f aws.yml --project-name mastodon-api service create --target-group-arn {streaming用のターゲットグループ} --container-name streaming --container-port 4000 --role ecsServiceRole

--project-nameの指定も必要になった。

ecs-cli compose -f aws.yml --project-name mastodon-web service up

AutoScalingでEC2インスタンス数を増減。
一つのEC2内で複数のタスクが動くし、タスクもAutoScalingできるようになった。

サービスを分けるならaws.ymlも分割したほうがメモリの無駄もない。

最終版

ごちゃごちゃしたのでまとめ。

aws-web.yml

mem_limitは分からないので仮。
portsの0が動的ポートのために必要。
もしくは0:部分なしでいいかも。こっちは未検証。

version: '2'
services:

  web:
    restart: always
    image: {自分のimage}
    env_file: .env.production
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    mem_limit: 536870912
    ports:
      - "0:3000"

aws-api.yml

version: '2'
services:
  streaming:
    restart: always
    image: {自分のimage}
    env_file: .env.production
    command: npm run start
    mem_limit: 268435456
    ports:
      - "0:4000"

  sidekiq:
    restart: always
    image: {自分のimage}
    env_file: .env.production
    command: bundle exec sidekiq -q default -q mailers -q pull -q push
    mem_limit: 268435456

ALB

ターゲットグループ

  • port3000のweb用
  • port4000のstreaming用

を作る。

リスナーHTTPS 443
ヘルスチェックのポートをトラフィックポートにする。

  • HostがAPI用のサブドメインならstreaming
  • Pathが/ならweb

というルールを設定する。

CloudFrontはこのALBをOriginにする。
/assets以下はキャッシュ強く。他は短め。

Route53はCloudFrontを指定。

今後のためのアップデート手順

masterブランチを最新にしてからマージ。

DB_HOSTはRDSを指定してるのでdb:migrateはローカルから直接行う。
これはどうなんだろうとは思うけど他の方法が分からなかった。

docker-compose build
docker-compose run --rm web rails db:migrate
docker-compose run --rm web rails assets:precompile

docker imageの更新はECRの手順通りに。

aws ecr get-login --region ap-northeast-1 | bash

docker build ...
docker tag ...
docker push ...

ecs-cli使ったほうが少し短いかも。

docker build ...
docker tag ...

ecs-cli push ...

後はup。upはymlが変更されてないと以前のタスクのままなのでimageだけ更新した場合は更新されない。
CIで動かしてdocker tagを設定してymlの書き換えまで自動化かな。

ecs-cli compose -f aws-web.yml --project-name mastodon-web service up
ecs-cli compose -f aws-api.yml --project-name mastodon-api service up

動きさえすれば運用段階では楽になる。

続きを読む

ECSでGPUを扱うためのAMI作成 by Amazon Linux Deep Learning AMI

結論

ここ見れば一発だった
http://docs.aws.amazon.com/ja_jp/batch/latest/userguide/batch-gpu-ami.html

概要

scriptとかは変更があるかもしれないので転記しません。上記URLを参照してください。
以下の項番は上記URLの番号と合わせています。

  1. Amazon Linux Deep Learning AMIを起動する

    1. 強いて言うならp2で立ち上げた方が楽しい
    2. でも高いからSpotInstanceを使おう。マーケットプレイスの画面から進むとSpotInstanceが選択出来た
  2. SSHで接続する
  3. URL内のconfigure-gpu.shを作成する
  4. configure-gpu.shを実行する(結構待つ)
  5. Dockerコンテナを実行して、インストールされているドライバにアクセスできることを確認する(以下のような結果が出力されること)
  6. ゴミ掃除をする
No.5の実行結果
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 367.57                 Driver Version: 367.57                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla K80           On   | 0000:00:1E.0     Off |                    0 |
| N/A   47C    P8    26W / 149W |      0MiB / 11439MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+


+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

あとの作業

これをECSのAMIとして使って、ECSの特権フラグをOnにする

続きを読む

JenkinsおじさんのためのAWS Batch

はじめに

この記事の対象者

主にこんな感じの人をターゲットにしています。

  • Jenkinsでジョブを管理している
  • AWSをcliで触るのは実は大変…。GUIでやりたい
  • Dockerはインストールはしているけれど、あんまり触ったことが無い

また、本記事執筆時点では、us-east(virginia)でのみ利用可能なので、VPCでの利用はあまり想定していません。 (VPNを繋げば出来ると思いますが…)
本来はAuto ScalingやSPOTインスタンスと組み合わせたりといろいろあるのですが、私的事情により、志は低く、過疎っているJenkinsサーバを廃止(サーバレス化)することを目標にしています。

対象のJenkinsジョブ

今回ターゲットにするのは、Jenkinsだと一般的と思われる以下の処理とします。

  • JDKがバージョン指定で入っている
  • バッチ処理の入ったリポジトリをgit cloneしてくる
  • シェルスクリプトからごにょごにょして、リポジトリの中身を実行する

PHPやRubyなど別言語の人は、Javaな部分は脳内で別言語に置き換えてみてください。

AWS Batchでの流れ

Jenkinsでごく一般的なこの処理をAWS Batchでやろうとした場合、以下のような流れが一番シンプルになるかなと思います。

  1. JDK等、必要な実行環境を準備したDockerfileを作成する
  2. Jenkinsでやっていたシェル相当のシェルスクリプトを作成する
  3. リポジトリにDockerfileとシェルスクリプトを追加する
  4. Amazon ECRに設定を作成する
  5. Dockerfileでビルドし、JDK及びバッチ処理のリポジトリの入ったコンテナを作成し、ECRにプッシュする
  6. AWS Batchの設定(IAM Role, Compute Environment, Job Definition等)を作成する
  7. AWS Batchを実行する

というわけで、ハンズオン的に進めて行きたいと思います。

作業手順

1. Dockerfileの作成

古風なエンジニアにはこちらの記事が一番わかりやすいんじゃないかと思います。

効率的に安全な Dockerfile を作るには

今回のケースだとJavaのバッチ(Hello.class)を動かしたいので

$ ls
Hello.class

$ vim Dockerfile

として、以下のようなDockerfileを作成します。

Dockerfile
FROM centos:6

RUN yum install -y java-1.7.0-openjdk java-1.7.0-openjdk-devel
ENV JAVA_HOME /usr/lib/jvm/java-openjdk
RUN mkdir /opt/batch-directory
COPY . /opt/batch-directory/
WORKDIR /opt/batch-directory

Javaは諸々の事情からOpenJDKにしていますが、Oracle Javaが必要な場合は、少し手間はかかりますが、Oracle Javaでもコンテナを作成することはできます。また、本来だとベースイメージはAmazonLinuxだったりJavaが入ったコンテナの方が良いと思いますが、保守的な方のために、敢えてCentOSにしました。(あんまり意味ないかな…)

2. シェルスクリプトの作成

Jenkinsにバッチを実行するためのシェルスクリプト(Jenkinsでコマンド欄に入れていたようなもの)を作ります。

$ ls
Dockefile
Hello.class

$ vim batch.sh

今回は解説用なので雑なものを用意しています。

batch.sh
#!/bin/bash

java -version
java Hello

3. Dockerfileとシェルスクリプトをリポジトリに追加

せっかく作成したので、これらのファイルをGitリポジトリに追加しましょう。(これはこの後の工程上の必須項目ではないので、一連がテストされてからでも大丈夫です)

4. Amazon ECRにリポジトリを作成する

Amazon EC2 Container Registry(ECR)にリポジトリを作成します。ここではリポジトリ名を入れるだけです。
Amazon EC2 Container Service.png

5. Dockerfileでビルド

先ほど付けた名前を使って、Docker buildをします。

$ docker build -t unagi/jenkins-ojisan .

6. コンテナをECRに登録する

タグ付けして、先ほど作成したECRに登録してあげます。

$ aws ecr get-login --region us-east-1

# これでdocker loginに必要なコマンドがでてくるので、実際はそれを使う
$ docker login -u AWS -p xxxxxx -e none https://xxxx.dkr.ecr.us-east-1.amazonaws.com
$ docker tag unagi/jenkins-ojisan:latest xxxx.ecr.us-east-1.amazonaws.com/unagi/jenkins-ojisan:latest
$ docker push xxxx.ecr.us-east-1.amazonaws.com/unagi/jenkins-ojisan:latest

7. AWS Batchの設定をつくる

Job definitionとCompute environmentを設定します。

こちらがJob definitionで、コンテナを起動するときの設定になります。環境変数を設定できるので、パラメータを渡したい場合は使う事ができます。
AWS Batch (1).png

S3アクセス等でIAM Roleを使いたい場合は、ここで定義するJob Roleで定義する必要があります。そしてさらに分かりにくいことに、ここに表示されるIAM Roleを作るためには、信頼するエンティティがAmazon EC2 Container Service Task Role(ecs-tasks.amazonaws.com)のIAM Roleを作る必要があります。IAM Role作成時に似たようなのが沢山あるので、非常に解りづらいところです。

そして、次の画面はCompute environmentです。
AWS Batch (2).png
こちらはあまり見所は無く、淡々と設定していきます。ここで出てくるRoleは、ECSで動作するために必要なもので、コンテナで使うモノではありません。なので、適当に作成します…。

8. AWS Batchの実行

Job definitionsからSubmit jobして実行します。実行時に先ほど設定した環境変数を変更しながらの実行等もできます。
ちなみにこれも凄く分かりにくいのですが、Job definitionを編集したい場合はCreate new versionです。新しいバージョンの定義が出来てしまうので、古い方は不要になった段階で削除してしまいましょう。

9. 実行ログの確認

CloudWatchのログから見ます。Submitしてから起動までは少し時間がかかるので、少し待たないとログ出力はされません。

あとがき

Jenkinsおじさん的には、Dockerが出てくるため取っつき辛い印象を持つのかなと思います。
美しくDockerを使う場合はさておき、バッチ処理をやるだけであれば、Dockerfileに書くのはバッチサーバを作るときのセットアップコマンドで、一回やってしまえばあまり難しくないです。

続きを読む

Amazon ECS デバッグ方法

ログ等のデバッグ情報 種類

ECSにおいて以下の種類のログ等を活用したデバッグ方法を説明します。

  • アプリケーションログ
  • Amazon ECS サービス ログ
  • Amazon ECS タスク ログ
  • Amazon ECS コンテナエージェントログ
  • Amazon ECS ecs-init ログ
  • タスク認証情報の監査ログ用の IAM ロール
  • ECS Logs Collectorの使用
  • エージェントのイントロスペクション診断
  • API failures エラーメッセージ

アプリケーションログ

ECS上のDockerで起動しているアプリケーションのログ出力の設定をします。

サイドメニューの[タスク定義]から新しいリビジョンのタスクを定義する際に[コンテナの定義]をします。このときに[ストレージとログ]項目中のログを以下のように設定します。

  • ログ設定

    • ログドライバー

      • awslogs
    • ログオプション
      • awslogs-group

        • sample-ecs-loggroup
      • awslogs-region
        • us-east-1
      • awslogs-stream-prefix
        • sample-ecs

以上で例えば、Node.jsを使用するときはconsole.log()などで出力される内容を
CloudWatchのサイドメニューの[ログ]から先程指定したawslogs-groupの項目にログ内容が出力されます。

Amazon ECS サービス ログ

クラスター > <対象のクラスター>で[サービス]タブ中のサービス一覧から対象のサービスを選択します。
遷移先のページの[イベント]タブ中のページで各イベントのイベント時間、メッセージなどが出力されるので参考にする。

Amazon ECS タスク ログ

クラスター > <対象のクラスター>で[タスク]タブの[必要なタスクのステータス]から[Stopped]を選択します。

すると、タスクが停止した場合などの原因などが表示される。

Amazon ECS コンテナエージェントログ、Amazon ECS ecs-init ログ、タスク認証情報の監査ログ用のIAMロール

EC2インスタンスにSSHでログインします。

$ ssh -i ~/.ssh/id_rsa ec2-user@XX.XX.XX.XX
$ sudo yum install vim
$ vim /etc/sysconfig/docker

以下のようにOPTIONSの設定に-D"--default-ulimit nofile=1024:4096"の先頭に追加することでログ出力を詳細に出力します。

Before

# The max number of open files for the daemon itself, and all
# running containers.  The default value of 1048576 mirrors the value
# used by the systemd service unit.
DAEMON_MAXFILES=1048576

# Additional startup options for the Docker daemon, for example:
# OPTIONS="--ip-forward=true --iptables=true"
# By default we limit the number of open files per container
OPTIONS="--default-ulimit nofile=1024:4096"

# How many seconds the sysvinit script waits for the pidfile to appear
# when starting the daemon.
DAEMON_PIDFILE_TIMEOUT=10

After

# The max number of open files for the daemon itself, and all
# running containers.  The default value of 1048576 mirrors the value
# used by the systemd service unit.
DAEMON_MAXFILES=1048576

# Additional startup options for the Docker daemon, for example:
# OPTIONS="--ip-forward=true --iptables=true"
# By default we limit the number of open files per container
OPTIONS="-D --default-ulimit nofile=1024:4096"

# How many seconds the sysvinit script waits for the pidfile to appear
# when starting the daemon.
DAEMON_PIDFILE_TIMEOUT=10
$ sudo service docker restart

ECSのログは/var/log/ecs/以下に吐き出される。

ログの種類

  • Amazon ECS コンテナエージェントログ
    /var/log/ecs/ecs-agent.log.timestamp.YYYY-MM-DD-HH
  • Amazon ECS ecs-init ログ
    /var/log/ecs/ecs-init.log.timestamp.YYYY-MM-DD-HH
  • タスク認証情報の監査ログ用の IAM ロール
    /var/log/ecs/audit.log.YYYY-MM-DD-HH

/var/log/ecs/ecs-agent.log.2017-03-26-17

2017-03-26T17:00:56Z [INFO] Starting Agent: Amazon ECS Agent - v1.14.1 (467c3d7)
2017-03-26T17:00:56Z [INFO] Loading configuration
2017-03-26T17:00:56Z [INFO] Checkpointing is enabled. Attempting to load state
2017-03-26T17:00:56Z [INFO] Loading state! module="statemanager"
2017-03-26T17:00:56Z [INFO] Restored cluster 'sample-cluster'
2017-03-26T17:00:56Z [INFO] Event stream ContainerChange start listening...
2017-03-26T17:00:56Z [INFO] Detected Docker versions [1.17 1.18 1.19 1.20 1.21 1.22 1.23]
2017-03-26T17:00:56Z [INFO] Restored from checkpoint file. I am running as 'arn:aws:ecs:us-east-1:xxxxxxxxxxxxxxxxxx:container-instance/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' in cluster 'sample-cluster'
2017-03-26T17:00:56Z [INFO] Registered! module="api client"
2017-03-26T17:00:56Z [INFO] Adding image name- xxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/sample-repository to Image state- sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
2017-03-26T17:00:56Z [INFO] Updating container reference sample-container in Image State - sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
2017-03-26T17:00:56Z [INFO] Saving state! module="statemanager"

/var/log/ecs/ecs-init.log.2017-03-26-17

2017-03-26T17:00:55Z [INFO] pre-start
2017-03-26T17:00:55Z [INFO] start
2017-03-26T17:00:55Z [INFO] Container name: /ecs-sample-task-1-sample-container-xxxxxxxxxxxxxxxxxxxxxxx
2017-03-26T17:00:55Z [INFO] Container name: /ecs-agent
2017-03-26T17:00:55Z [INFO] Removing existing agent container ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
2017-03-26T17:00:55Z [INFO] Starting Amazon EC2 Container Service Agent

(参照) エージェントの再起動方法

$ sudo stop ecs
$ sudo start ecs

ECS Logs Collectorの使用

ECS Logs Collectorを使用することで、オペレーティングシステムログやDocker、ECS コンテナエージェントログを一括して集約することができます。
https://github.com/awslabs/ecs-logs-collector

$ curl -O https://raw.githubusercontent.com/awslabs/ecs-logs-collector/master/ecs-logs-collector.sh
$ sudo bash ./ecs-logs-collector.sh

ログ情報はcollectディレクトリ以下に集められます。例えば、以下のような構成されます。

collect
└── system
    ├── docker
    │   ├── container-310f75292484.txt
    │   ├── container-537de59ea686.txt
    │   ├── docker-images.txt
    │   ├── docker-info.txt
    │   ├── docker-ps.txt
    │   └── docker-version.txt
    ├── docker_log
    │   └── docker
    ├── ecs-agent
    │   ├── agent-running-info.txt
    │   ├── ecs-agent.log.2017-03-26-17
    │   ├── ecs.config
    │   └── ecs_agent_data.txt
    ├── iptables.txt
    ├── lvs.txt
    ├── mounts.txt
    ├── netstat.txt
    ├── pkglist.txt
    ├── ps.txt
    ├── pvs.txt
    ├── selinux.txt
    ├── services.txt
    ├── top.txt
    ├── var_log
    │   ├── dmesg
    │   └── messages
    └── vgs.txt

エージェントのイントロスペクション診断

ECSエージェントのイントロスペクション APIで診断情報を取得し、Docker IDの特定などを行います。

$ curl http://localhost:51678/v1/tasks | python -mjson.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3731    0  3731    0     0   429k      0 --:--:-- --:--:-- --:--:--  455k
{
    "Tasks": [
        {
            "Arn": "arn:aws:ecs:us-east-1:xxxxxxxxxxxxx:task/xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "Containers": [
                {
                    "DockerId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                    "DockerName": "ecs-sample-task-1-sample-container-xxxxxxxxxxxxxxxxxxxxx",
                    "Name": "sample-container"
                }
            ],
            "DesiredStatus": "STOPPED",
            "Family": "sample-task",
            "KnownStatus": "STOPPED",
            "Version": "1"
       }
    ]
}

先程調べたDocker IDを使用して、

ログ

$ docker logs <Docker ID> | head

コンテナ検査

$ docker inspect <Docker ID>

API failures エラーメッセージ

マネジメントコンソール、およびCLIからコマンドを叩いたときに出力されるエラー内容を参照しましょう。
各表示項目におけるエラー詳細は以下のURLを参照。
http://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/troubleshooting.html#api_failures_messages

参考

http://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/troubleshooting.html

続きを読む

AWSの各サービスを雑に紹介する

えー、投稿しておいて何ですが、本稿本当に雑ですので、ご利用にあたってはあくまで自己責任ということで、よろしくお願いします。

コンピューティング

  • Elastic Compute Cloud (EC2)
    仮想専用サーバ、従量課金制 ≫公式

  • EC2 Container Registry (ECR)
    DockerHubみたいなやつ ≫英語公式 / Google翻訳 ≫Developers.IO

  • EC2 Container Service (ECS)
    Dockerオーケストレーション(デプロイ、起動停止制御) ≫公式 ≫@IT

  • Lightsail
    仮想専用サーバ、定額制 ≫公式

  • AWS Batch
    ECS対応バッチジョブスケジューラ ≫公式 ≫公式 ≫Developers.IO

  • Elastic Beanstalk
    プログラム実行環境 (Java, PHP, .NET, Node.js, Python, Ruby)、EC2を使用 ≫公式 ≫YouTube

  • AWS Lambda
    プログラム実行環境 (Node.js, Java, C#, Python)、サーバレス ≫公式

  • Auto Scaling
    EC2対応オートスケール制御 ≫公式

  • Elastic Load Balancing
    負荷分散、BIG-IPとかその手のヤツのクラウド版 ≫公式 ≫@IT

ストレージ

  • Amazon Simple Storage Service (S3)
    オブジェクトストレージ。ファイルサーバとしても一応使える ≫公式

  • Amazon Elastic Block Store (EBS)
    ブロックデバイス ≫CodeZine

  • Elastic File System (EFS)
    ファイルサーバ ≫公式

  • Glacier
    バックアップストレージ ≫公式

  • Snowball
    HDDをFedExで送るオフラインデータ転送

  • Storage Gateway
    バックアップデバイスはお客様各自のオンプレミスにてご用意下さい、AWSは対向するインターフェースを提供します、というもの ≫CodeZine ≫Developers.IO

データベース

ネットワーキング & コンテンツ配信

移行

  • Application Discovery Service
    オンプレミスサーバの構成管理情報を収集する ≫公式

  • Database Migration Service (DMS)
    RDBをオンプレミスからAWSへ乗り換えるときに使う支援ツール

  • Server Migration Service (SMS)
    サーバをオンプレミスからAWSへ乗り換えるときに使う支援ツール

開発者用ツール

  • CodeCommit
    GitHubみたいなやつ

  • CodeBuild
    従量課金制ビルド

  • CodeDeploy
    コードデプロイ

  • CodePipeline
    Continuous Integration (CI) オーケストレーション。ビルド→デプロイの自動実行フロー定義。

  • AWS X-Ray
    分散アプリケーションのトレース ≫Serverworks

管理ツール

セキュリティ、アイデンティティ、コンプライアンス

  • AWS Identity and Access Management (IAM)
    AWSの認証、権限管理単位 ≫Developers.IO

  • Inspector
    脆弱性検出 ≫公式

  • Certificate Manager
    X.509証明書の管理 ≫公式

  • AWS Cloud Hardware Security Module (HSM)
    秘密鍵の保管(暗号、署名) ≫公式

  • AWS Directory Service
    Active Directory ≫Developers.IO

  • AWS Web Application Firewall (WAF)
    ファイアーウォール ≫公式

  • AWS Shield
    DDoS対策 ≫公式

分析

人工知能

IoT

ゲーム開発

モバイルサービス

  • Mobile Hub
    AWSのいろんなmBaaS系サービスを統合的に使えるコンソール画面 ≫Qiita

  • Cognito
    ソーシャル認証+データ同期。FacebookログインとかTwitterログインとか ≫Cookpad

  • AWS Device Farm
    テスト環境。Android, iOSの実機にリモートアクセスしてテストができる ≫公式

  • Mobile Analytics
    アプリの使用データの測定、追跡、分析 ≫公式 ≫Developers.IO

  • Pinpoint
    プッシュ ≫Qiita

アプリケーションサービス

  • Step Functions
    フローチャートみたいなビジュアルワークフローを画面上に描いて分散アプリケーションを構築する、というもの ≫公式

  • Amazon Simple Workflow (SWF)
    旧世代サービス。現在はStep Functionsを推奨 ≫公式

  • API Gateway
    HTTP API化 ≫公式

  • Elastic Transcoder
    動画、音声のフォーマット変換。つんでれんこaaSみたいなヤツ ≫Serverworks

メッセージング

  • Amazon Simple Queue Service (SQS)
    メッセージキュー ≫公式

  • Amazon Simple Notification Service (SNS)
    プッシュ ≫公式

  • Amazon Simple Email Service (SES)
    E-mail配信。メルマガとか ≫公式

ビジネスの生産性

デスクトップとアプリケーションのストリーミング

  • Amazon WorkSpaces
    仮想デスクトップ ≫impress

  • Amazon WorkSpaces Application Manager (WAM)
    Amazon WorkSpaces端末にアプリを配信するツール ≫serverworks

  • AppStream 2.0
    Citrix XenAppみたいなやつ ≫Developers.IO

参考文献

AWS ドキュメント
https://aws.amazon.com/jp/documentation/

AWS re:Invent 2016 発表サービスを三行でまとめる
http://qiita.com/szk3/items/a642c62ef56eadd4a12c

続きを読む

ECSのチュートリアル – コンテナ運用を現実のものにする

皆さんこんにちは

以前にコンテナの何がいいのかを説明する資料を作りました。
「やっぱりコンテナ運用しか無いな」
「コンテナを使わざるを得ない」
「とりあえずdocker入れとけばいいや」
という声が聞こえてきそうです(幻聴)

一方で、コンテナで運用するとなると、新たなる監視体制が必要となります。
例えば、Dockerのコンテナが突然停止した場合、その状況を検知し、新しくコンテナを立ち上げる必要があります。
また、そもそもコンテナが乗っている環境をスケールする必要が出たりして、その場合は新しくスケールされた環境でもコンテナを立ち上げなければならないし、その設定をサーバに書かなければならないけど、そうなると結局コンテナが乗っているサーバがブラックボックス化したりするわけで、なんとかうまく回そうとすると、それなりに気を配ることが多くなってきます。

最近はlaradockを使用する開発者が増えてきた(ような気がする)ので、コンテナ運用で幸せになるためにECSを使ってみた記録をチュートリアル形式で再現しておきます。

え?備忘録?ははは

ECSとは

ECSはAWSが提供しているコンテナ運用サービスです。
ECSの概念のちょっとしたものは以前に書いたECSで困ったときに読むための俺的Q&Aに書いてありますが、今回はECSでたてるWEBサーバに絞って超かんたんなポンチ絵を作ってみました。

ecs.png

あまりややこしいところはなさそうですが、簡単に見ていきましょう。

クラスター、コンテナインスタンス

コンテナインスタンスはdockerのコンテナのホストになるインスタンスで、クラスターはこのコンテナインスタンスの群れ( オートスケーリンググループ )です。
コンテナインスタンスにはdockerとコンテナの状態を監視してこちらに伝えてくれるエージェントが入っています。
コンテナ運用時には、個々のインスタンスには興味が無いので、「クラスター」と一括りにしてしまいます。

タスク、ECR

タスクはアプリケーションのまとまりを一つ以上のコンテナ動作で定義します。
今回の例ではnginxを動かすコンテナとphp-fpmを動かすコンテナのふたつで、webサーバのタスクを定義していて、nginxが外部からのリクエストを受け付け、php-fpmに渡しています。
コンテナを定義するイメージはECRというAWSが提供しているプライベートなdockerイメージのレジストリから取得しています。

サービス

サービスは3つの仕事をします。
1つ目はタスクが現在必要とされている個数を保っているかを監視し、その数を下回っていた場合、タスクを立ち上げて必要数を保つことです。
2つ目は現在の負荷状況を鑑みて、タスクを増減させます。この設定はCloudWatchのアラーム機能と連携させます。
3つ目はtarget groupと立ち上がったタスクを紐付けることです。

また、タスクの配置を各AZに均等に配置したりと、よく気配りのきくやつです。

ALB、target group

ALBはロードバランサーです。昔のクラシックなELBと違って、間にtarget groupと言うものを設置して、細かくルーティングできるようになっています。
target groupは実際のサーバへの振り分けを実施し、ヘルスチェックもします。

今回はこれらを利用して簡単なWEBサーバを運用できる状況に持っていきましょう

コンテナの準備

とりあえずコンテナを作る

運用したくとも、そのもととなるコンテナイメージがないと何も始まりません。
そこで、例によってLaraDockを利用してlaravelアプリを作ってみましょう。
プロジェクトの作成はここを見てもらうとして(ダイマ)、LaraDockとほぼ同じ動作をしてもらうために、Dockerfileをコピーしちゃいましょう。

$ cp -r ../laradock/nginx ./
$ cp -r ../laradock/php-fpm ./

これでDockerfileと設定ファイルをコピーできます。

今回、コンテナの中は完全に固定化…つまり、スクリプトを内部に含ませてしまうため、各Dockerfileの後部に

COPY ./ /var/www/

これを追加しておきます
また、nginxのdefaultのコンフィグファイルも必要なので、nginxのDockerfileには

COPY nginx/sites/default.conf /etc/nginx/conf.d/

も追加しておきます。
なにはともあれ、イメージを作成してみましょう。

$ cp nginx/Dockerfile ./ && docker build -t niisan/nginx .
$ cp php-fpm/Dockerfile-70 ./Dockerfile && docker build -t niisan/php-fpm .

これでイメージが作られているので、試しにサーバを立ててみましょう。

$ docker run -d --name php-fpm niisan/php-fpm
$ docker run -d --link php-fpm:php-fpm -p 80:80  niisan/nginx
$ curl 127.0.0.1
<!DOCTYPE html>
<html lang="en">
    <head>
...

うまく動いているようです。

コンテナをアップロードする

次にECRにコンテナをアップロードするのですが、初めての場合、ちょっとビビります。
けばけばしいタイトルとともに「今すぐ始める」ボタンが登場し、その次のページで妙な選択肢を迫ってきます。

ECSを始めることを。。。強いられているんだ!

(こういうところ、あまり好きじゃないです)
ここではとりあえず、「Amazon ECR によりコンテナイメージをセキュアに保存する」だけを選択しておきます。
すると、リポジトリの作成用のウイザードが迫ってきます。

ECR

とりあえずリポジトリ名にnginxと入れて次のステップへ
今度はECRにイメージをアップロードする手順が出てきますので、この通りにやってみます。
前回の記事でも言及したように、ここだけはAWS CLIを使用する必要がありますので、頑張って入れておきましょう。

$ aws ecr get-login

これで出てくるログインコマンドをコマンドラインにコピーして実行すればログイン完了です。
既にイメージは作ってあるので、タグを張り替え、アップロードしましょう。

$ docker tag niisan/nginx:latest **************.ecr.ap-northeast-1.amazonaws.com/nginx:latest
$ docker push *****************.ecr.ap-northeast-1.amazonaws.com/nginx:latest

これで完了です。
手順ページの完了ボタンを押すと、いまアップロードしたイメージのレジストリができていることを確認できます。

そのまま、左のバーにあるリポジトリを選択し、同じようにphp-fpmもアップロードしてみましょう。
1分もかからず終わるでしょう。

ECR登録済み

デプロイ

タスクを定義する

コンテナのイメージもアップロードできたことですし、早速タスクを定義していきましょう。
と言っても、今回の場合、内容は異様なほど簡単ですんで、すぐに終わるでしょう。

タスクの名前は適当に決めていいと思います。(今回は webtest という名前にしました。)
早速コンテナを入れていきましょう。まずはphp-fpmから行きます。「コンテナを追加」ボタンを押すと次のモーダルが出てきます。

タスクを設定

php-fpmの設定はこれだけで十分でしょう。
次にnginxを設定します。基本的にはphp-fpmと同様にイメージと名前を設定するわけですが、二つほど、違う設定があります。

ポートフォワード

まずはポートの設定です。
nginxは外部から接続できなければならないので、ホストからポートフォワードするように設定しました。

内部リンク

もう一つはphp-fpmへのリンクです。
これで、タスクの定義は完了しました。

クラスターを作る

タスクを作ったので、こいつを動かしてみましょう。
こいつを動かすためには、動作環境が必要となりますが、それがクラスターです。
早速クラスターを作っていきましょう。

クラスターの作成

せこいですが、コンテナが動作するインスタンスは一番ちっちゃいやつを使います。
次にネットワーキングの設定ですが、これはデフォルトのvpcを使ってお茶を濁しておきます。

商用環境では独自のVPC使おう

では作成しましょう。

クラスター作成完了

クラスターが出来上がりました。

作ったクラスターを選択して、早速タスクを動かしてみましょう。
クラスター名を選択し、タスクタブからタスクの開始ボタンを押すと、動作するタスクを選択する画面になります。

タスクの実行

では動作してみましょう。
しばらくすると、次のような状態になっていると思います。

動いているっぽい

どうやら動いているようです。
ECSインスタンスからコンテナのホストになっているインスタンスを参照して、public dnsを調べましょう。
それをブラウザにはっつけると、Laravelのページが表示されます。
Webアプリのデプロイ完了
うまくいきました!

サービスを使う

とりあえずデプロイできて、動作も確認できました。
とはいえ、これを運用するのはまだまだ厳しいところです。

  • タスクが死んだ場合の復旧をどうすればいいのか
  • コンテナを更新したときのデプロイ方法はどうなるのか
  • コンテナのスケーリングはどうするのか

この辺をサービスに解決してもらうとしましょう。

タスクを停止してみる

とりあえず、タスクを停止します。クラスターのタスクタブで、先ほど動かしたタスクを落とします。
当然ですが、落としたタスクは復活したりしないので、この時点で先に動かしたWEBサーバはダウン状態となります。

イメージを更新する

これからロードバランサーを使用するに当たり、ヘルスチェック用のルーティングをします。
今回はlaravel5.4を使う(使っちゃってる)ので次のようなroutingを用意します。

routes/web.php
Route::get('/healthcheck', function () {
    return ['health'=>'ok'];
});

この状態で、Dockerのイメージビルドを再実行します。
コンテナを再度動かすと次のような挙動を示します。

$ docker run -d --name php-fpm niisan/php-fpm
$ docker run -d --link php-fpm:php-fpm -p 80:80  niisan/nginx
curl 127.0.0.1/healthcheck
{"health":"ok"}

これをECRに再アップロードしておきます。

タスクを更新する

次に、タスクを更新していきます。
タスクはバージョン管理されていて、タスクはの更新は正確には新しいリビジョンを作るということになります。

例えば、今動いているリビジョンのタスクを新しいリビジョンのタスクに置き換えることで、サーバを更新したことと同じ状況にできますし、いざ新しいリビジョンが障害を起こすようなものであった場合は古いリビジョンに戻してロールバックすることもできます。

タスク定義->webtestでタスク定義のリビジョン一覧が現れます。今は一個しか無いと思うので、それを選択し、新しいリビジョンの作成ボタンを押しましょう。
今回の変更はnginxのポートの部分になります。

ダイナミックポート

なんとホストポートが空欄になっていますが、これがダイナミックポートという仕組みになります。
これはコンテナインスタンスで開いているポートを選んで、nginxコンテナの80ポートに繋げる仕組みで、ALB + target groupと組み合わせるときに使用します。

ALBを用意する

ひとまずコンテナの調整はこの辺にしておいて、ロードバランサーの設定を始めましょう。
まず、サービス -> EC2 -> サイドバーのロードバランサーを選択し、ロードバランサーを作成ボタンを押しましょう。
ALBの設定
Application load balancer を選択して、次へを押すとロードバランサーの設定に移ります。
今回はデフォルトのVPCを使うので、名前以外は全部デフォルトで問題なしです。
サブネットも二つあると思うので、両方共チェックしておきましょう。
一応、プロトコルはHTTPにしておきましょう。
セキュリティの警告は、今回は別に秘密通信でもないので、必要ないです。

セキュリティブループの設定

セキュリティグループはとにかく設定しておきましょう。
覚えやすい名前にしておくと、後で便利かもしれません。

空のターゲットグループ

ターゲットの登録画面になりますが、今はターゲットがないので、そのまま次へで、作成を完了させます。
これで、とりあえずロードバランサーの作成が完了しました。

最後に、ロードバランサーのセキュリティグループからコンテナインスタンスのセキュリティグループへの通信経路を確保しておきましょう。
コンテナインスタンスのセキュリティグループ( EC2ContainerService-*** )のinboundを編集しておきましょう。

セキュリティグループの設定

ロードバランサーからのinboundで全てのtcpを選択しておきましょう。
ダイナミックポートを使うと、開いているポートを使うのでどのポートが割り当てられるかわかりません。

サービスの作成

ここまで来てようやくサービスの作成が初められます。
再びEC2 Container Serviceから先程作成したクラスターを選択し、サービスを選択します。
作成ボタンがあるので、これを押しましょう。
サービス作成
まず、タスクはWebtestを選ぶわけですが、ここではリビジョンを含めて指定することになります。
サービス名は・・・とりあえずタスクのファミリー名と同じにしています。
画面下部に行くとELBを設定するボタンがあるので押してみましょう。
スクリーンショット 2017-03-18 22.39.45.png
するとこんな画面になるので、さっき作ったALBを選択し、負荷分散用のコンテナがnginxで、ポートが0:80になっていることを確認したら、ELBへの追加ボタンを押しましょう
スクリーンショット 2017-03-18 22.41.36.png
するとこんな画面になるのでターゲットグループを先程追加したものに変更して保存を押しましょう。

すると、サービスにALBの情報が登録されるので、この状態でサービスを作成しましょう。

スクリーンショット 2017-03-18 23.41.08.png

クラスターの状態がこのようになれば、成功です。
あとは、ロードバランサーのDNSにアクセスして、
Webアプリのデプロイ完了
これが出れば成功です。

まとめ

実はこれ書き始めたのって随分と前なのですが、途中でコンテナ運用の何がいいのかを説明するための資料作りしていたら、時間が立ってしまったのです。
まあ、ECSって使ってみるとすごく楽で、更にスケーリングしたり、他のサービスと相乗りさせたりマイクロサービス化させたりがすごく簡単にできるのですが、Webアプリを動かすに当たっては、わりとハマりどころが多いので、一貫したチュートリアル形式のものを作ってみました。
特にハマりどころなのは、ALB -> コンテナインスタンスにおけるセキュリティグループの設定だと思います。
考えてみれば当たり前なのですが、まあ、忘れることが多いです。
とはいえ、そんなところを超えてしまえば、後はコンテナで簡単に運用できる環境を量産できるので、皆さん是非とも使ってみてください。

今回はそんなところです。

参考

コンテナに挫折したあなたへ – 超わかりやすい発表資料です!師匠と呼びたい

続きを読む