今日は「AWS Fargate Advent Calendar 2017」23日目の記事として,Fargate を試した感想と,デプロイツールの ecs-deploy で Fargate にデプロイできるようにする話を書いてみたいと思う.アドベントカレンダーの記事はどれも本当に素晴らしくて,Fargate 最高!という空気感が伝わってくる.東京リージョンでも使いたいなぁー!
今までの ECS を振り返る
既に本番環境で複数の ECS クラスタを運用していて,スケーラビリティ/運用のしやすさ/可搬性など,様々なメリットは感じているけど,やはりコンテナインスタンスを意識して設計する必要があった.
例えば,デプロイ戦略で言えば Minimum Healthy Percent
と Maximum Percent
を考える必要があり,デプロイ時に Desired Count
のキャパシティをどの程度維持するかを考える.例えば Maximum Percent
を 200%
にする場合は,一時的に Desired Count
の2倍までスケールするため,そのリソースを配置できるコンテナインスタンスを用意する必要がある.実際にはそこまで厳格に計算せず,余裕を持ったコンテナインスタンスを稼働させていることが多かった.
また,ECS でオートスケーリングを実現する場合,コンテナインスタンスに対する「オートスケーリング」と,タスクに対する「サービスオートスケーリング」を気にする必要がある.以下のように設定して運用していたりもするけど,実際に負荷テストをしてみると,データストア側が詰まって別のボトルネックが見つかったり,アーキテクチャ的に別のトリガーでオートスケーリングをした方が適切な場面もあったりした.このあたりはじっくり考える必要があり,AWS に詳しくないメンバーに「難しい...」と言われたこともあった.
- 例 :「オートスケーリング」の場合
- ECS クラスタの
CPUReservation
を監視して,クラスタ全体の CPU ユニットの量でスケールさせる
- ECS クラスタの
- 例 :「サービスオートスケーリング」の場合
- ECS クラスタの中に複数のサービスを乗せることもあるため,サービス全体の
CPUUtilization
を監視して,タスクをスケールさせる
- ECS クラスタの中に複数のサービスを乗せることもあるため,サービス全体の
また,コンテナ内部のモニタリングをする方法も悩んだ.他のチームが積極的に Datadog に乗り換えていく中,Mackerel でモニタリングをしようと試みていて,完全にワークアラウンドのような仕組みだけど,問題なく動くようになり,今もこの仕組みを使っている.けど,コンテナインスタンスに Mackerel Agent をインストールするため,今後コンテナ部分はやはり Datadog への移行を検討するかもしれない.
Fargate に対する期待と試した感想
このような現在の背景を考えると,コンテナインスタンスの管理をせず,コンテナにフォーカスして運用できるというのは非常にメリットになる.オートスケーリングの面でも,サービスオートスケーリングのことだけを考えれば良くなるのも嬉しい.現在は us-east-1 でしか使えないけど,さっそく Fargate を試した.既に詳しい記事がたくさん上がっているけど,自分のメモを兼ねて書いてみる.なお,Fargate の紹介記事は公式からも出ている.
cpu / memory
今までの ECS だと任意設定だったタスク定義の cpu / memory が Fargate では必須になる違いがある.また,自由に設定できず,決まった組み合わせの中から選ぶ形になる.詳しくはドキュメントに書いてあるけど,このあたりの変更点は頭に入れておいた方が良さそうだなと思った.
- 256 (.25 vCPU) - Available memory values: 512MB, 1GB, 2GB
- 512 (.5 vCPU) - Available memory values: 1GB, 2GB, 3GB, 4GB
- 1024 (1 vCPU) - Available memory values: 2GB, 3GB, 4GB, 5GB, 6GB, 7GB, 8GB
- 2048 (2 vCPU) - Available memory values: Between 4GB and 16GB in 1GB increments
- 4096 (4 vCPU) - Available memory values: Between 8GB and 30GB in 1GB increments
ネットワークモード awsvpc
今までの ECS だと,ネットワークモードはデフォルトの bridge
を使っていて,コンテナインスタンスと同じネットワークで外部にアクセスするような構成になっていたけど,Fargate では awsvpc
が必須となる.awsvpc
ネットワークモードというのは,コンテナ自体が ENI を持って,自律的に外部にアクセスできるようになる構成で,以下の記事で詳しく解説されている.Fargate では,コンテナインスタンスを意識しないため,当然ネットワークの部分を考慮する必要があり,それがコンテナのレイヤーに上がってきたというイメージになる.合わせて,セキュリティグループもコンテナに付けられるようになるというメリットもある.ただし,ENI を持つということは,サブネットの IP が枯渇する可能性があり,そのあたりは VPC 設計からやり直さないとダメな場合もありそう.
Auto-assign public IP
Fargate というか,ネットワークモード awsvpc
の場合は,コンテナにパブリック IP を設定することもできる.ECS サービスを作成するときに Auto-assign public IP の設定を選ぶことができる.試しに Enabled にして起動してみると,ALB のターゲットグループでパブリック IP が設定されていることを確認できた.もしくは NAT Gateway を経由して外部ネットワークにアクセスすることもできる.なお,Fargate ではターゲットグループの接続タイプが instance
から ip
に変わるので,ここもちゃんと理解しておく必要がある.
課金体系
Fargate の課金体系は「使っただけ」となり,以下の簡単な計算式になっている.あまりリクエスト数が多くなく,処理速度も早ければ,コスト削減に繋がると思うけど,逆にコンテナインスタンスを上げっぱなしにしておいた方がコスト削減になるパターンもあるとは思う.とは言え,コンテナインスタンスの運用コストを考慮すると,やはり Fargate の方が良いなと思うし,そもそもコスト削減を目的に Fargate に移行することはあまりなさそう.それなら SpotFleet で高めに買っても全然コスト削減になるような気がする.
Price per vCPU is $0.00001406 per second ($0.0506 per hour) and per GB memory is $0.00000353 per second ($0.0127 per hour).
アドベントカレンダーでも,課金体系にフォーカスした記事があり,非常に参考になった.
ecs-deploy の Fargate 対応
さて,やっと本題に入る.ECS のデプロイツールはいろいろと乱立していて,CloudFormation や ecs-cli や ecs-deploy がある.僕が運用している環境では ecs-deploy を採用しているので,定期的に GitHub をウォッチしているんだけど,re:Invent の直後に「Fargate 対応よろしく!」という Issue が出ていて,そのまま放置されていたので,これに挑戦することにした.
確かに,master ブランチにある ecs-deploy で実行したら,以下のエラーが出た.
An error occurred (InvalidParameterException) when calling the UpdateService operation: Task definition does not support launch_type FARGATE.
タスク定義の差分を調べる
ecs-deploy の仕組み上,タスク定義の JSON を jq でゴニョゴニョする感じになっているため,まずはタスク定義の差分を調べることにした.アドベントカレンダーの中に Terraform を使って定義の差分を紐解く記事があり,この記事がとにかく参考になった.実際にタスク定義の JSON を比較してみたら,確かにその通りの差分を確認することができた.
主な差分は executionRoleArn
/ requiresCompatibilities
/ networkMode
/ memory
/ cpu
あたりになる.
{ "executionRoleArn": "arn:aws:iam::111111111111:role/ecsTaskExecutionRole", "containerDefinitions": [ { (中略) } ], "placementConstraints": [], "memory": "512", "compatibilities": [ "EC2", "FARGATE" ], (中略) "requiresCompatibilities": [ "FARGATE" ], "networkMode": "awsvpc", "cpu": "256", (中略) }
ecs-deploy の createNewTaskDefJson()
を修正する
あとは jq でゴニョゴニョするだけなので,タスク定義の requiresCompatibilities
の値で Fargate 判定をして,Fargate の場合,必要なパラメータを追加でフィルタするとうまく動くようになる.さらに従来のタスク定義には requiresCompatibilities
のキーが存在しない場合があるらしく,jq の select
を使って対応した.プルリクも出したけど,一部の環境でエラーになるとレポートがあり(ただし僕の環境だと再現しない),まだ Merge してもらうところまでは進められてない.
実行イメージ
特に Fargete 用のオプションなどは必要なく,タスク定義から自動判定されるので,今まで通りのコマンドで実行できる.
$ ./ecs-deploy --region us-east-1 --cluster my-fargate-cluster --service-name my-fargate-service --image 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/goapi:10 New task definition: arn:aws:ecs:us-east-1:111111111111:task-definition/goapi:10 Service updated successfully, new task definition running. Waiting for service deployment to complete... Service deployment successful.
まとめ
- 今までの ECS を振り返った
- Fargate を実際に試して,ポイントとなる仕様などを調べた
- デプロイツールの ecs-deploy で Fargete にデプロイできるようにプルリクを送った
Black Belt