ECSを運用で使っていて難しいと思った点

ECSを触っていて今まで難しいと思ったことを雑にまとめておく。

タスクロールとタスク実行ロールの違い

ECSを長く触っているのに、いつも混乱する。

  • タスクロール
    • コンテナ内の権限
    • S3やSESなどの権限をつける
  • タスク実行ロール
    • コンテナ外の権限
    • ECRやParameter Storeの権限をつける

ECSのデプロイ時に静的ファイルが404になる

ECSを触った初期に遭遇した。 詳細は以下のQiitaの記事が分かりやすい。

参照: ECSのデプロイ時に一定確率で静的ファイルが404になる問題を回避する

回避する方法はいくつかある。

  • 静的ファイルをS3に置く
  • CodeDeployの OneAtATime を使う
  • CodeDeployのBlue/GreenとALBのスティッキーセッションを使う

知らないと気づくのは難しい。

ECSサービスを無停止で更新する手順

ECSサービスをTerraformで変更するとき、一部の設定は replace になる。 無停止で更新するために、新しいECSサービスを作成してターゲットグループをうまく切り替える必要がある。

  1. 新しいECSサービスを作成
  2. Host: dummy.exmaple.com のリスナールールに新ECSサービスを紐づける
    • デフォルトリスナーは旧ECSサービス
  3. 新旧のECSサービスを両方ともデプロイするようにデプロイを設定する
  4. リスナールールの Host を正しい値に変更
    • この時点で新ECSサービスにリクエストが流れる
  5. 旧ECSサービスを削除

手順が多くて面倒なので、リソースを作成する前にecs_serviceの全オプションをしっかり読んだ方が良い。

  • EC2 -> Fargate の移行
  • ECSデプロイ -> CodeDeploy の移行
  • Propagate tagsの設定

少なくとも、これらの作業をするときに必要になった。

CannotPullContainerError でECSタスクが無限に再起動する

ECRにDockerイメージをプッシュしないでタスク定義を更新・デプロイすると起きる。

deployment circuit breaker の設定しておくと良い。

参考: Amazon ECS deployment circuit breaker のご紹介

execute-command は最大2セッション

ecs execute-command でECSタスクに接続できるのは 2セッション まで。

複数人がECSタスクに接続する運用がある場合には注意が必要。

Terraformでタスク定義の最新を参照する

デプロイするとタスク定義のリビジョンが変わるので、ecs_task_definitionのコードを参考にコードを書く必要がある。

data "aws_ecs_task_definition" "mongo" {
  task_definition = aws_ecs_task_definition.mongo.family
}

resource "aws_ecs_cluster" "foo" {
  name = "foo"
}

resource "aws_ecs_task_definition" "mongo" {
  family = "mongodb"

  container_definitions = "<略>"
}

resource "aws_ecs_service" "mongo" {
  name          = "mongo"
  cluster       = aws_ecs_cluster.foo.id
  desired_count = 2

  # Track the latest ACTIVE revision
  task_definition = "${aws_ecs_task_definition.mongo.family}:${
    max(aws_ecs_task_definition.mongo.revision, data.aws_ecs_task_definition.mongo.revision)
  }"
}

CodeDeployを使っているとECSサービスのタグが更新できない

AWSコンソールからは普通にタグをつけられるが、Terraformからは更新できずに下記のエラーが起きる。

Unable to update network parameters on services with a CODE_DEPLOY deployment controller. Use AWS CodeDeploy to trigger a new deployment

詳細は調べられていないけど、AWS Providerのバグかも?

CodeDeploy Blue/Greenを使うとTarget Groupは交互に変わる

リソースを用意するときはTerraformだけど、デプロイは別で行う場合にターゲットグループがズレるケースがある。

  1. Terraformでターゲットグループ(TG-1, TG-2)を用意する
  2. Terraformで TG-1 をリスナールールに紐付ける
  3. CodeDeployでTG-1, TG2のデプロイ設定を行う
  4. CodeDeployでデプロイを行う
    • リスナールールに紐づくリソースが TG-1 => TG-2 に変わる
  5. Terraformで設定を変える
    • コード上は TG-1 がリスナールールに紐づいている
    • apply するとECSサービスの紐づいていない TG-1 に変わり障害になる

terraform plan の出力をちゃんと読めば気づける。

タスク定義みたいにTerraformのコードを工夫すれば回避できるのかな...私は知らないが...

GitHub Actions vs CodePipeline

どちらも触った経験があるけど、どちらも難しくて慣れが必要。

  • GitHub Actions: 日本語の記事が少ない、コード例が少ない
  • CodePipeline: GitHubの連携が面倒、慣れないとIAMとVPCでハマる

比較して考察している記事もあるので、読んでみると良い。

参考: ECS用のCDパイプラインに対する考察