0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AWS ECS + CodeDeploy + CodePipeline ( + ちょっとTerraform ) – デプロイ方法を ローリングアップデートからblue/greenデプロイに変える時のまとめ

Posted at

ECSへのデプロイ方法をローリングアップデートからblue/greenに変える手順を記す

事前確認

ローリングアップデートとblue/greenデプロイのどちらを使っているかの確認

  • ECSへの直接デプロイはローリングアップデート
  • CodeBuildを利用したデプロイはblue/greenデプロイ

主にこの構成のようだ。(2023/08/18現在)

デプロイ時にCodeDeployの履歴に何も増えなければ恐らくECSへの直接デプロイがされてるはず。

ターゲットグループを作る

特にblue用とgreen用のターゲットグループがあるというわけではなく
blue/greenデプロイでは2個のターゲットグループがスイッチングされる

  • ALBのリスナールールに紐づくターゲットグループが更新される
  • ECSに紐づくターゲットグループが更新される

という動作のようだ。

なので既にローリングアップデートしている場合は利用しているターゲットグループが1個はあるはずなので、それと同じようなターゲットグループをもう1個作れば良い。

2個のターゲットグループは同じALBに紐づくようにしておく。

サービスロールの作成

AWSCodeDeployRoleForECS のセット(?)でロールを作っておけば良いようだ

image

JSONを見てみると次の通り

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "ecs:DescribeServices",
                "ecs:CreateTaskSet",
                "ecs:UpdateServicePrimaryTaskSet",
                "ecs:DeleteTaskSet",
                "elasticloadbalancing:DescribeTargetGroups",
                "elasticloadbalancing:DescribeListeners",
                "elasticloadbalancing:ModifyListener",
                "elasticloadbalancing:DescribeRules",
                "elasticloadbalancing:ModifyRule",
                "lambda:InvokeFunction",
                "cloudwatch:DescribeAlarms",
                "sns:Publish",
                "s3:GetObject",
                "s3:GetObjectVersion"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "iam:PassRole"
            ],
            "Effect": "Allow",
            "Resource": "*",
            "Condition": {
                "StringLike": {
                    "iam:PassedToService": [
                        "ecs-tasks.amazonaws.com"
                    ]
                }
            }
        }
    ]
}

CodeDeployでデプロイアプリを作る

コンピューティングタイプ : Amazon ECS

デプロイグループを作る

Web Console の場合

  • ECSのクラスタやサービス
  • ECSで利用しているALB
  • 2個のターゲットグループ

などを指定していく

この
サービスロールは事前に作っておけば選択肢に出てくる

image

ポートの指定は本番稼働用とテスト用で別のものを選ぶ
ALBのリスナールールに少なくとも2種類のポートのルールがなければいけないかもしれない

Terraformの場合

サンプルのコードを参考に組み立てる

resource "aws_codedeploy_app" "example" {
  compute_platform = "ECS"
  name             = "example"
}

resource "aws_codedeploy_deployment_group" "example" {
  app_name               = aws_codedeploy_app.example.name
  deployment_config_name = "CodeDeployDefault.ECSAllAtOnce"
  deployment_group_name  = "example"
  service_role_arn       = aws_iam_role.example.arn

  auto_rollback_configuration {
    enabled = true
    events  = ["DEPLOYMENT_FAILURE"]
  }

  blue_green_deployment_config {
    deployment_ready_option {
      action_on_timeout = "CONTINUE_DEPLOYMENT"
    }

    terminate_blue_instances_on_deployment_success {
      action                           = "TERMINATE"
      termination_wait_time_in_minutes = 5
    }
  }

  deployment_style {
    deployment_option = "WITH_TRAFFIC_CONTROL"
    deployment_type   = "BLUE_GREEN"
  }

  ecs_service {
    cluster_name = aws_ecs_cluster.example.name
    service_name = aws_ecs_service.example.name
  }

  load_balancer_info {
    target_group_pair_info {
      prod_traffic_route {
        listener_arns = [aws_lb_listener.example.arn]
      }

      target_group {
        name = aws_lb_target_group.blue.name
      }

      target_group {
        name = aws_lb_target_group.green.name
      }
    }
  }
}

デプロイ設定

AWSに最初からデプロイ設定のひながたが数種類あるので特に自分では設定しなくてOK

ECSサービスのデプロイタイプを変える

WebConsoleの場合

単に設定を変えるということは出来なさそう。
ECSサービス作成時にはデプロイタイプでブルー/グリーンが選べるのでいちどECSサービスを削除してから再度作成するのが良さそう。
(ちなみに新しいUIだとローリングアップデートしか選べなくなっているようだ)

Terraformの場合

デプロイタイプを変えて terraform apply をするとECSサービスが破棄・再作成されるようなので注意

blue/greenデプロイの場合はECSサービスに紐づくタスク定義の更新が出来なくなるようなのでタスク定義の変更をignoreしておく
ロードバランサも
(本当にこの対処で良いのかは調べきれていないが)

resource "aws_ecs_service" "default" {

  ...

  deployment_controller {
    type = "CODE_DEPLOY"
  }

  lifecycle {
    ignore_changes        = [task_definition, load_balancer]
  }
}

CodePipelineのDeployステージの設定を変える

Web Consoleの場合

アクションプロバイダを Amazon ECS (ブルー/グリーン)に変える
あとはテストアプリケーション・テストグループなどを選んで行く

今回の例ではビルドステージを使っているので入力にはBuildのアーティファクトを選んでいる

image

Terraformの場合

ビルドステージをDeployの入力とする場合は次のような感じ


  stage {
    name = "Deploy"

    action {
      ... いろいろ省略 ...

      provider        = "CodeDeployToECS"
      input_artifacts = ["Build"]

      configuration = {
        ApplicationName = "deploy-app"
        DeploymentGroupName = "deploy-group"

        Image1ArtifactName = "Build"
        Image1ContainerName = "IMAGE1_NAME"
        TaskDefinitionTemplateArtifact = "Build"
        TaskDefinitionTemplatePath = "taskdef.json"
        AppSpecTemplateArtifact = "Build"
        AppSpecTemplatePath = "appspec.yml"
      }

    }
  }

appspec.yml を追加する

レポジトリのトップディレクトリに appspec.yml または appspec.json を設定する

<TASK_DEFINITION> の部分はプレースホルダでCodeDeployがタスク定義のARNに変えてくれる

ContainerName / ContainerPort は既存のタスク定義を参照するなりして確認すればOK

version: '0.0'
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: container-name
          ContainerPort: 80

ちなみにファイル名はCodePipelineのDeployステージの設定で変更可能

image

taskdef.json を作成する

レポジトリのトップにファイルを置いておく

既存のタスク定義の JSON をひな形にして作るのがやりやすい。
(AWS Web Console でもタスク定義画面からJSONが取れるはず)

ただ出力されたJSONと入力に使うJSONは異なるので修正する

  • registeredAt
  • registeredBy
  • requiresAttributes
  • status
  • revision

とかは不要な項目のようだ

あとtags項目があるとエラーが起こるので自分が試した時は消しておいた

image はCodePipelineで指定したプレースホルダにする

{
    "containerDefinitions": [
        {
            "name": "container-name",
            "image": "<IMAGE1_NAME>",

ちなみにlocalファイルを指定してタスク定義登録をしようとすると不要項目がある場合は教えてくれるので試しても良い

aws ecs register-task-definition --cli-input-json file://taskdef.json

どうやってタスク定義の値を動的に変えるのか?

イメージのプレースホルダ以外は動的に変わらなそう。
調べると buildステージ ( buildspec.yml ) でsedコマンドを使うなりして環境に応じて無理やりファイル内容を変えてしまう方法が紹介されていた。

参考:

ECS Fargateデプロイ用CodePipelineのtaskdef.jsonに変数を持たせる方法
https://qiita.com/neruneruo/items/a5313beb3074a1af4df2

他には環境ごとにtaskdef.jsonを用意しておくなどやり方は色々あるだろうが

buildspec.yml を修正する

  • ECS直接デプロイでは imagedefinitions.json を作成してたがこれを imageDetail.json に変える
  • appspec をDeployステージ用の出力に含める
  • appspec をDeployステージ用の出力に含める
  post_build:
    commands:
      ...
      - printf '{"Version":"1.0","ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json
artifacts:
  files:
    - imageDetail.json
    - taskdef.json
    - appspec.yml

いざ実行

  • ECSサービスのサービス更新を試す
  • ソースレポジトリ (Githubとか) に push する

などして動作を試す

チャットメンバー募集

何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

Twitter

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?