Golang製LambdaのためのCICDをGitHub Actionsで構築してみた
はじめに
はじめまして、SHIFT にて自動化アーキテクトとしてテスト自動化・DevOps 導入支援などをしています片山です。
CICD の一環で Go の Lambda を使って、
・Slack から AWS Chatbot で Lambda を呼び出せるようにする
・ Lambda から Slack 通知をする
・ Backlog チケットを更新する
というような仕組みを構築したが、肝心の Lambda を手動で deploy していたのでは意味ない・・・ という事で Lambda 関数の CICD を構築してみた。
※今回はすでに Lambda が存在する前提で、それを更新する部分を CICD で行った ※Go 言語は今回初めて触ったが、まあ他の言語で開発した事あるのもありなんとかなった。
どのようにやるのか?
CICD と言っても考え方は単純で、ローカルでやっている事を CICD 環境でやればいいだけ。なので、今回だと以下のような手順でローカルから Lambda 更新はできるのでそれを CICD 環境で実行すればいい。
1、 ローカルで Go の Lambda 用の build = zip ファイル作成と同じ手順で zip を作成
zip 作成手順はmacOS および Linux での .zip ファイルの作成を参照
2、 s3 にファイルをアップロード(今回はファイルコピーなので s3 cp )
コマンド: aws s3 cp {s3にupしたいファイル名} s3://{s3 bucket名}
3、 s3 のファイルで Lambda を更新
コマンド: aws lambda update-function-code --function-name {lambda関数名} --s3-bucket {lambdaへupするzipのあるs3bucket名} --s3-key {lambdaにupするzipファイル名}
AWS CLI の各種コマンドのリファレンスは以下。
・ aws.s3.cp
・ aws.lambda.update-function-code
※CICD の CI と CD の区切りをどこにするのか?が 1 つのポイントになり、これの定義でパイプラインの中身にの構成が変化するが、今回は継続的インテグレーション、継続的デリバリー、継続的デプロイメントの 3 つの工程があると考え、
・ CI:継続的インテグレーション、継続的デリバリー
・ CD:継続的デプロイメント
として CICD のパイプラインは構築した。
・参考:CI/CD とは
GitHub Actions
GitGub Actions の yaml は以下のようになる
name: lambda-build-deploy
on:
push:
branches: [lambda]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Go environment
uses: actions/setup-go@v2.1.3
with:
go-version: "1.16.7"
- name: go get aws lambda library
run: go get github.com/aws/aws-lambda-go/lambda
- name: go build
run: GOOS=linux go build -o main lambda.go
- name: create zip
run: zip main.zip main config.yaml
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: upload main.zip to s3
run: aws s3 cp main.zip s3://go-lambda-deploy
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: update Lambda function
run: |
aws lambda update-function-code --function-name go-lambda --s3-bucket go-lambda-deploy --s3-key main.zip\
| jq '.FunctionName, .LastUpdateStatus'
一部補足をすると・・・
・go build -o main lambda.go
build した後にできるバイナリの名前を main にしたいので -o main とし
ている(lambda.goというファイル名にしているので、指定しないと lambda というバイナリができる)
・zip main.zip main config.yaml
今回は config.yaml も Lambda 関数で読み込むので zip に取り込みたか
ったためこのようにしている
・*| jq '.FunctionName, .LastUpdateStatus'*
aws cli のリファレンスを読むと分かるが、response に Lambda 関数の
環境変数が含まれているのでここに API KEY などがあると CI の log にそ
れが出力されてしまい NG。なので jq コマンドなどで表示させる項目を
絞り込むようにする。何もしないと以下の図のようになってしまう
(※Token は新規発行しなおしたので log に出ているものは失効済み)
IAM
s3 に upload し s3 から Lambda に deploy(zip を Lambda にアップロード)するのに必要な最小限の権限は以下
・ s3
・s3:PutObject
バケットにオブジェクトを追加する権限
・s3:GetObject
Amazon S3 からオブジェクトを取得する権限
・ lambda
・UpdateFunctionCode
AWS Lambda 関数のコードを更新する権限
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject", "lambda:UpdateFunctionCode"],
"Resource": [
"arn:aws:s3:::go-lambda-deploy/main.zip",
"arn:aws:lambda:ap-northeast-1:xxxxxxxxxx:function:go-lambda"
]
}
]
}
Resource の部分についての解説としては以下。
・ aws:s3:::go-lambda-deploy/main.zip
s3 は Region・Account の指定が不要なので空白になっている(
s3:①:②:go-... の ① に Regionが、② に Account が、それぞれ本来指定
される)。ユーザがアクセス可能なリソースを、 go-lambda-deploy で
Bucket名の、 main.zip` でObject名の、指定をそれぞれしている
・ aws:lambda:ap-northeast-1:xxxxxxxxxx:function:go-lambda
ユーザがアクセス可能なリソースを、 ap-northeast-1 でRegion名の、
xxxxxxxxxx でAccount名の、 go-lambda でFunction名の、指定をそれぞ
れしている
※IAM がちゃんと働いているかを見ると、以下のコマンドは Denied される
C:\Users\xxxxx\go>aws s3 cp lambda.go s3://go-lambda-deploy
upload failed: .\lambda.go to s3://go-lambda-deploy/lambda.go An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
※今回は、S3 に Bucket を作成する(s3:CreateBucket)、Lambda を作成する(lambda:CreateFunction)など CICD の事前準備に必要な権限は記載せず、あくまで CICD のパイプラインを動かすのに必要な権限を記載している
まとめとして
今回は zip を作成して Deploy をするという方法を取ったが、AWS SAMを使ったDeploy 方法もあり、今後は SAM テンプレートを使った Deploy もやってみたい。また、CICD を AWS Code シリーズで構築するなどもできると思うのでそういった事もやってみたい。
参考文献
実際に今回の CICD を構築する上で参考にさせて頂いたサイトは以下の 3 つ。
・ AWS CLI のプロファイル切り替えをいい感じにする
・ オブジェクトのコピー
・ aws s3 cp と sync の違い | AWS CLI
__________________________________
お問合せはお気軽に
https://service.shiftinc.jp/contact/
SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/
SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/
SHIFTの導入事例
https://service.shiftinc.jp/case/
お役立ち資料はこちら
https://service.shiftinc.jp/resources/
SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/