kakakakakku blog

Weekly Tech Blog : Keep on Learning 👍

Fargate を試した感想と ecs-deploy で Fargate にデプロイできるようにする話

f:id:kakku22:20171223125406p:plain

今日は「AWS Fargate Advent Calendar 2017」23日目の記事として,Fargate を試した感想と,デプロイツールの ecs-deploy で Fargate にデプロイできるようにする話を書いてみたいと思う.アドベントカレンダーの記事はどれも本当に素晴らしくて,Fargate 最高!という空気感が伝わってくる.東京リージョンでも使いたいなぁー!

qiita.com

今までの ECS を振り返る

既に本番環境で複数の ECS クラスタを運用していて,スケーラビリティ/運用のしやすさ/可搬性など,様々なメリットは感じているけど,やはりコンテナインスタンスを意識して設計する必要があった.

例えば,デプロイ戦略で言えば Minimum Healthy PercentMaximum Percent を考える必要があり,デプロイ時に Desired Count のキャパシティをどの程度維持するかを考える.例えば Maximum Percent200% にする場合は,一時的に Desired Count の2倍までスケールするため,そのリソースを配置できるコンテナインスタンスを用意する必要がある.実際にはそこまで厳格に計算せず,余裕を持ったコンテナインスタンスを稼働させていることが多かった.

また,ECS でオートスケーリングを実現する場合,コンテナインスタンスに対する「オートスケーリング」と,タスクに対する「サービスオートスケーリング」を気にする必要がある.以下のように設定して運用していたりもするけど,実際に負荷テストをしてみると,データストア側が詰まって別のボトルネックが見つかったり,アーキテクチャ的に別のトリガーでオートスケーリングをした方が適切な場面もあったりした.このあたりはじっくり考える必要があり,AWS に詳しくないメンバーに「難しい...」と言われたこともあった.

  • 例 :「オートスケーリング」の場合
    • ECS クラスタの CPUReservation を監視して,クラスタ全体の CPU ユニットの量でスケールさせる
  • 例 :「サービスオートスケーリング」の場合
    • ECS クラスタの中に複数のサービスを乗せることもあるため,サービス全体の CPUUtilization を監視して,タスクをスケールさせる

docs.aws.amazon.com

また,コンテナ内部のモニタリングをする方法も悩んだ.他のチームが積極的に Datadog に乗り換えていく中,Mackerel でモニタリングをしようと試みていて,完全にワークアラウンドのような仕組みだけど,問題なく動くようになり,今もこの仕組みを使っている.けど,コンテナインスタンスに Mackerel Agent をインストールするため,今後コンテナ部分はやはり Datadog への移行を検討するかもしれない.

kakakakakku.hatenablog.com

Fargate に対する期待と試した感想

このような現在の背景を考えると,コンテナインスタンスの管理をせず,コンテナにフォーカスして運用できるというのは非常にメリットになる.オートスケーリングの面でも,サービスオートスケーリングのことだけを考えれば良くなるのも嬉しい.現在は us-east-1 でしか使えないけど,さっそく Fargate を試した.既に詳しい記事がたくさん上がっているけど,自分のメモを兼ねて書いてみる.なお,Fargate の紹介記事は公式からも出ている.

aws.amazon.com

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

docs.aws.amazon.com

ネットワークモード awsvpc

今までの ECS だと,ネットワークモードはデフォルトの bridge を使っていて,コンテナインスタンスと同じネットワークで外部にアクセスするような構成になっていたけど,Fargate では awsvpc が必須となる.awsvpc ネットワークモードというのは,コンテナ自体が ENI を持って,自律的に外部にアクセスできるようになる構成で,以下の記事で詳しく解説されている.Fargate では,コンテナインスタンスを意識しないため,当然ネットワークの部分を考慮する必要があり,それがコンテナのレイヤーに上がってきたというイメージになる.合わせて,セキュリティグループもコンテナに付けられるようになるというメリットもある.ただし,ENI を持つということは,サブネットの IP が枯渇する可能性があり,そのあたりは VPC 設計からやり直さないとダメな場合もありそう.

aws.amazon.com

Auto-assign public IP

Fargate というか,ネットワークモード awsvpc の場合は,コンテナにパブリック IP を設定することもできる.ECS サービスを作成するときに Auto-assign public IP の設定を選ぶことができる.試しに Enabled にして起動してみると,ALB のターゲットグループでパブリック IP が設定されていることを確認できた.もしくは NAT Gateway を経由して外部ネットワークにアクセスすることもできる.なお,Fargate ではターゲットグループの接続タイプが instance から ip に変わるので,ここもちゃんと理解しておく必要がある.

f:id:kakku22:20171223132116p:plain

課金体系

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).

aws.amazon.com

アドベントカレンダーでも,課金体系にフォーカスした記事があり,非常に参考になった.

qiita.com

ecs-deploy の Fargate 対応

さて,やっと本題に入る.ECS のデプロイツールはいろいろと乱立していて,CloudFormation や ecs-cli や ecs-deploy がある.僕が運用している環境では ecs-deploy を採用しているので,定期的に GitHub をウォッチしているんだけど,re:Invent の直後に「Fargate 対応よろしく!」という Issue が出ていて,そのまま放置されていたので,これに挑戦することにした.

github.com

確かに,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 を比較してみたら,確かにその通りの差分を確認することができた.

hoshinotsuyoshi.com

主な差分は 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 してもらうところまでは進められてない.

github.com

実行イメージ

特に 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.

まとめ

Black Belt

www.slideshare.net