[Java][ECS] Deploy JBot Application for Amazon ECS

java

はじめに

前回の続きです。前回Docker Imageが作成できたのでECSでコンテナを作成し、Webアプリケーションとして公開します。

ECSを使ってWebアプリケーションを公開する

このあたりの記事を参考にさせていただきました。やっていきましょう。

事前準備

前回起動した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 とします。

スクリーンショット_2017-02-19_20_40_40

リポジトリは、AWSのAccountIDの下に各リポジトリが配置されるようです。

スクリーンショット_2017-02-19_20_40_55

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が表示されます。

スクリーンショット_2017-02-28_19_14_27

これら一連の操作は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を作成していくのでしばらく待ちましょう。

スクリーンショット_2017-02-19_20_31_51

タスクを定義する

ECSでコンテナを実行するためのタスク定義を行います。先程PushしたリポジトリのDocker Imageを指定します。

スクリーンショット 2017-02-28 19.23.02

適当なタスク名を作成します。

特に他のAWSサービスへアクセスするようなものはないので、ロールはなし。ネットワークも特別何かをするわけではないのでBridgeのまま。こちらでOKです。

コンテナの追加 を押すと右の方からペインがにょきっと出てきます。

スクリーンショット 2017-02-28 19.24.25

コンテナ名を適当につけました。イメージはさきほどアップロードしたECRのイメージをフルパスで指定します。最新版を使ってほしいので、最後に :latest を付与しています。メモリ制限はこんなに使うことはないと思いますが、とりあえずハード制限で512MB。

ポートマッピングは、Dockerコンテナはインスタンス内でどのポートで稼働するかがよく分かりません。そのため、ホストポートを 空欄(実際は0) にしておくと後で自動でポートが割当たった時に補完してくれるようです。コンテナポートはJbotが受け付けている ポート8080 を指定します。

コンテナの詳細設定に関しては全くいじっていません。作成を押すとタスク定義の作成が完了します。

スクリーンショット 2017-02-28 22.22.03

ALBを作成する

ECSでWebサービスを公開する場合、ALBに紐付けます。事前に準備しておきます。

スクリーンショット 2017-02-21 17.08.45

EC2 > ロードバランサー からロードバランサーの作成。ALBを選択します。ECSのクラスターインスタンスを作成したVPCと同じものを選択して作成します。この段階でターゲットグループも作っておきます。

スクリーンショット 2017-02-21 17.11.53

ターゲットグループを作成する際に、すでに起動しているクラスターインスタンスを紐付けることもできますが、ここはスキップしておきます。特に何も紐付ける必要はありません。

スクリーンショット 2017-02-21 17.23.12

Security Groupのインバウンド設定は80番ポートをフルオープンで設定しました。

サービスを作成する

ここまで色々と準備してきましたが、そろそろコンテナを立ち上げましょう。Amazon ECS > クラスター を選択し、先程作成したクラスターのリンクを選択しましょう。

スクリーンショット 2017-02-21 17.26.32

サービスタブが見えるので、作成を押します。

スクリーンショット 2017-02-28 22.37.48

以下のパラメータで作成しました

パラメータ名
タスク定義 【作成したタスク定義:revision】
クラスター 【作成したクラスター】
サービス名 jbot-sample-app-service
タスクの数 1
最小ヘルス数 50(default)
最大率 200(default)

スクリーンショット 2017-02-21 17.28.38

タスク定義でポートマッピングの設定を行っていたので ELBの設定 が有効になっています。ELBの紐付けを行いましょう。

スクリーンショット 2017-02-28 22.38.11

ELB名 には先程作成したALBを指定します。コンテナの選択で jbot-sample-container:0:8080 を選択し、ELBへの追加 をクリック。

スクリーンショット 2017-02-28 22.38.29

ターゲットグループの設定が出てきます。先程ALBと同時に作成したターゲットグループを選択します。ヘルスチェックのパスやポート設定などが自動的に選択されます。最後に一番下の 保存 を忘れずに押しておきます。

準備が整ったので 作成 をクリックすると、サービスの作成が開始されます。コンテナが立ち上がっていきます。

スクリーンショット 2017-02-28 22.49.11

これでECSでコンテナの起動まで完了しました。お疲れさまでした。

ヘルスチェックの確認

ヘルチェックが通っているかを確認します。 EC2 > ロードバランサー からターゲットグループを選択します。クラシックELBの場合は、ヘルスチェックはロードバランサーから見えたのですが、ALBを選択した場合はターゲットグループにヘルスチェックのステータスが表示されています。コンテナが立ち上がりきってなかったりしている場合は initial と表示されているのでしばし待ちましょう。

スクリーンショット_2017-02-28_22_52_06

unhealthyとなった場合

何度もやってもunhealthyとなってしまう場合、以下のような原因が考えられます。

  1. コンテナが立ち上がってない
  2. コンテナ内部のアプリケーションが正常に動いていない
  3. コンテナとホストインスタンスとのポートマッピングがうまくいっていない
  4. ホストインスタンスが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番設定で解決していましました。

スクリーンショット_2017-03-01_12_28_28

起動確認

全て正常に起動していれば、前回Slackに登録した jbot-sample がログイン状態になっています。これで、BotアプリケーションをECSで起動することができました。次回はSlash Commandについて検証します。

スクリーンショット 2017-03-01 12.26.31

スクリーンショット 2017-03-01 12.26.52