目的
- ECS on Fargateで動いてるサイトがある
- このサイトへのデプロイを完全自動化したい
- 何か問題が合った時にすぐ切り戻せるようにしたい
目的を達成するための手段
- デプロイまでの処理をGitHub Actionsで完全自動化する
- ロールバック用のワークフローを作っておき、問題があったときに手動実行できるようにしておく
デプロイまでの処理をGitHub Actionsで完全自動化して何も問題ないの?危なくない?
- GitHub Actionsを使用してDockerイメージをECRにプッシュし、ECS on Fargateで動作しているサイトを更新する自動化プロセスは一般的で、適切に設定すれば問題なし。逆に適切に設定されたCI/CDパイプラインは、デプロイプロセスの効率と信頼性を向上させ、人為的ミスを減らすことができる。
- ただし、いくつかの重要なポイントを考慮する必要がある:
- 自動化の安全性:
- 適切なIAM権限設定を行い、必要最小限の権限のみを付与します。
- OIDCを使用してGitHub ActionsとAWSの認証を安全に行います。
- イメージのタグ付け:
- 適切なタグ付け戦略を使用し、各ビルドを一意に識別できるようにします。
- 例えば、GitコミットSHAやビルド番号をタグに含めます。
- ECSサービスの更新:
- 新しいイメージをプッシュした後、ECSサービスを更新するステップを含めます。
- ローリングアップデートを使用して、ダウンタイムを最小限に抑えます。
- テストと検証:
- プロダクション環境にデプロイする前に、ステージング環境でテストを行います。
- 自動テストをワークフローに組み込みます。
- ロールバック戦略:
- 問題が発生した場合に備えて、簡単にロールバックできる仕組みを用意します。
- 監視とアラート:
- デプロイ後のアプリケーションの健全性を監視します。
- 問題が発生した場合に迅速に通知を受け取れるようにします。
- ブランチ保護:
- 本番環境へのデプロイは特定のブランチ(例:main)からのみ行うようにします。
- プルリクエストのレビューと承認プロセスを設定します。
- シークレット管理:
- AWS認証情報などの機密情報はGitHub Secretsを使用して安全に管理します。
- 自動化の安全性:
コードサンプル
ECSデプロイまでを自動でやるワークフロー(ロールバック考慮済み):
deploy_to_ecs.yml
name: Deploy to ECS
on:
push:
branches: [ main ]
# OIDCトークンの生成と読み取り権限を設定
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
# リポジトリのコードをチェックアウト
- uses: actions/checkout@v2
# AWS認証情報を設定(OIDCを使用)
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: arn:aws:iam::<YOUR-AWS-ACCOUNT-ID>:role/<YOUR-IAM-ROLE-NAME>
aws-region: us-east-1
# Amazon ECRにログイン
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
# Dockerイメージをビルド、タグ付け、ECRにプッシュ
- name: Build, tag, and push image to Amazon ECR
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: my-ecr-repo
IMAGE_TAG: ${{ github.sha }} # GitHubのコミットSHAをタグとして使用
run: |
# GitHubのコミットSHAをタグ付けしたDockerイメージをビルド
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
# ビルドしたイメージをECRにプッシュ
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
# ECSサービスを更新
- name: Update ECS service
run: |
# 最新のタスク定義を使用してECSのサービスを強制的に更新
aws ecs update-service \
--cluster my-cluster \
--service my-service \
--force-new-deployment \
--task-definition my-task-definition:latest
# プッシュしたイメージに"production"タグを追加
- name: Tag as production
run: |
# 先ほどプッシュしたGitHub SHAタグ付けイメージに "production" タグも追加
# これにより、最新のプロダクションイメージを簡単に識別できる
aws ecr put-image \
--repository-name my-ecr-repo \
--image-tag production \
--image-manifest $(aws ecr batch-get-image \
--repository-name my-ecr-repo \
--image-ids imageTag=${{ github.sha }} \
--query 'images[].imageManifest' \
--output text)
# デプロイ情報を記録
- name: Record deployment
run: |
# デプロイに使用したイメージのタグ(GitHub SHA)をファイルに書き込み
echo ${{ github.sha }} > last_deployed_tag.txt
# 書き込んだファイルをS3バケットにアップロード
# これにより、最後にデプロイされたイメージのタグを記録し、必要に応じてロールバックできるようにする
aws s3 cp last_deployed_tag.txt s3://my-deployment-bucket/last_deployed_tag.txt
rollback_ecs_service.yml
### ECSロールバック用のワークフロー:
name: Rollback ECS Service
# 手動でワークフローを実行できるようにする
on:
workflow_dispatch:
# OIDCトークンの生成と読み取り権限を設定
permissions:
id-token: write
contents: read
jobs:
rollback:
runs-on: ubuntu-latest
steps:
# AWS認証情報を設定(OIDCを使用)
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: arn:aws:iam::<YOUR-AWS-ACCOUNT-ID>:role/<YOUR-IAM-ROLE-NAME>
aws-region: us-east-1
# S3から最後にデプロイされたタグを取得
- name: Get last deployed tag from S3
run: |
# S3バケットから最後にデプロイされたタグ情報をダウンロード
aws s3 cp s3://my-deployment-bucket/last_deployed_tag.txt .
# ファイルの内容を環境変数に設定
ROLLBACK_TAG=$(cat last_deployed_tag.txt)
# GitHub Actionsの環境変数としてROLLBACK_TAGを設定
echo "ROLLBACK_TAG=$ROLLBACK_TAG" >> $GITHUB_ENV
# Amazon ECRにログイン
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
# ロールバック用のイメージでECSサービスを更新
- name: Update ECS service with rollback image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: my-ecr-repo
run: |
# ECSサービスを更新し、ロールバック用のイメージを指定
aws ecs update-service \
--cluster my-cluster \
--service my-service \
--task-definition my-task-definition \
--force-new-deployment \
--overrides '{
"containerOverrides": [{
"name": "container-name",
"image": "${ECR_REGISTRY}/${ECR_REPOSITORY}:${ROLLBACK_TAG}"
}]
}'
# デプロイメントの完了を確認
- name: Verify deployment
run: |
# ECSサービスが安定状態になるまで待機
aws ecs wait services-stable \
--cluster my-cluster \
--services my-service
# ロールバックの完了を通知
echo "Rollback completed successfully"
ECRのタグ付け戦略イメージの具体例
- デプロイ前の状態:
my-ecr-repo:2023-09-10-v1.0.5 (最新のデプロイ)
my-ecr-repo:production (= 2023-09-10-v1.0.5)
my-ecr-repo:2023-09-05-v1.0.4
my-ecr-repo:2023-09-01-v1.0.3
- 新しいバージョン
v1.0.6
をデプロイ後:
my-ecr-repo:2023-09-15-v1.0.6 (新しくデプロイされたイメージ)
my-ecr-repo:production (= 2023-09-15-v1.0.6)
my-ecr-repo:2023-09-10-v1.0.5 (以前のproduction)
my-ecr-repo:2023-09-05-v1.0.4
my-ecr-repo:2023-09-01-v1.0.3
- 問題が発生し、ロールバックが必要な状況:
my-ecr-repo:2023-09-15-v1.0.6 (問題のあるイメージ)
my-ecr-repo:production (= 2023-09-15-v1.0.6)
my-ecr-repo:2023-09-10-v1.0.5 (ロールバック先の安定バージョン)
my-ecr-repo:2023-09-05-v1.0.4
my-ecr-repo:2023-09-01-v1.0.3
-
2023-09-10-v1.0.5
へのロールバック後:
my-ecr-repo:2023-09-10-v1.0.5 (ロールバックされたイメージ)
my-ecr-repo:production (= 2023-09-10-v1.0.5)
my-ecr-repo:2023-09-15-v1.0.6 (問題のあったイメージ)
my-ecr-repo:2023-09-05-v1.0.4
my-ecr-repo:2023-09-01-v1.0.3
この例では:
- 各イメージは日付とバージョン番号の組み合わせでタグ付けされています(例:2023-09-15-v1.0.6)。
-
production
タグは常に現在のプロダクション環境で使用されているイメージを指しています。 - ロールバック時は、以前の安定したバージョン(この場合は2023-09-10-v1.0.5)に
production
タグを移動させます。 - 全てのイメージバージョンが保持されているため、必要に応じて任意のバージョンにロールバックできます。
この命名規則により:
- デプロイの日付が明確になります。
- バージョン番号により、イメージの順序や進捗が分かりやすくなります。
-
production
タグにより、現在の本番環境のイメージが一目で分かります。
この方法を使用することで、イメージの管理がより直観的になり、デプロイ履歴の追跡やロールバックの実行が容易になります。
注意点:
- この方法では多くのイメージが保存されるため、ECRのライフサイクルポリシーを設定して古いイメージを自動的に削除することをお勧めします。ただし、
production
タグが付いたイメージは削除されないようにポリシーを設定する必要があります。
おわりに
- 作ってみて思ったけど、ロールバック用のワークフローは、特定のこのバージョンに戻したい!には対応できない。
- バージョン指定してロールバックできるようにしないと。が今後の課題。