# 初期設定など
以下の記事を参照してください
tatsumiyamamoto.com
https://tatsumiyamamoto.com/articles/26f8b7bfea6243
# 作るもの
以下のような CI を作ります
- github に push
- codebuild のマネコンの「ビルド開始」を押す(もしくは aws コマンドから起動する)
- codebuild が github の特定のリポジトリの main ブランチを参照し、Dockerfile がビルドされ、イメージが ECR に置かれ、lambda にデプロイされる
# lambda にデプロイするイメージの作成
lambdan にデプロイしたいイメージを作っていきます
src/app.py
import sys
def handler(event, context) -> str:
return "Hello from AWS Lambda using Python" + sys.version + "!"
src/Dockerfile
FROM public.ecr.aws/lambda/python:3.10
COPY requirements.txt ./
RUN pip3 install -r requirements.txt --target "${LAMBDA_TASK_ROOT}"
COPY app.py ${LAMBDA_TASK_ROOT}
CMD ["app.handler"]
# コンテナの動作テスト
以下のようなコマンドを実行します
ローカルでdockerのテスト
docker build . -t test
docker run --rm -it -p 9000:8000 test
localhost の 9000 番ポートの以下のエンドポイントに対してリクエストを送ることで、ローカルでの lambda の実行テストができます
ローカルでlambdaの実行テスト
curl -X POST http://localhost:9000/2015-03-31/functions/function/invocations -d {} # lambdaの呼び出し
Lambda コンテナイメージをローカルでテストする - AWS Lambda
Runtime Interface Emulator を使用して、AWS Lambda 関数のコンテナイメージをローカルでテストします。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images-test.html
# aws-cdk のコード
ざっと、こんな感じになったというのを書いてみます aws-cdk のベストプラクティス的なものを知らないので、よりいいやり方があれば教えてください
cdk/libs/ecr-stack.ts
import {
App,
Duration,
RemovalPolicy,
Stack,
StackProps,
aws_codebuild,
aws_ecr,
aws_iam,
aws_lambda,
} from 'aws-cdk-lib';
import 'dotenv/config'; # 環境変数の読み込み
const REGION = process.env.AWS_DEFAULT_REGION ?? '';
const ACCOUNT_ID = process.env.AWS_ACCOUNT_ID ?? '';
const OWNER = process.env.GITHUB_OWNER ?? '';
const REPO = process.env.GITHUB_REPO ?? '';
const BRANCH = process.env.GITHUB_BRANCH ?? '';
export class EcrStack extends Stack {
constructor(scope: App, id: string, props?: StackProps) {
super(scope, id, props);
const ecr = new aws_ecr.Repository(this, 'ZennCdkRepository', {
repositoryName: 'zenn-cdk-repository',
removalPolicy: RemovalPolicy.DESTROY, // スタック削除時(npx cdk destroy実行時)にrepositoryも削除
autoDeleteImages: true, // repository削除時にcontainer imageも削除
});
// buildSpecをjsのオブジェクト形式で記述する
const buildSpec = {
version: '0.2',
phases: {
pre_build: {
commands: [
'echo "Logging in to Amazon ECR..."',
'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',
],
},
build: {
commands: [
'echo "Building the Docker image..."',
'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',
],
},
post_build: {
commands: [
'echo "Pushing the Docker image..."',
'docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/zenn-cdk-repository:latest',
// lambdaはecrにimageがないと失敗するので、初回はコメントアウトなどして対応する
// なにかいい方法があれば教えてください
'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',
],
},
},
};
const codebuildRole = new aws_iam.Role(this, 'ZennCdkCodebuildRole', {
roleName: 'zenn-cdk-codebuild-role',
assumedBy: new aws_iam.ServicePrincipal('codebuild.amazonaws.com'),
});
// ecrへのアクセス権限をcodebuildに付与
codebuildRole.addManagedPolicy(
aws_iam.ManagedPolicy.fromAwsManagedPolicyName(
'AmazonEC2ContainerRegistryPowerUser',
),
);
// lambdaのupdate権限をcodebuildに付与(めんどいのでフルアクセスをつけている)
codebuildRole.addManagedPolicy(
aws_iam.ManagedPolicy.fromAwsManagedPolicyName('AWSLambda_FullAccess'),
);
const codebuild = new aws_codebuild.Project(this, 'ZennCdkCodebuild', {
projectName: 'zenn-cdk-codebuild',
source: aws_codebuild.Source.gitHub({
owner: OWNER,
repo: REPO,
branchOrRef: BRANCH,
webhook: false, // GitHubからのWebhookを無効化
}),
buildSpec: aws_codebuild.BuildSpec.fromObject(buildSpec),
environment: {
privileged: true, // dockerを動かすのでsudo権限を付与
buildImage: aws_codebuild.LinuxBuildImage.STANDARD_7_0, // Dockerfileをどのイメージ上でビルドするか
environmentVariables: {
AWS_ACCOUNT_ID: {
type: aws_codebuild.BuildEnvironmentVariableType.PLAINTEXT,
value: ACCOUNT_ID,
},
AWS_DEFAULT_REGION: {
type: aws_codebuild.BuildEnvironmentVariableType.PLAINTEXT,
value: REGION,
},
},
},
role: codebuildRole,
cache: aws_codebuild.Cache.local(
aws_codebuild.LocalCacheMode.DOCKER_LAYER,
),
});
// lambdaはecrにimageがないと失敗するので、初回はコメントアウトなどして対応する(なにかいい方法があれば知りたい...)
const lambda = new aws_lambda.Function(this, 'ZennCdkLambda', {
functionName: 'zenn-cdk-lambda',
code: aws_lambda.Code.fromEcrImage(ecr, {
cmd: ['app.handler'],
tagOrDigest: 'latest',
}),
runtime: aws_lambda.Runtime.FROM_IMAGE,
handler: aws_lambda.Handler.FROM_IMAGE,
timeout: Duration.seconds(3),
});
}
}
# ECR にイメージがないと lambda のデプロイが失敗する
初回は ECR に何もイメージないので、lambda をデプロイする際に「イメージないやんけ!」みたいなエラーが発生します。 イメージがあったらそっち、なかったらデフォルトのイメージ?みたいな切り替えができればなあと思っています(やり方知っている方いれば教えてほしいです)
lambdaのデプロイが失敗する
// lambdaはecrにimageがないと失敗するので、初回はコメントアウトなどして対応する(なにかいい方法があれば知りたい...)
const lambda = new aws_lambda.Function(this, "ZennCdkLambda", {
functionName: "zenn-cdk-lambda",
code: aws_lambda.Code.fromEcrImage(ecr, {
cmd: ["app.handler"],
tagOrDigest: "latest",
}),
runtime: aws_lambda.Runtime.FROM_IMAGE,
handler: aws_lambda.Handler.FROM_IMAGE,
timeout: Duration.seconds(3),
});
# 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.
https://maku.blog/p/vx5ta85/
多分上のコードは環境変数的にいいやり方ではないのですが、学習用のコードだったのでまあいっかと…
# github との連携には以下の手順が必要
github と codebuild の連携には以下の手順が事前に必要です github から token を発行し以下のコマンドを実行します
codebuildの初回設定
aws codebuild import-source-credentials --server-type GITHUB --auth-type PERSONAL_ACCESS_TOKEN --token <token_value>
docs.aws.amazon.com
https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_codebuild-readme.html
# デプロイ
デプロイ
npx cdk deploy # lambdaが初回イメージがないとエラーになるので注意
git add -A
git commit -m 'aws-cdkのテストをする '
git push
# codebuild のビルドを開始する
マネコンから「ビルド開始」を押すか、以下のコマンドを実行します
ビルド開始コマンド
aws codebuild start-build --project-name zenn-cdk-codebuild
codebuild が成功したら lambda のテストをして終了です
# お片付け
stuckを削除する
npx cdk destroy