『Docker/Kubernetes 実践コンテナ開発入門』のサンプルアプリケーションをECSに載せる

この記事は PMOB Advent Calendar 11日目の記事です.

ECSの練習ということで,『Docker/Kubernetes 実践コンテナ開発入門』の4章 「Swarmによる実践的なアプリケーション構築」の構成を参考にECSに載せてみるということをやってみた.

  • tododb
  • todoapi
  • todonginx
  • todoweb

いずれもgihyodockerから入手できる.

gihyodocker · GitHub

これらをサンプルの通り環境変数を設定して,ECSでは5つのサービスを作った

  • dbmaster
  • dbslave
  • api
  • apinginx
  • web

構成

ECS自体に慣れるという目的もあったのでいくつか条件を決めて構築した.

  • Fargateは使わない
  • コンテナインスタンスを複数立てる
  • サービスディスカバリを使う

デプロイはdbmasterから順番に後ろの方から構築した.

ハマったところ

基本的にはSwarmのymlファイルの内容をタスク定義とサービスにそのまま移せば良いのだが,いくつか構築中にハマったところもあった.

サービスディスカバリ

まず最初にslaveからmasterに接続できないという事が起きた.

原因としてはこの行だった.

https://github.com/gihyodocker/tododb/blob/master/prepare.sh#L30

この行でデリミタを変更してしまい,後のmysqlに接続する部分で正しい変数展開が行われなかったためになる.

ECSでは名前空間をtodoapp,サービス名をdbmasterとすると,外部からアクセスするにはdbmaster.todoappと指定する必要がある.

つまり MYSQL_MASTER_HOST=dbmaster.todoappにすると,mysql -h $MYSQL_MASTER_HOST -u ~の部分が, mysql -h dbmaster todoapp -u ~ と展開され,名前解決に失敗しエラーになる.

ERROR 2005 (HY000): Unknown MySQL server host 'dbmaster' (0)

これを回避するには,デリミタを元に戻すかその後のMYSQL_MASTER_HOSTをダブルクォートで加工などの変更が必要.

IFSを元に戻す · cohalz/tododb@d2ce960 · GitHub

Swarmでは名前解決にサービス名だけで済むのでこの問題は当然起こらない.

セキュリティグループ

サービスを作成する際に,セキュリティグループを新規作成してくれるのだけれど,デフォルトでは80番ポートしか開けてくれないので,うっかりしてると全然繋がらないみたいなのが多発する.

あらかじめ内部の通信に関して緩めのセキュリティグループを作っておき,外部に向ける部分だけは厳しくという方針でやっていくと良いのかも知れない.

接続できるのかのデバッグ

見るところが多くて大変だった.

  • ECS,EC2,CloudWatch Logsそれぞれのコンソールを見る
  • 踏み台から疎通確認
  • dockerの中に入るのに手順が多い
    • ECSのコンソールから入りたいタスクを選ぶ
    • タスクからコンテナが置かれているホストを特定しssh
    • docker psしてそれっぽいプロセスを探す
    • docker exec

サービスを作った後変更できない部分が多い

これはサービスの構成を間違えてしまうと後から変更できないので作り直しになってしまう.

  • 「ネットワーク構成」の部分が変更できない
    • セキュリティグループやLB,サービスディスカバリなど

ENI上限

今回ネットワークモードはawsvpcを使った.

ECSのクラスタを作成する際にm4.largeがデフォルトで選択されているのだけれどこれが罠だった.

m4.largeはアタッチできるENIの上限が2になっていて,コンテナインスタンス自体のENIで1つ使っている.

つまり1つのインスタンスにつきコンテナを一つしか載せられないことになる.

今回インスタンスは4台にしていたので,5個目のコンテナを載せようとしたときに鳩の巣原理によってどこにも載せられなくなったのが発覚した.

これを解決するために,一つ上のm4.xlargeにした.(上限は4)

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-eni.html

ただ,インスタンスタイプを変更するのにもちょっと一手間が必要.

Auto Scaling Group と 起動設定

インスタンスタイプを変更するにはAuto Scaling Group と 起動設定を変更する必要がある.

m4.largeからm4.xlargeへ変更する際には,今までの起動設定からコピーしてインスタンスタイプの変更をした設定を作った.

基本的にはそれで良いけれど,何も考えずポチポチやると2つ変わってしまう

  • インスタンスプロファイルが「なし」にされている
    • 詳細設定の「IAM ロール」からecsInstanceRoleを選択して解決
  • ブロックデバイスが変わる
    • ブロックデバイスのルートが /dev/xvda になっていた

ECSのコンテナインスタンスを登録解除したあと,インスタンスを停止しないと新しいオートスケーリングが働かないことにも注意が必要.

起動設定やオートスケーリンググループを変えただけでインスタンスの入れ替えが起こるわけではない.

サービスを全部載せ替えると,起動の順番により失敗することもあるのでそこも注意が必要.

失敗したときの再実行に時間がかかることもあるので,今すぐ再実行させたいときはサービスの更新を行うことですぐに再実行できる.

タスクがログ吐かずに落ちる

色々いらないものを整理しているうちにnginxコンテナが何もエラー吐かずに落ち続けるようになった.

原因としては,ECRのリポジトリを何かの拍子に消していたことで,タスクの詳細からコンテナの覧を開くと,

CannotPullContainerError: API error (404): repository xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/todonginx not found というエラーが確認できた

これのように,ecsのログは全てログドライバに吐かれるわけではなく,タスクの情報に載っていることもある.

ECRのリポジトリを削除しても利用中というダイアログは出ないということにも注意が必要かもしれない.

感想

  • 『Docker/Kubernetes 実践コンテナ開発入門』は実際に手を動かして試せるサンプルがあるのでみんな読もう.
  • ECSやコンテナオーケストレーションにまだ慣れていないから時間が掛かった.
  • 別のオーケストレーションツールに載せ替えるというのはいい練習になると思う.