背景
複数のLambdaで構成されているサーバレスアプリにて、Lambdaのデプロイをコンソールから行なっていました。
時間がかかるのとオペミスのリスクがあったのでCodeCommitにpushするとAWS SAMで自動デプロイが行われるデプロイパイプラインを構築しました。
SAMの初歩的なことはこちら
上記のSAM操作をCodeBuildにて行う、というイメージです。
全体図
CodeCommit→CodePipeline→CodeBuildでSAMを起動してデプロイという流れ
CodeBuildが肝になってきます
CodePipelineとCodeBuildの準備
CodePipelineの準備
パイプラインを新規作成する
ソースプロバイダーをGitHubやCodeCommitの任意のブランチに設定
CodeBuildに変更されたファイルを伝えるため、完全クローンを選択する
CodeBuildの準備
ビルドステージでビルドプロジェクトを作成する
環境変数にbuildspec.yml
で使用するS3_BUCKET
を設定する
CodeBuildロールにCodeCommitやS3やCloudFormation、作成AWSリソースの権限を設定する
ハマりポイント!💡
ビルドステージでSAMのデプロイが完了しているのでCodePipelineのデプロイステージはスキップする
リポジトリの準備
ディレクトリ構造
$ tree
.
├── README.md
├── SAM_test-sam-a
│ ├── index.mjs
│ ├── samconfig.toml
│ └── template.yaml
├── SAM_test-sam-b
│ ├── index.mjs
│ ├── samconfig.toml
│ └── template.yaml
├── SAM_test-sam-c
│ ├── index.js
│ ├── samconfig.toml
│ └── template.yaml
└── buildspec.yml
buildspec.ymlの準備
リポジトリのルートにbuildspec.yml
を作成する
変更があったLambdaの判断、SAMでのデプロイを担当する
version: 0.2
phases:
install:
runtime-versions:
python: 3.11
commands:
- echo Installing dependencies...
- pip install toml
build:
commands:
- echo Build started...
- |
set -e # シェルスクリプトがエラーを起こしたら実行を止める
CHANGED_LAMBDA_DIRS=$(git diff --dirstat=files,0 HEAD^ HEAD | cut -d '%' -f 2 | cut -f 2 -d ' ')
for DIR in $CHANGED_LAMBDA_DIRS # 変更があったファイルをforで回してSAMデプロイする
do
if [[ $DIR = SAM_* ]] # SAMデプロイの対象かを判断
then
echo "Building and deploying $DIR..."
ORIGINAL_DIR=$(pwd)
cd $DIR
TARGET_NAME=$(python -c "import toml; print(toml.load(open('samconfig.toml'))['default']['deploy']['parameters']['stack_name'])") # samconfig.tomlからスタック名を取得
echo "TARGET_NAME $TARGET_NAME..."
sam build --template template.yaml --build-dir .aws-sam/build # ビルドしてアーティファクトを生成
echo Build done!
sam package --template-file .aws-sam/build/template.yaml --s3-bucket $S3_BUCKET --s3-prefix $TARGET_NAME --output-template-file .aws-sam/build/packaged.yaml # 生成されたアーティファクトをS3に保存
echo Package done!
sam deploy --template-file .aws-sam/build/packaged.yaml --stack-name $TARGET_NAME --s3-bucket $S3_BUCKET --config-file samconfig.toml --capabilities CAPABILITY_IAM # S3のアーティファクトから実リソースを生成
echo Deploy done!
cd $ORIGINAL_DIR
fi
done
CHANGED_LAMBDA_DIRS=$(git diff --dirstat=files,0 HEAD^ HEAD | cut -d '%' -f 2 | cut -f 2 -d ' ')
によって、どのLambdaが変更されたかを検出しています。
これを行うためには、CodePipelineのソースステージで完全クローンが必要になります。
変更があったLambdaを対象にしてSAMコマンドを実行します。
その他ローカルソースコード
Lambda関数コード
// テスト用 ただ 'Hello SAM' を出力するコード
export const handler = async (event) => {
console.log('Hello SAM C!!!!')
const response = {
statusCode: 200,
body: JSON.stringify('Hello from SAM C!!!!'),
};
return response;
};
SAMテンプレートファイル
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SAM Template for SAM_test-sam-c
Resources:
# Lambda のリソース設定
Function:
Type: AWS::Serverless::Function
Properties:
FunctionName: SAM_test-sam-c
CodeUri: .
Handler: index.handler
Runtime: nodejs16.x
Timeout: 30
Role: arn:aws:iam::<account-id>:role/service-role/SAM_test-sam-c-role-pcj1qpgb
Environment:
Variables:
ENV_1: 1
ENV_2: 'ENV2'
ENV_3: 'ENV3'
# CloudWach ロググループのリソース設定
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${Function}
RetentionInDays: 365 # ログの保存期間
# CloudFormationデプロイログ出力用
Outputs:
Function:
Description: "SAM_AmazonConnect_MIVR_GetFacilityData Lambda Function ARN"
Value: !GetAtt Function.Arn
SAMのコンフィグファイル
version = 0.1
[default.build.parameters]
debug = true
use_container = false # Lambda向けコンテナを使用するか
[default]
[default.deploy]
[default.deploy.parameters]
debug = true
stack_name = "SAM-test-sam-c"
s3_bucket = "" # CodeBuildの環境変数で設定するため不要
s3_prefix = "SAM-test-sam-c"
region = "ap-northeast-1"
confirm_changeset = false # CodeBuildからのデプロイなので変更セットを確認しないでデプロイする
capabilities = "CAPABILITY_NAMED_IAM" # 固定値 CloudFormationにスタック作成のIAM権限を与える
disable_rollback = true # デプロイ失敗時にスタックをロールバックさせる
tags = [
"env=\"pro\""
]
これで対象リポジトリにPushを行うと変更したLambdaが自動でデプロイされるようになりました!🎉🎉🎉
ハマりポイント
CodeBuildの権限設定でめためた失敗した
CodeBuildがアクセスする範囲が広くて何度もリトライしました🥲
ざっと必要だった権限をつけましたが、アクセス範囲が広すぎるのでどうしようか検討中です。
参考