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

1.はじめに

1.1.まえがき

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

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

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

1.2.きっかけ

2025年 GW というまとまった時間で、いままで避けてきてしまった CDK に触れてみようと思い、ふらっと本構築をスタートしました。

コードに強いわけでもなく、仕事で IaCを利用しているわけでもなく、これが正しいというゴールもなく LLMと二人三脚で構築をしています。
そのため仕事で利用している方などにとっては、大変見ずらいものになるかとは思っていますが、それはそれで置いておいて挑戦しています。

1.2.1.検証したかった部分

  • コンテナでLambda実装: 従来の.zipデプロイじゃなくてECRから直接コンテナ起動させる方式
  • IaCとCI/CDの統合: GitHubへプッシュするだけで全部自動デプロイ

1.3.本ブログでの構成図

  • GitHubにコードをプッシュすると、Lambdaコンテナが自動デプロイされる仕組みの構築

■全体の流れ

項番 処理概要
1 開発者がコードを GitHub に push
2 OIDC 認証で IAM ロールを取得
3 Docker イメージを ECR にプッシュ
4 CDK が CloudFormation テンプレートを生成
5 CloudFormation がインフラを構築
6 CodeDeploy がブルーグリーンデプロイ実行

file

1.4.CDK(Cloud Development Kit)概要

1.4.1.CDK(Cloud Development Kit)とは?

  • プログラミング言語(TypeScript、Python、Java、C#など)を使ってクラウドインフラストラクチャをコードとして定義・管理・デプロイできるオープンソースのソフトウェア開発フレームワークをさす。
  • 従来AWSリソースの構築にはCloudFormationのようなテンプレート(YAMLやJSON)を用いていましたが、CDKを活用することで使い慣れたプログラミング言語で、より柔軟かつ動的にインフラの記述が可能となる。
  • CDKで書いたコードは最終的に CloudFormationのテンプレートへ変換 され、AWS上にリソースがプロビジョニングされる。

1.4.2.コンストラクト について

  • CDKは「コンストラクト」と呼ばれる 再利用可能な部品を提供してくれるおかげで、複雑なリソースやベストプラクティスに基づいた構成を簡単に記述することができる。
  • 本ブログでは、比較的学習コストが低く、実装もシンプルな L2(レベル2)を利用して構築を行います。
レベル 概要
L1(レベル1) CloudFormationリソースをそのまま表現。細かい設定が必要。
L2(レベル2) L1をラップし、より高レベルで便利なAPIやデフォルト値を提供。
L3(レベル3) 複数のL1/L2を組み合わせ、特定のユースケース向けのパターンを提供。

2.ハンズオン

2.1.前提

2.1.1.実行環境

  • CloudShellで実施

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.2. AWSでの事前準備

2.2.1.OIDC プロバイダ(=GitHub)との信頼確立

2.2.1.1.OIDC とは?
  • OIDC(OpenID Connect Provider)プロバイダとは認証サービスの一種で、異なるシステム間で認証情報を共有するための仕組みです。
    「6938~」部分は、GitHubのサムプリント(= サーバ証明書)です。
2.2.1.2.ざっくり OIDC認証フロー
項番 項目 ざっくり内容
1 初期設定 信頼関係確立(以下、コマンドでAWSにサムプリントの登録部分)
2 認証リクエスト GitHub Actions ワークフローが、OIDCプロバイダ(=GitHub)からJWTトークン取得
3 トークン検証と交換 GitHub Actions ワークフローが、AWS へ JWTトークンを提示
AWS は JWTトークンを検証、条件に合致していれば AWSアクセストークン発行
4 AWSへアクセス AWSから発行された AWSアクセストークンを利用s知恵アクセス
2.2.1.3.本項目での構築箇所

file

2.2.1.4.実行コマンド
  • CloudShellにて実施
  • マネジメントコンソール右上 [>.] アイコンより、Cloudshellの起動
# GitHubとの信頼関係の確立
aws iam create-open-id-connect-provider \
  --url https://token.actions.githubusercontent.com \
  --client-id-list sts.amazonaws.com \
  --thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1

AWSユーザーガイド:OpenID Connect ID プロバイダーのサムプリントを取得する

2.2.2.GitHub Actions用 IAMロール作成

  • 変数設定を自身のものに置き換えて実施
  • 今回作成する IAMポリシーについては PoC のため非常に強い権限です。
    本番環境においては最小権限の原則に従い、必要な権限に絞ったカスタムポリシーを作成・利用することが推奨されます。
# 変数設定
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export GITHUB_USERNAME="your-github-username"
export GITHUB_REPO="your-repo-name"

# 信頼ポリシーのJSONファイルを作成
cat > trust-policy.json << EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::$AWS_ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:$GITHUB_USERNAME/$GITHUB_REPO:*"
        },
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        }
      }
    }
  ]
}
EOF

# GitHub用のIAMロール作成
aws iam create-role \
  --role-name GitHubAction-AssumeRoleWithAction \
  --assume-role-policy-document file://trust-policy.json

# 必要なポリシーをアタッチ
# ECRのポリシーをアタッチ
aws iam attach-role-policy \
  --role-name GitHubAction-AssumeRoleWithAction \
  --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess

# Lambdaのポリシーをアタッチ
aws iam attach-role-policy \
  --role-name GitHubAction-AssumeRoleWithAction \
  --policy-arn arn:aws:iam::aws:policy/AWSLambda_FullAccess

# API Gatewayのポリシーをアタッチ
aws iam attach-role-policy \
  --role-name GitHubAction-AssumeRoleWithAction \
  --policy-arn arn:aws:iam::aws:policy/AmazonAPIGatewayAdministrator

# SSMのポリシーをアタッチ(cdk bootstrapの設定値取得用)
aws iam attach-role-policy \
  --role-name GitHubAction-AssumeRoleWithAction \
  --policy-arn arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess

2.2.3.Bootstrap実行

  • Bootstrpとは?

CDK で AWS リソースをデプロイするための事前準備(※今回は最新版の CDK CLI をインストール)

# 変数の設定
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REGIOM="us-east-1"

# 環境変数として設定
aws configure set region us-east-1

# CDK CLIインストール
npm install -g aws-cdk

# cdk bootstrap実行
cdk bootstrap aws://${AWS_ACCOUNT_ID}/us-east-1
  • 以下のようなEnvironment aws://... bootstrapped.」が表示されれば成功
    file

2.2.4.GitHub Actions用 追加ポリシー作成

  • 2.2.3.Bootstrap後に実施することで、CDKで利用するバケット名Qualifier(=CDKリソースを識別するためのID文字列)を取得
# コマンドを実行し、その結果を BUCKET_NAME 変数に代入
BUCKET_NAME=$(aws cloudformation describe-stack-resources --stack-name CDKToolkit --query "StackResources[?ResourceType=='AWS::S3::Bucket'].PhysicalResourceId" --output text --region us-east-1)

# BUCKET_NAME の中身を確認
echo "$BUCKET_NAME"

# Qualifier を抽出
YOUR_QUALIFIER=$(echo "$BUCKET_NAME" | cut -d'-' -f2)

# Qualifier の中身を確認
echo "$YOUR_QUALIFIER"

# この後、これらの変数を使って github-cdk-permissions.json を生成する
cat > github-cdk-permissions.json << EOF 
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowAssumeCdkBootstrapRoles",
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": [
                "arn:aws:iam::$AWS_ACCOUNT_ID:role/cdk-$YOUR_QUALIFIER-file-publishing-role-$AWS_ACCOUNT_ID-us-east-1",
                "arn:aws:iam::$AWS_ACCOUNT_ID:role/cdk-$YOUR_QUALIFIER-image-publishing-role-$AWS_ACCOUNT_ID-us-east-1",
                "arn:aws:iam::$AWS_ACCOUNT_ID:role/cdk-$YOUR_QUALIFIER-lookup-role-$AWS_ACCOUNT_ID-us-east-1",
                "arn:aws:iam::$AWS_ACCOUNT_ID:role/cdk-$YOUR_QUALIFIER-deploy-role-$AWS_ACCOUNT_ID-us-east-1"
            ]
        },
        {
            "Sid": "AllowPassCfnExecRole",
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "arn:aws:iam::$AWS_ACCOUNT_ID:role/cdk-$YOUR_QUALIFIER-cfn-exec-role-$AWS_ACCOUNT_ID-us-east-1"
        }
    ]
}
EOF

# IAMポリシーを作成
POLICY_ARN=$(aws iam create-policy \
    --policy-name GitHubAction-AssumeCdkRoles \
    --policy-document file://github-cdk-permissions.json \
    --query 'Policy.Arn' \
    --output text)

# ロールにアタッチ
aws iam attach-role-policy \
    --role-name GitHubAction-AssumeRoleWithAction \
    --policy-arn "$POLICY_ARN"

2.2.5.ECRのリポジトリポリシー設定

# ECRリポジトリポリシー作成
cat > ecr-policy.json << EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "LambdaECRImageRetrievalPolicy",
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": [
        "ecr:BatchGetImage",
        "ecr:GetDownloadUrlForLayer"
      ],
      "Condition": {
        "StringLike": {
          "aws:sourceArn": "arn:aws:lambda:us-east-1:$AWS_ACCOUNT_ID:function:*"
        }
      }
    },
    {
      "Sid": "AllowGitHubActionsPush",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::$AWS_ACCOUNT_ID:role/GitHubAction-AssumeRoleWithAction"
      },
      "Action": [
        "ecr:CompleteLayerUpload",
        "ecr:UploadLayerPart",
        "ecr:InitiateLayerUpload",
        "ecr:BatchCheckLayerAvailability",
        "ecr:PutImage"
      ]
    }
  ]
}
EOF

# ECR リポジトリポリシーへ設定
aws ecr set-repository-policy \
    --repository-name cdk-${YOUR_QUALIFIER}-container-assets-${AWS_ACCOUNT_ID}-us-east-1 \
    --policy-text file://ecr-policy.json \
    --region us-east-1

2.3.GitHubにて環境変数の保存

  • Web GitHubでの操作

  • GitHubのリポジトリに「Settings」→「Secrets and variables」→「Actions」を選択

file

  • 次に、Repository secrets の「New repository secret」を選択

file

  • シークレットを登録
    AWS_ACCOUNT_ID:AWSのアカウントID(12桁)を貼り付け

3.おわりに

今回は第1回 概要とAWS事前準備編を記載しました。

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

  • OIDC認証でGitHub Actionsを安全にAWSに接続
  • 必要なIAMロールとポリシーを設定
  • CDK Bootstrapを実施して環境を準備
  • ECRとGitHub Secretsの初期設定完了

次回は実際のアプリケーションコード作成とCDK実装編で続きの構築をしていきたいと思います。

Last modified: 2025-05-04

Author