3
1

More than 1 year has passed since last update.

CodeBuildとSAMを組み合わせてLambdaを自動デプロイする

Posted at

背景

複数のLambdaで構成されているサーバレスアプリにて、Lambdaのデプロイをコンソールから行なっていました。
時間がかかるのとオペミスのリスクがあったのでCodeCommitにpushするとAWS SAMで自動デプロイが行われるデプロイパイプラインを構築しました。

SAMの初歩的なことはこちら
上記のSAM操作をCodeBuildにて行う、というイメージです。

全体図

CodeCommit→CodePipeline→CodeBuildでSAMを起動してデプロイという流れ
CodeBuildが肝になってきます
Image from Gyazo

CodePipelineとCodeBuildの準備

CodePipelineの準備

パイプラインを新規作成する
ソースプロバイダーをGitHubやCodeCommitの任意のブランチに設定

CodeBuildに変更されたファイルを伝えるため、完全クローンを選択する

Image from Gyazo

CodeBuildの準備

ビルドステージでビルドプロジェクトを作成する
環境変数にbuildspec.ymlで使用するS3_BUCKETを設定する

Image from Gyazo

CodeBuildロールにCodeCommitやS3やCloudFormation、作成AWSリソースの権限を設定する
ハマりポイント!💡

Image from Gyazo

ビルドステージで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でのデプロイを担当する

buildspec.yml
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関数コード

index.js
// テスト用 ただ '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テンプレートファイル

template.yaml
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のコンフィグファイル

samconfig.toml
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がアクセスする範囲が広くて何度もリトライしました🥲
ざっと必要だった権限をつけましたが、アクセス範囲が広すぎるのでどうしようか検討中です。

Image from Gyazo

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1