AWS CDK + GitHub Actionsで作るLambdaコンテナCI/CDパイプライン(3/4)

1.はじめに

1.1.まえがき

本ブログは以下項目の4つに分かれており、本ブログはその3つ目になります。

※ 本ハンズオンの全コードはこちらのGitHubリポジトリで参照できます。

項番 ブログタイトル 概要
1 概要とAWS事前準備編 Lambdaコンテナの仕組みと環境準備
2 アプリケーションとCDK実装編 LambdaアプリとCDKコードの解説
3 GitHub Actions設定とデプロイ・挙動確認編(本ブログ) CI/CDパイプライン構築
4 トラブルシューティング集 ハマりポイントと解決方法まとめ

1.2.今回の内容

今回は CI/CDパイプライン部分を構築します。
GitHub Actionsの設定から、実際のデプロイ、そして動作確認まで進めていきます。

今回でやること:

  1. GitHub Actionsワークフローの作成:push時に自動実行されるCI/CDパイプライン
  2. 実際のデプロイと動作確認:CodeDeployによるカナリアリリースを体験
  3. GitHubシークレットの設定:安全な認証情報管理

前提条件:

以下が完了していることを前提とします:

2.ハンズオン

2.1.前提

2.1.1.実行環境

2.1.2.全体のファイル構成

  • 以下のファイル構成をAmazo SageMaker Studio Code Editor(IDE)で構築する

■ 本手順の最終的なファイル構成

your-app/
├── .gitignore              #【前回作成】
├── .github/
│   └── workflows/
│       └── deploy.yml      #【★今回作成★】GitHub Actions ワークフロー定義
├── app/
│   ├── app.py              #【前回作成】
│   └── Dockerfile          #【前回作成】
└── cdk/                    # AWS CDK アプリケーション (Python)
    ├── app.py              #【前回作成】 CDK エントリーポイント
    ├── cdk.json            #【前回作成】 CDK 設定ファイル
    ├── requirements.txt    #【前回作成】 CDK 依存関係
    ├── .venv/              # Python 仮想環境
    └── pipeline_stack/     # スタック定義を置くディレクトリ
        ├── __init__.py     #【前回作成】
        └── pipeline_stack.py #【前回作成】 CDK スタック定義 (Python)

2.1.3.アプリケーションの説明

  • 機能: HTTP GETリクエストを受け取ると、事前に設定されたメッセージと、現在実行されているLambda関数のバージョン情報、リクエストIDをJSON形式で返却する。
  • CI/CDパイプライン構築が目的のため、アプリケーション自体のロジックは最小限にしている。

2.1.4.インフラの説明

  • AWS上にサーバーレスなAPIバックエンドと、そのCI/CDパイプラインを構築する。

■ 利用するリソース

項番 提供元 リソース名 概要
1 AWS AWS Lambda アプリケーションコード(コンテナイメージ)を実行するコンピューティングサービス。
2 AWS Amazon ECR Lambda関数で利用するDockerコンテナイメージを保存・管理するためのプライベートリポジトリです。GitHub Actionsでビルドしたイメージがここにプッシュされる。
3 AWS Amazon API Gateway Lambda関数を外部(インターネット)からHTTPリクエストで呼び出すためのエンドポイントを作成
4 AWS AWS CodeDeploy Lambda関数の新しいバージョンを安全にデプロイするためのサービスです。今回 カナリアリリース戦略を採用する。
5 AWS IAM GitHub ActionsがAWSリソース(ECRへのプッシュ、CDKによるデプロイなど)を操作するため、またLambda関数やCodeDeployが必要な権限で動作するためのロールとポリシーを作成・管理。OIDC (OpenID Connect) を利用してGitHub ActionsとAWS間の安全な認証連携を実現する。
6 AWS AWS CDK (Cloud Development Kit) 上記のAWSリソース構成をPythonコードで定義し、CloudFormationスタックとしてプロビジョニング(作成・更新)する。
7 GitHub GitHub Actions GitHubリポジトリへのコードプッシュをトリガーとして、アプリケーションのビルド(Dockerイメージ作成)、ECRへのプッシュ、CDKによるAWS環境へのデプロイを自動化するCI/CDパイプラインを構築。
2.1.5.本項目での構築箇所

file

2.2.Github Actions作成

  • CI/CDパイプラインの中心となるコード
  • GitHubにプッシュされることで自動的に実行され、ビルド – デプロイまでを処理する。

2.2.1.GitHub Actionsワークフローの構成

  • このワークフローは大きく以下4つの処理ステップに分かれている。
  1. 環境セットアップ:Python/Node.js/AWS CDK
  2. AWS認証:OIDCを使って安全にAWSにアクセス
  3. コンテナビルド & プッシュ:DockerイメージをECRに配置
  4. CDKデプロイ:クラウドインフラを自動デプロイ

2.2.3.Qualifierの取得

スタック定義で必要なECRリポジトリ名にはQualifierが含まれます。
以下のコマンドをCloudShell環境で実行して、自身の環境の値を取得しコード内 # 環境変数定義 の ECR_REPOSITORYを修正

# CDKが作成したS3バケット名を取得
BUCKET_NAME=$(aws cloudformation describe-stack-resources --stack-name CDKToolkit --query "StackResources[?ResourceType=='AWS::S3::Bucket'].PhysicalResourceId" --output text --region us-east-1)

# Qualifierを抽出(バケット名のパターン:cdk-{QUALIFIER}-...)
YOUR_QUALIFIER=$(echo "$BUCKET_NAME" | cut -d'-' -f2)

# 確認出力
echo $YOUR_QUALIFIER

2.2.4.ワークフローファイルの作成

# ファイル作成
mkdir -p your-app/.github/workflows

# デプロイワークフローの作成
cat > your-app/.github/workflows/deploy.yml << 'EOF'
name: Deploy Lambda Container via CDK (Python)

# トリガー設定:masterブランチプッシュ時に実行
on:
  push:
    branches:
      - master # masterブランチへのプッシュでトリガー

# 権限設定(OIDC認証に必要)
permissions:
  id-token: write # OIDC トークンを発行するために必要
  contents: read  # リポジトリのコンテンツを読み取るために必要

jobs:
  deploy:
    runs-on: ubuntu-latest

    # 環境変数定義
    env:
      AWS_REGION: us-east-1 # 対象のAWSリージョン
      CDK_STACK_NAME: LambdaPipelineStackPy    # CDKスタック名 (app.pyのスタックIDと合わせる)
      ECR_REPOSITORY: cdk-★★自身の Qualifier★★-container-assets-${{ secrets.AWS_ACCOUNT_ID }}-us-east-1

    steps:
      # Step 1: ソースコード取得
      - name: Checkout code
        uses: actions/checkout@v4

      # Step 2: 環境セットアップ
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.10' # CDKとLambdaで使うPythonバージョン

      # Node.js 環境のセットアップ
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      # AWS CDK CLI (npm) のインストール
      - name: Install AWS CDK CLI via npm
        run: npm install -g aws-cdk

      # Step 3: AWS認証(OIDC経由)
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/GitHubAction-AssumeRoleWithAction
          aws-region: ${{ env.AWS_REGION }}

      # Step 4: ECRログイン
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      # Step 5: Python依存関係インストール
      - name: Install Python dependencies
        working-directory: ./cdk
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt

      # Step 6: イメージタグ決定(Gitコミットハッシュ使用)
      - name: Set Image Tag
        id: image_tag
        run: echo "tag=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT

     # Step 7: Dockerイメージビルド & ECRプッシュ
      - name: Build, tag, and push image to Amazon ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} # 例: 123456789012.dkr.ecr.us-east-1.amazonaws.com
          IMAGE_TAG: ${{ steps.image_tag.outputs.tag }}
        run: |
          ECR_IMAGE_URI="$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
          docker build -t $ECR_IMAGE_URI app
          docker push $ECR_IMAGE_URI
          echo "ecr_image_uri=$ECR_IMAGE_URI" >> $GITHUB_OUTPUT # 完全なURIを出力

      # Step 8: CDKデプロイ実行
      - name: Deploy CDK Stack
        working-directory: ./cdk
        env:
          CDK_DEFAULT_REGION: ${{ env.AWS_REGION }}
        run: |
          echo "--- Running CDK deploy with image URI: ${ECR_IMAGE_URI} ---"
          # -c オプションでコンテキストとしてイメージタグを渡す
          cdk deploy ${{ env.CDK_STACK_NAME }} --require-approval never -c image_tag=${{ steps.image_tag.outputs.tag }} -vvv
EOF

3.CDKアプリ実行

  • 今まで作ったコードを全てGitHubにプッシュすることで、これ以降プッシュされると GitHub Actionsが自動でビルド・デプロイを実行する。

3.1.デプロイの実行

プロジェクトをGitHubにプッシュすると、先ほど作成したGitHub Actionsワークフローが自動で起動します。

# Git初期化(初回のみ)
git init

# 全ファイルを追加
git add .

# コミット(最初のコミット)
git commit -m "Initial commit with Lambda container and CDK setup"

# GitHubリポジトリをリモートに追加 (初回のみ)
# git remote add origin https://github.com/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME.git

# masterブランチにプッシュ(GitHub Actionsがトリガされる)
git push -u origin master # または main

3.2.GitHubでの確認画面への遷移

  • GitHub画面で「Update」の文字が表示される、押下することで「Details」が表示される。
    file

  • 「Details」を押下して以下、ビルド・デプロイまでのフローが表示される
    file

3.2.1.カナリアリリースによる挙動の違い

  • CodeDeployのカナリアリリース戦略を用いているため、以下のような挙動をする。

    • 1.新バージョンに10%のトラフィックを流す(5分間様子見)
    • 2.問題なければ100%切り替え
    • 3.エラーがあれば自動ロールバック
  • 初回デプロイ: 約2分(リソース作成のみ)
    file

  • 2回目以降のデプロイ: 約7分(リソース更新 + CodeDeploy カナリアリリース待機時間 5分設定)
    file

3.3.デプロイ後の動作確認

  • デプロイ完了後、実際にAPIエンドポイントに CloudShell でアクセスして動作確認を実施します。

3.3.1.APIエンドポイントの確認

# スタック名を変数に設定
STACK_NAME="LambdaPipelineStackPy"

# CloudFormationスタックの出力からApiEndpointの値を取得
API_ENDPOINT=$(aws cloudformation describe-stacks --stack-name $STACK_NAME --query "Stacks[0].Outputs[?OutputKey=='ApiEndpoint'].OutputValue" --output text --region us-east-1)

# 取得したURLを確認
echo "取得した API エンドポイント URL: $API_ENDPOINT"

# エンドポイントへアクセス
curl "$API_ENDPOINT"

# 想定レスポンス:以下のようなレスポンスが Lambdaより返却される
{"message": "Hello from CDK !", "version_id": "3", "aws_request_id": "968a21ba-6f15-4cc7-bc15-a54e1b1a522d"}

3.3.2.設定変更の動作確認

  • カナリアリリースを体験するために、アプリケーション設定を変更する。
項目 変数名 変更前 変更後
タイムアウト LAMBDA_TIMEOUT 30 60
メッセージ LAMBDA_MESSAGE "Hello from CDK !" Hello from Lambda !

your-app/cdk/pipeline_stack/pipeline_stack.pyを編集後、再度Git commitとpushを実行します

# 変更をコミット
git add .
git commit -m "Update Lambda settings: timeout and message"
git push

3.3.3.変更結果の確認

■ タイムアウト確認

# タイムアウト取得
aws lambda list-functions \
    --query 'Functions[?contains(FunctionName, `LambdaPipelineStackPy-MyLambdaFunction`)].[Timeout]' \
    --output text \
    --region us-east-1

# 変更前: 30
# 変更後: 60  ←正しく更新されている!

■ メッセージ確認(カナリアリリース)
version_idも、新バージョンでは1つカウントアップされる

# 継続的にAPIにアクセス
curl "$API_ENDPOINT"

# 最初の5分間:新旧メッセージが混在!
{"message": "Hello from CDK !", "version_id": "3", ...}    # 90%の確率
{"message": "Hello from Lambda !", "version_id": "4", ...} # 10%の確率

# 5分経過後:新メッセージのみ
{"message": "Hello from Lambda !", "version_id": "4", ...} # 100%

4.クリーンアップ

  • ハンズオンで作成した AWS リソースを手動で削除します。
項番 リソース 作業手順 注意点
1 CloudFormation: CDKToolkit マネジメントコンソール > CloudFormation > スタック 依存リソースがある場合は削除失敗します
2 S3: cdk--assets-… マネジメントコンソール > S3 > バケット バケット内のオブジェクトも全削除が必要
3 ECR: cdk--container-assets-… マネジメントコンソール > ECR > リポジトリ コンテナイメージ代は日々課金されるため重要
4 IAM: GitHubAction-AssumeRoleWithAction マネジメントコンソール > IAM > ロール アタッチ済みポリシーも確認
5 IAM: GitHubAction-AssumeCdkRoles マネジメントコンソール > IAM > ポリシー このポリシーを使用中のロールがないか確認
6 IAM: IDプロバイダ token.actions.githubusercontent.com マネジメントコンソール > IAM > IDプロバイダ OIDC認証の設定
7 GitHub: シークレット AWS_ACCOUNT_ID GitHub > リポジトリ > Settings > Secrets セキュリティ対策として削除

5.おわりに

今回は第3回 GitHub Actions設定とデプロイ・挙動確認編を記載しました。

今回実施したことサマリ:

  • GitHub Actionsワークフロー作成:自動CI/CDパイプラインを構築
    • OIDCベース認証設定:セキュアなAWS認証を実現
    • コンテナイメージビルド:DockerコンテナをECRへ自動プッシュ
    • CDK自動デプロイ:インフラを自動でプロビジョニング
    • CodeDeployカナリアリリース設定:安全な本番更新方法を確認
  • 動作確認と設定変更テスト:機能の検証

次回は実際のトラブルシューティング集で今回発生したエラーについてまとめたいと思います。

Last modified: 2025-05-04

Author