WebLog

aws-cdkでlambdaにコンテナをデプロイするCIを作る

2023/06/09 10:39

初期設定など

以下の記事を参照してください

aws-cdkを使ってs3+cloudfrontの静的サイトホスティングを作る | WebLog
aws-cdkを使ってs3+cloudfrontの静的サイトホスティングを作る | WebLog

aws-cdkを使ってs3+cloudfrontの静的サイトホスティングを作る | WebLog

# はじめに aws-cli が使えるようにしておきます ```bash:aws-cliのインストール brew install awscli # aws-cliのインストール aws --version # インストールされたことの

作るもの

以下のような CI を作ります

  1. github に push
  2. codebuild のマネコンの「ビルド開始」を押す(もしくは aws コマンドから起動する)
  3. codebuild が github の特定のリポジトリの main ブランチを参照し、Dockerfile がビルドされ、イメージが ECR に置かれ、lambda にデプロイされる

構成図

lambda にデプロイするイメージの作成

lambdan にデプロイしたいイメージを作っていきます

src/app.py
1import sys
2
3
4def handler(event, context) -> str:
5 return "Hello from AWS Lambda using Python" + sys.version + "!"
src/Dockerfile
1FROM public.ecr.aws/lambda/python:3.10
2
3COPY requirements.txt ./
4
5RUN pip3 install -r requirements.txt --target "${LAMBDA_TASK_ROOT}"
6
7COPY app.py ${LAMBDA_TASK_ROOT}
8
9CMD ["app.handler"]

コンテナの動作テスト

以下のようなコマンドを実行します

ローカルでdockerのテスト
1docker build . -t test
2docker run --rm -it -p 9000:8000 test

localhost の 9000 番ポートの以下のエンドポイントに対してリクエストを送ることで、ローカルでの lambda の実行テストができます

ローカルでlambdaの実行テスト
1curl -X POST http://localhost:9000/2015-03-31/functions/function/invocations -d {} # lambdaの呼び出し
Lambda コンテナイメージをローカルでテストする - AWS LambdaLambda コンテナイメージをローカルでテストする - AWS Lambda
Lambda コンテナイメージをローカルでテストする - AWS LambdaLambda コンテナイメージをローカルでテストする - AWS Lambda

Lambda コンテナイメージをローカルでテストする - AWS LambdaLambda コンテナイメージをローカルでテストする - AWS Lambda

Runtime Interface Emulator を使用して、AWS Lambda 関数のコンテナイメージをローカルでテストします。

aws-cdk のコード

ざっと、こんな感じになったというのを書いてみます aws-cdk のベストプラクティス的なものを知らないので、よりいいやり方があれば教えてください

cdk/libs/ecr-stack.ts
1import {
2 App,
3 Duration,
4 RemovalPolicy,
5 Stack,
6 StackProps,
7 aws_codebuild,
8 aws_ecr,
9 aws_iam,
10 aws_lambda,
11} from 'aws-cdk-lib';
12import 'dotenv/config'; # 環境変数の読み込み
13
14const REGION = process.env.AWS_DEFAULT_REGION ?? '';
15const ACCOUNT_ID = process.env.AWS_ACCOUNT_ID ?? '';
16const OWNER = process.env.GITHUB_OWNER ?? '';
17const REPO = process.env.GITHUB_REPO ?? '';
18const BRANCH = process.env.GITHUB_BRANCH ?? '';
19
20export class EcrStack extends Stack {
21 constructor(scope: App, id: string, props?: StackProps) {
22 super(scope, id, props);
23
24 const ecr = new aws_ecr.Repository(this, 'ZennCdkRepository', {
25 repositoryName: 'zenn-cdk-repository',
26 removalPolicy: RemovalPolicy.DESTROY, // スタック削除時(npx cdk destroy実行時)にrepositoryも削除
27 autoDeleteImages: true, // repository削除時にcontainer imageも削除
28 });
29
30 // buildSpecをjsのオブジェクト形式で記述する
31 const buildSpec = {
32 version: '0.2',
33 phases: {
34 pre_build: {
35 commands: [
36 'echo "Logging in to Amazon ECR..."',
37 'aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com',
38 ],
39 },
40 build: {
41 commands: [
42 'echo "Building the Docker image..."',
43 'docker build -t $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/zenn-cdk-repository:latest -f cdk-ecr-lambda/src/Dockerfile cdk-ecr-lambda/src',
44 ],
45 },
46 post_build: {
47 commands: [
48 'echo "Pushing the Docker image..."',
49 'docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/zenn-cdk-repository:latest',
50 // lambdaはecrにimageがないと失敗するので、初回はコメントアウトなどして対応する
51 // なにかいい方法があれば教えてください
52 'aws lambda update-function-code --function-name zenn-cdk-lambda --image $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/zenn-cdk-repository:latest',
53 ],
54 },
55 },
56 };
57
58 const codebuildRole = new aws_iam.Role(this, 'ZennCdkCodebuildRole', {
59 roleName: 'zenn-cdk-codebuild-role',
60 assumedBy: new aws_iam.ServicePrincipal('codebuild.amazonaws.com'),
61 });
62
63 // ecrへのアクセス権限をcodebuildに付与
64 codebuildRole.addManagedPolicy(
65 aws_iam.ManagedPolicy.fromAwsManagedPolicyName(
66 'AmazonEC2ContainerRegistryPowerUser',
67 ),
68 );
69
70 // lambdaのupdate権限をcodebuildに付与(めんどいのでフルアクセスをつけている)
71 codebuildRole.addManagedPolicy(
72 aws_iam.ManagedPolicy.fromAwsManagedPolicyName('AWSLambda_FullAccess'),
73 );
74
75 const codebuild = new aws_codebuild.Project(this, 'ZennCdkCodebuild', {
76 projectName: 'zenn-cdk-codebuild',
77 source: aws_codebuild.Source.gitHub({
78 owner: OWNER,
79 repo: REPO,
80 branchOrRef: BRANCH,
81 webhook: false, // GitHubからのWebhookを無効化
82 }),
83 buildSpec: aws_codebuild.BuildSpec.fromObject(buildSpec),
84 environment: {
85 privileged: true, // dockerを動かすのでsudo権限を付与
86 buildImage: aws_codebuild.LinuxBuildImage.STANDARD_7_0, // Dockerfileをどのイメージ上でビルドするか
87 environmentVariables: {
88 AWS_ACCOUNT_ID: {
89 type: aws_codebuild.BuildEnvironmentVariableType.PLAINTEXT,
90 value: ACCOUNT_ID,
91 },
92 AWS_DEFAULT_REGION: {
93 type: aws_codebuild.BuildEnvironmentVariableType.PLAINTEXT,
94 value: REGION,
95 },
96 },
97 },
98 role: codebuildRole,
99 cache: aws_codebuild.Cache.local(
100 aws_codebuild.LocalCacheMode.DOCKER_LAYER,
101 ),
102 });
103
104 // lambdaはecrにimageがないと失敗するので、初回はコメントアウトなどして対応する(なにかいい方法があれば知りたい...)
105 const lambda = new aws_lambda.Function(this, 'ZennCdkLambda', {
106 functionName: 'zenn-cdk-lambda',
107 code: aws_lambda.Code.fromEcrImage(ecr, {
108 cmd: ['app.handler'],
109 tagOrDigest: 'latest',
110 }),
111 runtime: aws_lambda.Runtime.FROM_IMAGE,
112 handler: aws_lambda.Handler.FROM_IMAGE,
113 timeout: Duration.seconds(3),
114 });
115 }
116}

ECR にイメージがないと lambda のデプロイが失敗する

初回は ECR に何もイメージないので、lambda をデプロイする際に「イメージないやんけ!」みたいなエラーが発生します。 イメージがあったらそっち、なかったらデフォルトのイメージ?みたいな切り替えができればなあと思っています(やり方知っている方いれば教えてほしいです)

lambdaのデプロイが失敗する
1// lambdaはecrにimageがないと失敗するので、初回はコメントアウトなどして対応する(なにかいい方法があれば知りたい...)
2const lambda = new aws_lambda.Function(this, "ZennCdkLambda", {
3 functionName: "zenn-cdk-lambda",
4 code: aws_lambda.Code.fromEcrImage(ecr, {
5 cmd: ["app.handler"],
6 tagOrDigest: "latest",
7 }),
8 runtime: aws_lambda.Runtime.FROM_IMAGE,
9 handler: aws_lambda.Handler.FROM_IMAGE,
10 timeout: Duration.seconds(3),
11});

aws-cdk における環境変数の扱いについて

以下の記事が参考になります

AWS CDK で外部パラメーターを扱う(コンテキスト・バリューと環境変数)|まくろぐ
AWS CDK で外部パラメーターを扱う(コンテキスト・バリューと環境変数)|まくろぐ

AWS CDK で外部パラメーターを扱う(コンテキスト・バリューと環境変数)|まくろぐ

CDK コードに外部パラメーターを与える方法 AWS CDK による CloudFormation スタックの構築時に、外部からキー&バリューの形でパラメーターを設定したいときは、主に次の 3 つの方法があります(クラウド上に値を保存するパラメーターストアなどは対象外とします)。 Context values (コンテキスト・バリュー) Environment variables (環境変数) CloudFormation parameters (CloudFormation パラメーター) S3 バケットの名前をパラメーター化したり、デプロイターゲットを staging と production の間で切り替えたりするときに使えます。 Context values(コンテキスト・バリュー) コンテキスト・バリューは、CDK 特有の仕組みで、cdk deploy 実行時のコマンドライン引数や、cdk.json ファイルの中で、キー&バリューのペアを設定することができます。 キーの型は string で、バリューの型は JSON がサポートするデータ型のいずれかです(string、number、オブジェクト、およびそれらの配列)。 コンテキスト・バリューは CDK の仕組みなので、CDK コードの中からしか参照できません。 Lambda 関数の中から値を参照したい場合は、Lambda 関数のコンストラクトを生成するときに、environment props などで間接的に渡す必要があります。 コマンドライン引数で指定する方法 cdk deploy コマンド(あるいは diff、synth)を実行するときに、--context (-c) オプションで、コンテキスト・バリューを設定できます。 $ cdk deploy --context key=value 複数のキー&バリューペアを設定したいときは、単純にオプション指定を繰り返します。 $ cdk deploy -c key1=value1 -c key2=value2 コンテキスト・バリューは CDK アプリ内の全スタックに渡されますが、特定のスタックにのみ反映させることもできます。 $ cdk deploy -c Stack1:key1=value1 -c Stack2:key2=value2 cdk.

多分上のコードは環境変数的にいいやり方ではないのですが、学習用のコードだったのでまあいっかと...

github との連携には以下の手順が必要

github と codebuild の連携には以下の手順が事前に必要です github から token を発行し以下のコマンドを実行します

codebuildの初回設定
1aws codebuild import-source-credentials --server-type GITHUB --auth-type PERSONAL_ACCESS_TOKEN --token <token_value>
aws-cdk-lib.aws_codebuild module · AWS CDK

aws-cdk-lib.aws_codebuild module · AWS CDK

Language | Package

デプロイ

デプロイ
1npx cdk deploy # lambdaが初回イメージがないとエラーになるので注意
2git add -A
3git commit -m 'aws-cdkのテストをする '
4git push

codebuild のビルドを開始する

マネコンから「ビルド開始」を押すか、以下のコマンドを実行します

ビルド開始コマンド
1aws codebuild start-build --project-name zenn-cdk-codebuild

codebuild が成功したら lambda のテストをして終了です

お片付け

stuckを削除する
1npx cdk destroy

最新の投稿