🐳

GitHub Actionsで本番環境と検証環境に異なるコンテナをpushする方法

に公開

この記事の目的

GitHub Actions を使ってコンテナを AWS Elastic Container Registry (ECR) に push する際、本番環境と検証環境で異なるコンテナを使い分けたいケースは多いと思います。

特に ECS Fargate で運用している場合、環境ごとに適切なタグを付けてイメージを管理することが重要になります。

本記事では、GitHub Actions で環境ごとに異なるコンテナを push する方法を解説します。

環境ごとに異なるコンテナを push する方法

本番環境と検証環境で異なるコンテナをデプロイするには、ブランチごとにタグを分けるのが一般的です。

タグのルールを決める

ブランチ名 環境 イメージタグ
main 本番環境 my-image:prod
develop 検証環境 my-image:staging
feature/* 開発環境 my-image:dev

GitHub Actions では GITHUB_REF という環境変数を使い、どのブランチで実行されているかを取得できます。

例えば、以下のような方法でブランチ名を取得できます。

- name: ブランチ名を取得
  run: echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV

GITHUB_REF には refs/heads/main のような値が入っているので、refs/heads/ の部分を削ることでブランチ名だけを取り出せます。Actions のログでは次のように出力されます。

Run echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV

例えば main ブランチで実行した場合、BRANCH_NAME=main が環境変数にセットされます。

この BRANCH_NAME を使って、ECR に push するタグを動的に決めます。

GitHub Actions のワークフロー

以下は GitHub Actions を使って環境ごとに異なるコンテナを push するワークフローの例です。

name: Build and Push Docker Image

on:
  push:
    branches:
      - main
      - develop
      - "feature/*"

env:
  AWS_REGION: ap-northeast-1
  ECR_REPOSITORY: my-container-repo

jobs:
  build-and-push:
    runs-on: ubuntu-latest

    steps:
      - name: コードをチェックアウト
        uses: actions/checkout@v3

      - name: AWS CLI を設定
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: ECR にログイン
        run: |
          aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin <AWS_ACCOUNT_ID>.dkr.ecr.$AWS_REGION.amazonaws.com

      - name: ブランチ名を取得
        run: echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV

      - name: イメージタグを決定
        run: |
          if [[ "$BRANCH_NAME" == "main" ]]; then
            echo "IMAGE_TAG=prod" >> $GITHUB_ENV
          elif [[ "$BRANCH_NAME" == "develop" ]]; then
            echo "IMAGE_TAG=staging" >> $GITHUB_ENV
          else
            echo "IMAGE_TAG=dev" >> $GITHUB_ENV
          fi

      - name: Docker イメージをビルド
        run: |
          docker build -t $ECR_REPOSITORY:$IMAGE_TAG .

      - name: ECR に push
        run: |
          docker tag $ECR_REPOSITORY:$IMAGE_TAG <AWS_ACCOUNT_ID>.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPOSITORY:$IMAGE_TAG
          docker push <AWS_ACCOUNT_ID>.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPOSITORY:$IMAGE_TAG

「イメージタグを決定」ステップの Actions ログは、たとえば develop ブランチで実行した場合、次のようになります。

Run if [[ "$BRANCH_NAME" == "main" ]]; then
  echo "IMAGE_TAG=prod" >> $GITHUB_ENV
elif [[ "$BRANCH_NAME" == "develop" ]]; then
  echo "IMAGE_TAG=staging" >> $GITHUB_ENV
else
  echo "IMAGE_TAG=dev" >> $GITHUB_ENV
fi

この結果、IMAGE_TAG=staging が環境変数にセットされ、以降のステップで my-container-repo:staging としてビルド・push されます。

Fargate でのデプロイ時のポイント

ECS タスク定義を環境ごとに更新する

ECS Fargate では task-definition.json を使ってコンテナ設定を更新できます。

環境ごとに適切なタグを適用するには、GitHub Actions でタスク定義を更新しましょう。

- name: タスク定義の更新
  run: |
    aws ecs update-service --cluster my-cluster \
      --service my-service \
      --force-new-deployment

ここで force-new-deployment を指定しているのがポイントです。このオプションを付けると、タスク定義やイメージが更新された際に確実に新しいコンテナへ切り替わります。

task-definition.json に変数を埋め込む方法

1. task-definition.json をテンプレート化する

環境変数を使うため、{{IMAGE_TAG}} のようなプレースホルダーを入れておきます。

{
  "family": "my-task",
  "containerDefinitions": [
    {
      "name": "my-app",
      "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/my-container-repo:{{IMAGE_TAG}}",
      "memory": 512,
      "cpu": 256,
      "essential": true
    }
  ]
}

2. GitHub Actions で IMAGE_TAG を埋め込む

sed コマンドを使って、プレースホルダーを実際の値に置き換えます。

- name: `task-definition.json` に環境変数を埋め込む
  run: |
    sed -i 's/{{IMAGE_TAG}}/'"$IMAGE_TAG"'/g' task-definition.json

たとえば main ブランチで実行した場合、{{IMAGE_TAG}}prod に置き換わり、イメージの指定が my-container-repo:prod になります。

まとめ

GitHub Actions で本番環境・検証環境ごとに異なるコンテナを push する方法を解説しました。

  • ブランチごとにタグを分ける (prod, staging, dev)
  • GitHub Actions でブランチを判定して自動で push する
  • task-definition.json に環境変数を埋め込んでタスク定義を動的に生成する
  • Fargate の force-new-deployment を活用して確実にデプロイを反映する

これらを組み合わせることで、環境ごとに適切なコンテナ管理ができ、デプロイの柔軟性が向上します。実際のプロジェクトに合わせてブランチ名やタグのルールを調整してみてください。

Discussion