LoginSignup
2
0

More than 1 year has passed since last update.

ECS/FargateでBlue/Greenデプロイをしてみた

Last updated at Posted at 2022-01-16

はじめに

  • チュートリアルをなぞりながらECS/FargateでBlue/Greenデプロイをしてみたときのメモです。

デプロイ

構成イメージ

手順

1. 事前構築手順

1-1. ネットワークの構築

  • Terraformで作成
  • VPCの作成
    • DNSホスト名有効化(エンドポイントのため)
  • サブネットの作成
  • インターネットゲートウェイの作成
    • -> ルートテーブルへ追加する
  • エンドポイント(Interface)の作成
    • -> エンドポイント用のSGを作成する
    • ecr.dkr
    • ecr.api
    • logs
  • エンドポイント(Gateway)の作成
    • -> ルーティングテーブルへ追加する
    • s3

1-2. ALBの構築

  • Terraformで作成
  • ALB用のSG作成
  • ALBの作成
  • ターゲットグループの作成
    • 2つ作成する(blue用とgreen用)
    • このターゲットグループは、サービスで設定されている元のタスクにトラフィックをルーティングする
    • 後続で作成するECSサービスで、このターゲットグループを指定する
  • リスナーの作成
    • ターゲットグループにリクエストを転送するデフォルトルールが関連付けられた、ロードバランサーのリスナーを作成する

1-3. ECRの構築

  • Terraformで作成
  • リポジトリの作成
    • タグのイミュータビリティを有効化
      • 同じタグでpushしても更新されない
    • プッシュ時にスキャン
  • 補足
    • ecs cliの場合push時の作成もできるが、管理上+リポジトリ設定のため、Terraformで構築する

1-4. ECSクラスターの構築

  • Terraformで作成
  • Clusterの作成
    • Fargateの場合 -> 「ネットワーキングのみ」
  • 補足
    • Cluster: TaskとServiceをグルーピングする概念。アプリケーションごと、環境ごとに用意する。

1-5. ECSサービスの構築

  • Terraformで作成
  • ECSサービス用のSG(ALBのSGからのインバウンド)
  • ECSサービスの作成
    • 初回は先にタスク定義ファイルの登録が必要?(「タスク定義ファイルの更新と登録」)
    • タスク定義バージョンの指定
    • タスクの数の指定( desired-count )
  • ex. CLIで作成する場合
ecs-service.json
{
    "cluster": "ecs-example-cluster",
    "serviceName": "ecs-example-service",
    "taskDefinition": "ecs-task-def",
    "loadBalancers": [
        {
            "targetGroupArn": "arn:aws:elasticloadbalancing:region:aws_account_id:targetgroup/ecs-example-tg1/XXXXXXXX",
            "containerName": "ecs-example",
            "containerPort": 80
        }
    ],
    "launchType": "FARGATE",
    "schedulingStrategy": "REPLICA",
    "deploymentController": {
        "type": "CODE_DEPLOY"
    },
    "platformVersion": "LATEST",
    "networkConfiguration": {
       "awsvpcConfiguration": {
          "assignPublicIp": "ENABLED",
          "securityGroups": [ "sg-abcd1234" ],
          "subnets": [ "subnet-abcd1234", "subnet-abcd5678" ]
       }
    },
    "desiredCount": 2
}
# 保留中でサービスが作成される
$ aws ecs create-service --cli-input-json file://ecs-service.json
  • 補足
    • Serviceを作成せずTaskを実行することも可能(バッチ処理など)
    • Service: 指定したtaskDefinitionからtaskを生成する
    • Serviceで定義するもの: ネットワーク、VPC、タスク定義
    • ネットワークモードで awsvpc を使う場合はプライベートサブネットを使う
    • ECS Serviceを作成する際に「deployment_controller」の設定で「type = "CODE_DEPLOY"」を指定する

1-6. CodeDeploy Applicationの構築

  • Terraformで作成
  • ex. CLIで作成する場合
aws deploy create-application \
     --application-name ecs-example-deploy-application \
     --compute-platform ECS

1-7. CodeDeploy Deployment Groupの構築

  • Terraformで作成
  • Deployment Groupを作成する
    • Blue/Greenを指定
    • ターゲットグループ(Blue/Green)とリスナーを指定
    • その他、切り替え方式などを指定
  • ex. CLIで作成する場合
    • CLIを実行するIAMの権限に注意(code deploy, pass roleが必要)
deployment-group.json
{
   "applicationName": "ecs-example-deploy-application",
   "autoRollbackConfiguration": {
      "enabled": true,
      "events": [ "DEPLOYMENT_FAILURE" ]
   },
   "blueGreenDeploymentConfiguration": {
      "deploymentReadyOption": {
         "actionOnTimeout": "CONTINUE_DEPLOYMENT",
         "waitTimeInMinutes": 0
      },
      "terminateBlueInstancesOnDeploymentSuccess": {
         "action": "TERMINATE",
         "terminationWaitTimeInMinutes": 5
      }
   },
   "deploymentGroupName": "ecs-example-deploy-group",
   "deploymentStyle": {
      "deploymentOption": "WITH_TRAFFIC_CONTROL",
      "deploymentType": "BLUE_GREEN"
   },
   "loadBalancerInfo": {
      "targetGroupPairInfoList": [
        {
          "targetGroups": [
             {
                 "name": "ecs-example-tg1"
             },
             {
                 "name": "ecs-example-tg2"
             }
          ],
          "prodTrafficRoute": {
              "listenerArns": [
                  "arn:aws:elasticloadbalancing:region:aws_account_id:listener/app/ecs-example-alb/e5ba62739c16e642/665750bec1b03bd4"
              ]
          }
        }
      ]
   },
   "serviceRoleArn": "arn:aws:iam::aws_account_id:role/ecsCodeDeployRole",
   "ecsServices": [
       {
           "serviceName": "ecs-example-service",
           "clusterName": "ecs-example-cluster"
       }
   ]
}
$ aws deploy create-deployment-group --cli-input-json file://deployment-group.json

2. CI/CD手順

2-1. ビルド実行

  • GitLabRunnerなどで、コードのマージをトリガーに、①コンテナのビルドとECRへのpush+②タスク定義ファイルの更新と登録を実施する
2-1-1. コンテナのビルドとECRへのpush
# 手動の場合
# イメージビルド
# もしもどうしても環境ごとに変数を変えたい場合は、ARGインストラクションを使う(参考: [Use argument in Dockerfile](https://blog.lorentzca.me/use-argument-in-dockerfile/) )
$ docker build ./ -t ecs-example

# (参考)ローカルで確認
$ docker run --name hogehoge ecs-example -p 8080:80

# ECRにログイン
$ aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin XXX.dkr.ecr.us-east-2.amazonaws.com

# タグ付け(ローカルで)
# commit hash値を使う
$ docker tag ecs-example:latest XXX.dkr.ecr.us-east-2.amazonaws.com/ecs-example:v1

# ECRにプッシュ
$ docker push XXX.dkr.ecr.us-east-2.amazonaws.com/ecs-example:v1
2-2-2. タスク定義ファイルの更新と登録
  • タスク定義ファイルの更新
    • 基本的には image のtagを更新していく
ecs-task-def.json
{
  "family": "ecs-task-def",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecs-exec-role",
  "networkMode": "awsvpc",
  "requiresCompatibilities": [ "FARGATE" ],
  "cpu": "256",
  "memory": "512",
  "containerDefinitions": [
    {
      "name": "ecs-example",
      "image": "XXX.dkr.ecr.us-east-2.amazonaws.com/ecs-example:v1",
      "essential": true,
      "memory": 384,
      "memoryReservation": 128,
      "portMappings": [
        {
          "containerPort": 80
        }
      ]
    }
  ]
}
  • タスク定義ファイルの登録
    • file:// を忘れない
aws ecs register-task-definition --cli-input-json file://ecs-task-def.json
2-2-3. appspec.yamlファイルの更新とS3アップロード
  • appspec.yamlの更新
    • タスク定義のバージョン情報を更新する
appspec.yaml
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "arn:aws:ecs:region:aws_account_id:task-definition/ecs-task-definition:7"
        LoadBalancerInfo:
          ContainerName: "ecs-example"
          ContainerPort: 80
        PlatformVersion: "LATEST"
  • appspec.yamlのアップロード
$ aws s3 cp ./appspec.yaml s3://deploy-bucket/appspec.yaml
  • 補足
    • Task: コンテナの集合体
    • TaskDefinition: docker-compose的なもの
    • TaskDefinitionで定義するもの: タスクメモリ、CPU、コンテナ1のイメージURI・ポートマッピング・ログ設定
    • タスク定義パラメータはこちらを参照

2-2. デプロイ実行

  • 事前にcreate-deployment.jsonを作成しておく(更新不要)
{
    "applicationName": "ecs-example-deploy-application",
    "deploymentGroupName": "ecs-example-deploy-group",
    "revision": {
        "revisionType": "S3",
        "s3Location": {
            "bucket": "deploy-bucket",
            "key": "appspec.yaml",
            "bundleType": "YAML"
        }
    }
}
  • CodeDeployのデプロイを作成する(デプロイ実行)
$ aws deploy create-deployment \
     --cli-input-json file://create-deployment.json

2-3. 動作確認

  • テストポートで動作確認する

2-4. Blue/Green切り替え

  • 確認が完了したらCodeDeploy画面で『トラフィックの再ルーティング』を実行する。→ロールバックの必要がないと判断したら『元のタスクセットの終了』を選択する。

参考

2
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
2
0