[Java][ECS] Deploy JBot Application for Amazon ECS
はじめに
前回の続きです。前回Docker Imageが作成できたのでECSでコンテナを作成し、Webアプリケーションとして公開します。
ECSを使ってWebアプリケーションを公開する
このあたりの記事を参考にさせていただきました。やっていきましょう。
- 【短期企画】触ったことのないAWSサービスを触っていくぞ -ECS編-
- Amazon EC2 Container Serviceで構築されたシステムでDockerコンテナを入れ替える
- Dockerコンテナの作成からECSの動的ポート+ALBでロードバランスするまで【cloudpack大阪ブログ】
事前準備
前回起動したDockerは停止しておいてください。
AWSでWebアプリケーションを公開する際にヘルスチェックとして確認できる口を用意しておく必要があります。前回まで使っていたJbot-sampleにはヘルスチェックとして叩けるパスがないようです。ヘルスチェックで叩ける口を準備しておきましょう。JbotApplication.java
と同列に以下のようなControllerを追記しておきます。
/** * health */ @RestController @RequestMapping("health") public class HealthController { @RequestMapping(method = RequestMethod.GET) public String health() { return "I am jbot"; } }
http://localhost:8080/health
でアクセスすることができるようにしておきました。こちらをhealthチェックに利用します。
リポジトリを作成する
Dockerのイメージを管理するリポジトリを作成します。Amazon ECSのサービスメニューからリポジトリを選択します。
リポジトリ名は jbot-example とします。
リポジトリは、AWSのAccountIDの下に各リポジトリが配置されるようです。
ECRにログインしてImageをPushまで
指定されたコマンドをそのまま実行しましょう。適切なRoleが設定されていれば長大なDockerコマンドが出力されます。
$ aws ecr get-login --region us-east-1 docker login -u AWS -p Axxxxxxug4= -e none https://xxxxxxxx.dkr.ecr.us-east-1.amazonaws.com
docker loginを実行する
先程出力されたコマンドをそのまま実行します。 Login Succeeded
と表示されていればOKです。
xxxxxx.dkr.ecr.us-east-1.amazonaws.com Flag --email has been deprecated, will be removed in 1.14. Login Succeeded
Docker Imageを作成してPush
Docker Imageを作成してタグを付与します。
$ docker build -t jbot-example . ~~~ $ docker tag jbot-example:latest xxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/jbot-example:latest
タグを付与したらPushの準備は完了。
$ docker push xxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/jbot-example:latest
Pushが完了するとECRにImageが表示されます。
これら一連の操作はImageをアップデートする際に毎度実行するので流れを覚えておくと良いかもしれません(僕は毎度コマンドリファレンスを見てますが)
権限がない場合
以下のようなエラーが出力されます。IAMユーザー、Roleなどを確認してください。プロファイルが設定されている場合は、他のAWS CLIコマンドと同じく --profile
指定でプロファイルが指定できますので適宜確認ください。
$ aws ecr get-login --region us-east-1 An error occurred (UnrecognizedClientException) when calling the GetAuthorizationToken operation: The security token included in the request is invalid.
クラスターを作成する
クラスターを作成します。以下のパラメータで作成します。
パラメータ名 | 値 |
---|---|
クラスター名 | jbot-cluster |
EC2 インスタンスタイプ | t2.small |
インスタンス数 | 1 |
EBS ストレージ (GiB) | 22GB |
キーペア | <作成したprivate key>を指定 ※1 |
ネットワーキング設定は全てデフォルトで新しいVPC設定を作成しました。初めて作成する場合は、コンテナインスタンスIAMロールが存在しないと思います。その場合、新しいロールの作成 を選択します。すでに作成されてる場合はそちらを選べば良いようです。
作成を押すとResourceの作成が実行されます。CloudFormationがResourceを作成していくのでしばらく待ちましょう。
タスクを定義する
ECSでコンテナを実行するためのタスク定義を行います。先程PushしたリポジトリのDocker Imageを指定します。
適当なタスク名を作成します。
特に他のAWSサービスへアクセスするようなものはないので、ロールはなし。ネットワークも特別何かをするわけではないのでBridgeのまま。こちらでOKです。
コンテナの追加 を押すと右の方からペインがにょきっと出てきます。
コンテナ名を適当につけました。イメージはさきほどアップロードしたECRのイメージをフルパスで指定します。最新版を使ってほしいので、最後に :latest
を付与しています。メモリ制限はこんなに使うことはないと思いますが、とりあえずハード制限で512MB。
ポートマッピングは、Dockerコンテナはインスタンス内でどのポートで稼働するかがよく分かりません。そのため、ホストポートを 空欄(実際は0) にしておくと後で自動でポートが割当たった時に補完してくれるようです。コンテナポートはJbotが受け付けている ポート8080 を指定します。
コンテナの詳細設定に関しては全くいじっていません。作成を押すとタスク定義の作成が完了します。
ALBを作成する
ECSでWebサービスを公開する場合、ALBに紐付けます。事前に準備しておきます。
EC2 > ロードバランサー からロードバランサーの作成。ALBを選択します。ECSのクラスターインスタンスを作成したVPCと同じものを選択して作成します。この段階でターゲットグループも作っておきます。
ターゲットグループを作成する際に、すでに起動しているクラスターインスタンスを紐付けることもできますが、ここはスキップしておきます。特に何も紐付ける必要はありません。
Security Groupのインバウンド設定は80番ポートをフルオープンで設定しました。
サービスを作成する
ここまで色々と準備してきましたが、そろそろコンテナを立ち上げましょう。Amazon ECS > クラスター を選択し、先程作成したクラスターのリンクを選択しましょう。
サービスタブが見えるので、作成を押します。
以下のパラメータで作成しました
パラメータ名 | 値 |
---|---|
タスク定義 | 【作成したタスク定義:revision】 |
クラスター | 【作成したクラスター】 |
サービス名 | jbot-sample-app-service |
タスクの数 | 1 |
最小ヘルス数 | 50(default) |
最大率 | 200(default) |
タスク定義でポートマッピングの設定を行っていたので ELBの設定 が有効になっています。ELBの紐付けを行いましょう。
ELB名 には先程作成したALBを指定します。コンテナの選択で jbot-sample-container:0:8080
を選択し、ELBへの追加 をクリック。
ターゲットグループの設定が出てきます。先程ALBと同時に作成したターゲットグループを選択します。ヘルスチェックのパスやポート設定などが自動的に選択されます。最後に一番下の 保存 を忘れずに押しておきます。
準備が整ったので 作成 をクリックすると、サービスの作成が開始されます。コンテナが立ち上がっていきます。
これでECSでコンテナの起動まで完了しました。お疲れさまでした。
ヘルスチェックの確認
ヘルチェックが通っているかを確認します。 EC2 > ロードバランサー からターゲットグループを選択します。クラシックELBの場合は、ヘルスチェックはロードバランサーから見えたのですが、ALBを選択した場合はターゲットグループにヘルスチェックのステータスが表示されています。コンテナが立ち上がりきってなかったりしている場合は initial と表示されているのでしばし待ちましょう。
unhealthyとなった場合
何度もやってもunhealthyとなってしまう場合、以下のような原因が考えられます。
- コンテナが立ち上がってない
- コンテナ内部のアプリケーションが正常に動いていない
- コンテナとホストインスタンスとのポートマッピングがうまくいっていない
- ホストインスタンスが80番ポートのインバウンドを許可していない
1, 2, 3の場合
コンテナの状況を確認してみると良いかもしれません。ホストインスタンスにSSH(22)でアクセスできるSecurityGroupを付与する必要があります。ホストインスタンスにSSHでログインし、インスタンス内でdockerコマンドを実行すると原因が分かる可能性があります。 docker ps
で稼働しているコンテナの状況を把握できます。正常に動作している場合は以下のような表示になっていると思います。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1a9eb1855eaf xxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/jbot-example "sh -c 'java -jar /op" 40 hours ago Up 40 hours 0.0.0.0:32768->8080/tcp ecs-jbot-sample-task-3-jbot-sample-container-adaefabvfadfadcdf01 696ce988b9e5 amazon/amazon-ecs-agent:latest "/agent" 40 hours ago Up 40 hours ecs-agent
4の場合
自分は4に遭遇しました。ホストインスタンスに80番ポートのインバウンドが許可されていないため、ALBからのヘルスチェックに失敗していました。
手っ取り早い解決方法は、インバウンドで80番ポートを全IPから許可するSecurityGroupを新たに作成し、ホストインスタンスへ割り当ててしまう方法です。若干強引ではあるかと思ったのですが、VPCはインターネットゲートウェイ等は紐付いておらず、外側からEC2が直接見られる可能性はなさそうなので、SecurityGroupを使ってフルオープン80番設定で解決していましました。
起動確認
全て正常に起動していれば、前回Slackに登録した jbot-sample
がログイン状態になっています。これで、BotアプリケーションをECSで起動することができました。次回はSlash Commandについて検証します。