CodePiplineをつかってLambdaのデプロイフローを作成する
要件
- lambdaのビルド&デプロイフローを構築する (lambdaの言語はGo)
- Githubの
develop
,master
へのpushを検知してdeployを行いたい - Jenkinsなどをつかって自前でホスティングはしたくない。
構成図
CodeBuild
buildspec.yml
に処理手順を書きます。
今回はGo言語でのデプロイとなるので以下のようになりました。
行なっていることは
- dep ensure
- build & zip
- S3のファイルと比較して変更があった場合のみS3にupload (upload_S3.sh)
version: 0.2 env: variables: path: "src/github.com/xxx/yyy" phases: install: commands: - export GOPATH=${HOME}/go - go get github.com/golang/dep/cmd/dep - chmod +x /go/bin/dep pre_build: commands: - mkdir -p ${GOPATH}/${path} - mv * ${GOPATH}/${path}/. - cd ${GOPATH}/${path} && dep ensure build: commands: - GOOS=linux GOARCH=amd64 go build -o XXX main.go - zip XXX.zip ./XXX post_build: commands: - ./upload_s3.sh ${S3_PATH}
upload_s3.sh
やっていることは以下
* S3から既存のコードを取得
* 今回のデプロイ対象のコードと既存のコードを比較
* 差分があるファイルのみS3にアップロード
#!/bin/bash SOURCE_PATH="src/github.com/xxx/yyy" cd ${GOPATH}/${SOURCE_PATH} mkdir -p deploy cd deploy aws s3 cp s3://$1/ . --recursive changes=() for v in "ZZZ" do unzip $v.zip IS_DIFF=`diff $v ../$v | wc -l` if [ $IS_DIFF != 0 ]; then changes+=( $v ) fi done for v in ${changes[@]}; do aws s3 cp $v.zip s3://$1/ done
CodePipeline
CodePipelineでは、以下のように設定します。 (詳細は割愛)
- 名前
- ソース
- ビルド
- デプロイ
- サービスロール
デプロイ用lambda
デプロイ用lambdaでは、以下を行なっています。
- S3にアップロードされたことをhookに動作する
- S3にアップロードされたファイルをLambdaのソースとしてデプロイ
const aws = require('aws-sdk'); const s3 = new aws.S3({ apiVersion: '2006-03-01' }); const lambda = new aws.Lambda(); exports.handler = (event, context, callback) => { if (!event.Records) { callback(null, null); } event.Records.forEach(record => { const key = decodeURIComponent(record.s3.object.key.replace(/\+/g, ' ')); const s3params = { Bucket: record.s3.bucket.name, Key: key, }; s3.getObject(s3params, (err, data) => { if (err) { callback(`Error getting object ${key}. Make sure they exist and your bucket is in the same region as this function.`); } else { const fileName = key.replace('.zip', '') const lambdaParams = { FunctionName: "functionName", S3Bucket: record.s3.bucket.name, S3Key: key }; lambda.updateFunctionCode(lambdaParams, (err, res) => { if (err) { console.log(err, err.stack); } else { console.log(res) } }); callback(null, data.ContentType); } }); }) };