AWS Lambdaのコンテナイメージサポートを使用したCI/CD環境の構築
現在では、AWS Lambdaの実行環境にコンテナイメージが利用できます。
これにより、ECSやEKSといったコンテナ系のサービスだけでなく、Lambdaでもコンテナネイティブな開発環境を作ることができます。
自分の環境では、ECSやEKSとLambdaを併用してシステムを構成することが多いので、開発環境を統一できることにはメリットがあります。
今回はLambdaの場合、どのような開発ワークフローとなるのか、CI/CD環境を構築して確認してみます。
あくまでCI/CDの一例ですので、参考にしてもらえればと思います。
なお、LambdaなどのAWSリソースの作成には、Terraformを利用します。
成果物はこちらです。
github.com
概要
今回の開発ワークフローの概要です。
GitHubのリポジトリへのコミットをトリガーにして、CodeBuildを起動します。
CodeBuildでは、リポジトリ内のDockerfileの構成に従い、コンテナイメージを作成します。
コンテナイメージをECRにPushします。
Lambda関数の更新にECRのコンテナイメージを指定します。
CI/CDの構成
環境構築
コンテナイメージの作成
初回にLambda関数を作成する際には、コンテナイメージが必要です。
そのため、以下の手順でコンテナイメージを用意します。
$ FUNCTION_NAME=aws-lambda-container-cicd-example $ REGION=$(aws configure get region) $ ACCOUNTID=$(aws sts get-caller-identity --output text --query Account) $ docker build -t ${FUNCTION_NAME} . $ aws ecr create-repository --repository-name ${FUNCTION_NAME} $ docker tag ${FUNCTION_NAME}:latest ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com/${FUNCTION_NAME}:latest $ aws ecr get-login-password | docker login --username AWS --password-stdin ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com $ docker push ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com/${FUNCTION_NAME}:latest
ECRにコンテナイメージをPushする際の標準的なやり方です。
一時的にイメージを作りたいだけなので、イメージタグにlatestを使うことを許容しています。
CodeBuildの作成
CI/CDの基盤となるCodeBuildを用意します。
Terraformのtfファイルを一部抜粋したものです。
詳細は成果物を確認ください。
... resource "aws_codebuild_project" "aws_lambda_container_cicd_example" { name = local.function_name service_role = aws_iam_role.iam_for_codebuild.arn artifacts { type = "NO_ARTIFACTS" } cache { modes = [ "LOCAL_DOCKER_LAYER_CACHE", ] type = "LOCAL" } environment { compute_type = "BUILD_GENERAL1_SMALL" image = "aws/codebuild/amazonlinux2-x86_64-standard:3.0" type = "LINUX_CONTAINER" privileged_mode = true } source { git_clone_depth = 1 insecure_ssl = false location = "https://github.com/hi1280/${local.function_name}" report_build_status = false type = "GITHUB" git_submodules_config { fetch_submodules = false } } } ...
ビルドの処理内容を決めるbuildspec.yamlです。
./scripts_build.shに処理を委譲しています。
version: 0.2 env: variables: REPOSITORY_NAME: aws-lambda-container-cicd-example phases: build: commands: - ./scripts/build.sh
./scripts/build.sh
#!/bin/sh AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text) REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${REPOSITORY_NAME} IMAGE_TAG=$(echo "${CODEBUILD_RESOLVED_SOURCE_VERSION}" | cut -c 1-7) # build 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" docker build -t "${REPOSITORY_URI}:${IMAGE_TAG}" . docker tag "${REPOSITORY_URI}:${IMAGE_TAG}" "${REPOSITORY_URI}:latest" docker push "${REPOSITORY_URI}:${IMAGE_TAG}" docker push "${REPOSITORY_URI}:latest" # deploy aws lambda update-function-code --function-name "${REPOSITORY_NAME}" --image-uri "${REPOSITORY_URI}:${IMAGE_TAG}" --publish
CODEBUILD_RESOLVED_SOURCE_VERSIONには、GitのコミットIDが入ります。コミットIDの一部をイメージタグに指定します。
ビルド部分とデプロイ部分に分けています。
ビルド部分は、ECRにコンテナイメージをPushする際の標準的なやり方です。
デプロイ部分はAWS CLIでLambdaを更新する処理を行います。
--publishを指定することで、バージョンごとにLambdaの内容が履歴に残るように更新しています。
Lambdaの作成
以下のtfファイルでLambdaを作成します。
... resource "aws_lambda_function" "aws_lambda_container_cicd_example" { function_name = local.function_name role = aws_iam_role.iam_for_lambda.arn package_type = "Image" image_uri = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${data.aws_region.current.name}.amazonaws.com/${local.function_name}:latest" lifecycle { ignore_changes = [ image_uri ] } }
package_typeでImageを指定することで、コンテナイメージを使ってLambdaを作成することになります。
image_uriはLambdaの更新ごとに変更されるため、ignore_changesを指定し、Terraformのチェックからは除外します。
まとめ
Lambdaにコンテナイメージがサポートされる前までは、効率的にLambdaを開発するために各種ツールを駆使しながら各自が工夫して、開発フローを作っていたかと思います。
コンテナイメージがサポートされたことにより、個人的にはそのあたりが明確になり、開発フローが分かりやすくなったと思います。