Edited at

AWS ECSでDockerコンテナ管理入門(基本的な使い方、Blue/Green Deployment、AutoScalingなどいろいろ試してみた)


はじめに

Dockerを本番環境で利用するに当たり、私レベルではDockerのクラスタを管理することはなかなか難しい訳です。凄くめんどくさそうだし。

ということでAWS ECS(EC2 Container Service)ですよ。

記事書くまでも無いかなと思ったんですけど意外と手順がWEBにない(気がしました)。ということで、今回は社内でハンズオンでもやろうかと思って細かく書いてみました。

こんな感じのシナリオをやってみたいと思います。


  1. Dockerのイメージを用意する

  2. ECSの使い方の基本

  3. コンテナのリリース

  4. Blue/Green Deployment

  5. AutoScaling/ScaleIn



前準備:Dockerのイメージを用意する


  • DockerhHub上にpush済ですので、下記手順は飛ばしても構いません。


  • OracleJDKが入っているDockerImageを取得し、SpringBootで作ったこちらのアプリが動くDockerImageを用意してみます。

  • jarファイルはJava8が入っている環境であれば↓2行でできます。

$ git clone https://github.com/uzresk/springboot-doma2.git

$ mvnw package


  • Dockerfile

FROM uzresk/docker-oracle-jdk

MAINTAINER uzresk

ADD demo-1.0.jar /root/demo-1.0.jar
CMD java -jar /root/demo-1.0.jar


  • Docker build

[root@centos7 build_demo_ver1.0]# docker build -t uzresk/demo:ver1.0 /vagrant/build_demo_ver1.0

Sending build context to Docker daemon 33.11 MB
Step 1 : FROM uzresk/docker-oracle-jdk
---> df2f575c2a0d
Step 2 : MAINTAINER uzresk
---> Using cache
---> 1995a4e99748
Step 3 : ADD demo-1.0.jar /root/demo-1.0.jar
---> 705df0209779
Removing intermediate container cd9ef33d8812
Step 4 : CMD java -jar /root/demo-1.0.jar
---> Running in b7bd939a8b5a
---> add0783a851f
Removing intermediate container b7bd939a8b5a
Successfully built add0783a851f


  • 起動します


    • アプリケーションは8080で起動しているのでポートフォワードしておきます。



[root@centos7 build_demo_ver1.0]# docker run -itd -p 80:8080 --name demo uzresk/demo:ver1.0

92bda2419bf7285d78f12be5877ae3242b5b13ac14409b3c47d38e2d74a06464


  • ブラウザでこんな画面がでれば成功です。

image


  • Dockerhubにコミットしてpushしておきます。

[root@centos7 build_demo_ver1.0]# docker commit -m "update ver1.0" demo uzresk/demo:ver1.0

[root@centos7 build_demo_ver1.0]# docker push uzresk/demo:ver1.0



ECSの使い方の基本


AWS ECSとはなんなのか?


  • 今回は利用手順について書こうと思うので割愛しますが、AWS Black Belt ECSを読むのがよろしいかと思います。


構成する順番を抑えよう


  • こんな感じの順番で構成していきます。大事なので押さえておきましょう。



  1. クラスタの作成


    • クラスタを動かすためのEC2インスタンスの設定を行います。具体的にはインスタンスタイプ、インスタンス数、VPC、サブネットの設定になります。




  2. タスク定義


    • クラスタ上で動かすコンテナの情報を登録します。コンテナイメージのURLやCPU、メモリのハード/ソフト制限、アプリケーションで利用する環境変数の定義などを行います。




  3. ロードバランサの作成


    • クラスタの上位に位置するロードバランサの設定を行います。スケールアウトやスケールインしてもロードバランサはサービスを見つけ出し配下に組み込むことができます。




  4. サービスの作成


    • クラスタとサービスを結びつけるのがサービスの役割です。タスクの最少数やAutoScalingの設定を行ったりできます。

    • 1つのクラスタに複数サービスを登録することももちろん可能です。



それではさっそくクラスタの作成からやってみましょう。


クラスタの作成

image

image


  • 正常に作成されると「クラスターの表示」ボタンが押せるようになります。

image


タスク定義


  • 次はタスクの定義です。タスクでは

image


  • タスク定義名を入力し、「コンテナの追加」をクリックします。

image

image


  • 作成を押せばタスク定義の作成が完了します。


ELBの作成



  • ELBは以下の設定で作っておきましょう


    • ELB名:app-demo-lb

    • 種類:アプリケーションロードバランサ

    • 2つのAZそれぞれのSubnetを指定

    • セキュリティグループで80/HTTPを通すように設定



  • ターゲットグループは以下のようにクラスタで設定したインスタンスIDをそれぞれ登録してください。


image


サービスの作成


  • クラスターのTOPからdemo-clusterを選択し、サービスタブで「作成」

image


  • タスク定義とクラスタ名は自動で埋まりますので、サービス名とタスクの数を設定します。

  • 今回はAZにそれぞれコンテナを作りたいので2としました。

image


  • 画面の下の方にあるELBの追加を選択します。

image


  • ELB名は作成したもの、リスナーポートは80、ターゲットグループ名は作成したものを選択します。

image

image


  • 「作成」を押して、サービスの画面をみるとPENDINGになっています。

image


  • 少し経つとRUNNINGになっている事が確認できると思います。

image


  • ELBのエンドポイント/app/をブラウザで叩くと画面が表示されるはずです。

image


コンテナを落としてみるとどうなるのか


  • タスクの一覧から、タスクを一つ消してみましょう。

image


  • 数十秒後に見てみると別のタスクIDのインスタンスが表示されているはずです。

image


  • コンテナが起動する数十秒間の間はアプリケーションロードバランサが生きているタスクの方にうまくルーティングしてくれるのかな?と思ったら「502BadGateway」というエラーが画面に返ってきました。

  • ここはALBのヘルスチェックの閾値を短くすることである程度は短くできそうです。

  • ここをさらに短くするには、コンテナ自体を軽くすることと、すぐに起動できるアプリケーションを利用するしかなさそうですね。



コンテナのリリース


  • 新しいコンテナをリリースするには、タスク定義に新しいリビジョンを登録し、サービスを更新することで実現可能です。さっそくやってみましょう。

image


  • コンテナのバージョンを2.0にして、新しいリビジョンを登録します。

image


  • 追加されたリビジョンを選択し、アクション→サービスの更新を押します。

image


  • タスク定義に新しいリビジョンが指定されていることを確認して、「サービスの更新」

image


  • サービスの「デプロイ」タブを覗くと、今はVer1.0が2つ動いていることが確認できます。

image


  • コンテナを一つ落としてみましょう

image

image


  • 実行中の数がそれぞれ1になり、タスクの一覧からもそれぞれが動いていることがわかりますね。
    image

image



Blue/Green Deployment


  • Blue/GreenDeploymentでは新しいリビジョンのアプリ用に、新しいインスタンスを構築して入れ替える必要があります。

  • この為のパラメータがサービスのデプロイメントオプションにある最大率(maximumPercent)です。2台の時にこの値を200%にしておくと、4台まで同時に動かしておくことができることを意味します。

  • 4台のインスタンス上で動かすにはECSのインスタンス台数を事前に追加しておくか、AutoScalingさせておく必要があります。もしECSインスタンスが2台の状態で4つのコンテナを動かそうとすると以下のようなメッセージがでてしまいます。(ポートかぶってるから上がらないよ。ってことですね)


  • さっそくやってみます


image

image


  • この状態でサービスの更新画面でタスク定義を新しいリビジョンに指定して「サービスの更新」を押してみます。

  • おお。4台分のコンテナが起動しましたね。

image


  • ちょっと経つと(3分ほど?)、古いタスクから削除されていきます・・・・

image


  • 最期は新しいタスク定義しか残らなくなりました。自動ですよ。自動。便利ですねー。

image



Blue/Green Deployment(動的ポートマッピング)


  • さきほどは4台のサーバを起動して2台を入れ替える方法を試してみましたが今度は2台を徐々に入れ替える方法です。

  • まずは新たにver1.0のタスク定義を追加してみます。この時にホストのポートを空にして登録してください。

image

image


  • 2台のECSインスタンスを起動して、リビジョン番号3を起動しておきます

image


  • ALBで利用するターゲットグループには対象のインスタンスを登録しないでくださいAWSがコンテナ自動でAWSが見つけてくれます。

image


  • デプロイしてみます。サービスの設定を開いてタスク定義で[demo-app-task:4]、最大率を200に設定します。

image


  • 最大率を200にすることで合計で4台同時に起動することができるようになります。4台同時に起動できるのはAWSが勝手にポートをかぶらないように設定してくれるからです。

image


  • 少し経つと勝手にdemo-app-task:3は消えていきます

image



AutoScaling/ScaleIn


  • 次はオートスケールとスケールインを試してみます。

  • 通常のオートスケールではインスタンスだけでしたが、インスタンス上で動くコンテナもスケールする必要があります。

  • 今回は2つのインスタンスで2つのコンテナで動いていたものを、負荷をかけることにより4つのインスタンス上に4つのコンテナにスケールアウトさせて、スケールインさせたいと思います。


サービスのAutoScaling設定


  • タスクの最大数を4にして、スケーリングポリシーの追加を押します。

image


  • スケールアウトポリシーの設定を行います。

  • CPU使用率の1分間の平均が20%超えた場合2タスクスケールアウトする設定にしました。

image


  • スケールインポリシーの設定を行います。

image


  • ポリシーが追加できたら「保存」を押しましょう

image


  • ポリシーが追加されていることを確認して、「サービスの更新」を押します。

image


  • これでサービスの設定はおしまいです。


ClusterのAutoScaling/ScaleInの設定


  • ECSインスタンスのオートスケールのポリシーは、EC2インスタンスのAutoScalingGroupの設定で行います。

  • 最大数を4にします。

image


  • Scaleout/ScaleInのポリシーを設定します。

  • サービスの設定と同じく、クラスタのCPU使用率が20%以上だと2台スケールアウトするように設定しました。

image


うごかしてみる


  • ECSインスタンス上でCPU使用率を強引に(openssl speed -multi 1)あげてみたのですがうまく動きませんでした。

  • ありがちですけどabで負荷をかけてみます。

  • abをインストール

sudo yum install -y httpd24-tools


  • 負荷をかける

ab -n 100000 -c 100 http://localhost/app/loginForm


  • CloudWatch Alerm(CPUが20%以上)があがる

image


  • サービスの必要数が4に変更される

image


  • インスタンスがオートスケールする

image


  • タスクが起動する

image


  • 負荷を解除する


  • CloudWatch Alerm(CPUが20%より小さい)があがる


image


  • 必要数が2に変更される

image


  • コンテナとインスタンスが2ずつに変わる


  • ここまでやって思ったんですが、インスタンス→コンテナの順に起動されたんですからコンテナ→インスタンスの順に落としていった方がよさそうですね。それはスケーリングポリシーのクールダウン時間で調整ができそうです。



ECSインスタンスの起動を待つのか?


  • ECSのインスタンスの起動を行った後にコンテナが起動されるので結局時間が掛かってしまいます。負荷の時間が予測されるのであればECSインスタンスを事前に起動しておいた方がECSのスケールアウトが高速にできそうです。

  • Dockerのメリットの一つである起動の高速化のメリットを享受するにはこのスケジューリングがキーになりそうですね。


どのインスタンスがスケールインするのか?



さいごに

ここまでコンテナ管理のハードルが下がると、今後はアプリケーションをコンテナにして配布するのが普通になってくると思います。

そうなるときのためにDockerについてしっかりと理解し、良い設計を心がけたいものですね