こんにちは。お久しぶりです。
今年の春に受験した IPA のネットワークスペシャリスト試験に合格しているのを確認し、ホっと胸をなで下ろしている今日この頃です。
さて、ちょうど AWS が Fargate ネイティブの Blue/Green デプロイを公式サポートしたところではありますが、普段 CodeDeploy と AWS 公式の GitHub Actions を使って組んでいるデプロイ機構に関して、あえて公式のアクション ( amazon-ecs-deploy-task-definition 等 ) を使わずに実装してみようと思います。
※ シェルと CLI で頑張る?という謎な縛りで実装する備忘録になります。いったい何の役に立つのやら。
構成
以下の図のように GitHub Actions でコンテナイメージのビルド、及び ECR への PUSH と、タスク定義登録、CodeDeploy のキックを行います。
今回は主に GitHub Actions の WorkFlow の処理に着目してみます。
詳細な処理のシーケンスは以下の通りです。
① ビルドしたコンテナイメージを ECR に PUSH
② タスク定義を編集し、新規登録
③ AppSpec の内容を更新し、CodeDeploy を起動
④ Green のターゲットグループ内で新イメージを元に ECS タスクが起動
⑤ ALB からの同線を Green に切り替え

Actions ( steps )
⓪ 事前処理
リポジトリのコードをチェックアウトし、IAM Role から一時的な認証情報を取得します。
ECR へのログインも済ませておきます。
※ ココだけ AWS 公式のアクションを使います。( 早速のレギュ違反 )
jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4.0.2 with: role-to-assume: ${{ inputs.role-arn }} aws-region: ${{ inputs.region }} - name: Login to Amazon ECR uses: aws-actions/amazon-ecr-login@v2.0.1
① ビルドしたコンテナイメージを ECR に PUSH
Docker のコンテナイメージをビルドし、ビルドしたイメージへタグを付与、そして ECR へ PUSH します。
- name: Build and push the image env: IMAGE_URI: ${{ inputs.image-uri }} IMAGE_TAG: ${{ inputs.github-sha }} run: | docker build -f ./Dockerfile -t src_image . docker tag src_image ${IMAGE_URI}:${IMAGE_TAG} docker push ${IMAGE_URI}:${IMAGE_TAG}
※ タグ ( IMAGE_TAG ) には コミット SHA を使用する想定です。
on: workflow_call: inputs: github-sha: required: false default: ${{ github.sha }} type: string
② タスク定義を編集し、新規登録
① で PUSH したイメージでタスクが起動するように、タスク定義の内容を更新し、AWS へ登録します。
ここで登録したタスク定義の ARN は後続の処理で使う想定です。
- name: Edit taskdefinition env: IMAGE_URI: ${{ inputs.image-uri }} IMAGE_TAG: ${{ inputs.github-sha }} TASK_DEF_FILE: ${{ inputs.task-def-file }} run: | sed -i "s#<IMAGE_TAG>#${IMAGE_TAG}#g" ${TASK_DEF_FILE} sed -i "s#<IMAGE_URI>#${IMAGE_URI}#g" ${TASK_DEF_FILE} cat ${TASK_DEF_FILE} - name: Registe taskdefinition id: register-task env: IMAGE_URI: ${{ inputs.image-uri }} IMAGE_TAG: ${{ inputs.github-sha }} TASK_DEF_FILE: ${{ inputs.task-def-file }} run: | TASK_DEF_ARN=$(aws ecs register-task-definition \ --cli-input-json file://${TASK_DEF_FILE} \ --query 'taskDefinition.taskDefinitionArn' --output text) echo "task_definition_arn=${TASK_DEF_ARN}" >> $GITHUB_OUTPUT
③ AppSpec の内容を更新し、CodeDeploy を起動
AppSpec テンプレートファイル ( ※① ) にある
置き換えた結果を appspec-tmp.yml という一時的なファイルとして保存します。
CodeDeploy に渡すリビジョン JSON 構築のため、先のステップで作った appspec-tmp.yml を jq コマンドで JSON 文字列へ変換しつつ appSpecContent の値として埋め込みます。
最後に aws deploy create-deployment を実行し、 CodeDeploy による ECS デプロイを開始します。
- name: Replace task definition ARN in AppSpec env: APPSPEC_FILE: ${{ inputs.appspec-file }} run: | sed "s|<TASK_DEFINITION>|${{ steps.register-task.outputs.task_definition_arn }}|g" ${APPSPEC_FILE} > ./appspec-tmp.yml - name: Create CodeDeploy revision JSON id: revision-json run: | APPSPEC=$(cat ./appspec-tmp.yml | jq -Rs .) REVISION='{"revisionType":"AppSpecContent","appSpecContent":{"content":'${APPSPEC}'}}' echo "revision_json=${REVISION}" >> $GITHUB_OUTPUT - name: Create deployment id: create-deployment env: CODEDEPLOY_APP_NAME: ${{ inputs.codedeploy-application }} CODEDEPLOY_DEPLOY_GROUP: ${{ inputs.codedeploy-deployment-group }} GITHUB_SHA: ${{ inputs.github-sha }} run: | DEPLOYMENT_ID=$(aws deploy create-deployment \ --application-name ${CODEDEPLOY_APP_NAME} \ --deployment-group-name ${CODEDEPLOY_DEPLOY_GROUP} \ --revision '${{ steps.revision-json.outputs.revision_json }}' \ --description "Deploy from commit ${GITHUB_SHA}" \ --output text) echo "deployment_id=${DEPLOYMENT_ID}" >> $GITHUB_OUTPUT echo "Started deployment: ${DEPLOYMENT_ID}"
※① AppSpec テンプレートファイルのサンプルは以下の通りです。
▶ AppSpec のサンプル
version: 0.0 Resources: - TargetService: Type: AWS::ECS::Service Properties: TaskDefinition: <TASK_DEFINITION> LoadBalancerInfo: ContainerName: "snkk1210-sandbox-hoge-hoge01" ContainerPort: 80 PlatformVersion: "1.4.0"
④ / ⑤
後続の処理は CodeDeploy が代行してくれるので、WorkFlow 上では wait を使って、処理完了まで待機します。
必要な処理はココまでです。
- name: Wait for deployment to finish and show URL env: REGION: ${{ inputs.region }} run: | DEPLOYMENT_ID="${{ steps.create-deployment.outputs.deployment_id }}" echo "View deployment in AWS Console:" echo "https://${REGION}.console.aws.amazon.com/codesuite/codedeploy/deployments/${DEPLOYMENT_ID}?region=${REGION}" echo "Waiting for deployment to complete..." aws deploy wait deployment-successful --deployment-id "$DEPLOYMENT_ID"
終わりに
冒頭でも触れたとおり、Fargate ネイティブの Blue/Green デプロイが公式サポートされたようで、これからは CodeDeploy を使ったデプロイ機構が非推奨になる?ようです。
将来的に公式アクションもサポートされなくなる可能性があるかも?と思い、今回、中身の代替手段を調べた次第でした。