トレタ Advent Calendar 2020 5日目の記事です。
はじめに
はじめまして。2020年4月からSREチームにJOINしたbutadoraと申します。
入社日から即フルリモートでなれない部分もありましたが、気づけばもう年末であっという間の1年だったなと感じるこの頃です。
さて、今回はAPI Gateway+LambdaでREST APIを構築するにあたり、 lambrollというデプロイツールを利用したデプロイフローを採用したため、紹介させていただきます。
lambrollとは
lambrollはfujiwaraさんによって作成されたLambdaのデプロイツールです。
一方lambrollはLambdaリソースに特化しており、 1コマンドでコードのアップロード準備〜デプロイをやってくれます。 大まかなデプロイの流れは以下のとおりです。
- デプロイ対象ディレクトリのzipアーカイブ
- zipファイルのアップロード(to S3)
- Lambda functionの(作成&)更新
- currentタグの(作成&)エイリアス更新
lambroll開発の経緯やクイックスタートはfujiwaraさんのブログにまとまっているためそちらをご参照ください。
ディレクトリ構成
最終的な構成としては以下のようになりました。
. ├── bin/ # go biuldのバイナリデータ出力先ディレクトリ ├── .gitignore ├── .lambdaignore # lambdaアーカイブ時に除外するディレクトリ ├── function.production.json # production環境のLambda(lambroll)設定ファイル ├── function.staging.json # staging環境のLambda(lambroll)設定ファイル ├── go.mod # goプログラムの依存モジュール管理ファイル ├── go.sum # goプログラムの依存モジュールのチェックサム管理ファイル └── main.go # goプログラム本体のファイル
- 今回はgoで書かれているため、ビルド後のファイル置き場(空ディレクトリ)を用意
- function.jsonはfunction.環境名.jsonそれぞれに書き分けて
--function
オプションで切り替え
CI/CD
デプロイフローを実現するために追加した設定を書いていきます。
必要な権限(IAM Policy)
lambrollはAWS Lambda APIを利用している。
lambroll deploy
を実行するためには以下のようなIAM Policyが必要となります。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:PassRole" ], "Resource": "arn:aws:iam::123456789012:role/lambda-role" }, { "Effect": "Allow", "Action": [ "lambda:CreateAlias", "lambda:CreateFunction", "lambda:GetFunction", "lambda:GetFunctionConfiguration", "lambda:ListTags", "lambda:UpdateAlias", "lambda:UpdateFunctionCode", "lambda:UpdateFunctionConfiguration" ], "Resource": "arn:aws:lambda:ap-northeast-1:123456789012:function:*" } ] }
- IAMのResourceはLambdaFunctionに割り当てるIAM Role
.circleci/confg.yml
今回はCircleCIで実現しました。configの一部を抜粋して紹介します。
version: 2.1 orbs: lambroll: fujiwara/lambroll@0.0.7 executors: golang: docker: - image: cimg/go:1.14 auth: username: $DOCKERHUB_USER password: $DOCKERHUB_PASSWORD commands: function_build: parameters: function_dir: type: string steps: - run: name: create persistent dir command: mkdir -p /tmp/lambroll-api/<<parameters.function_dir>>/bin - run: name: go build command: "GOOS=linux GOARCH=amd64 go build -ldflags='-s -w' -o /tmp/lambroll-api/<<parameters.function_dir>>/bin/main ./main.go" working_directory: "functions/<<parameters.function_dir>>" lambroll_init: steps: - lambroll/install: version: v0.9.1 jobs: build: executor: golang steps: - checkout - function_build: function_dir: hoge-function - function_build: function_dir: fuga-function - persist_to_workspace: root: /tmp/lambroll-api paths: - hoge-function/bin/* - fuga-function/bin/* lambroll_deploy: executor: golang steps: - checkout - attach_workspace: at: functions/ - lambroll_init - run: command: lambroll deploy --src="./bin" --function="function.$ENV.json" working_directory: "functions/hoge-function" - run: command: lambroll deploy --src="./bin" --function="function.$ENV.json" working_directory: "functions/fuga-function" # workflowsは省略
- lambrollはgithubのreleaseから取ってくるだけですぐ利用できるが、Orbが用意されているためそちらを利用してインストール
- 今回はbuildに使っている
cimg/go
をそのまま利用しているが、他のコンビニエンスイメージでもインストールできるはず
- 今回はbuildに使っている
- 環境変数はCircleCIのcontextsから呼び出すようにしている。定義している環境変数は以下。
ENV
: 環境名AWS_ACCESS_KEY_ID
: lambrollデプロイ用ユーザのAWSアクセスキーAWS_SECRET_ACCESS_KEY
: lambrollデプロイ用ユーザのAWSシークレットアクセスキーAWS_REGION
: Lambdaをデプロイするリージョン
前日譚
トレタでは基本的にAWSリソースの管理にはTerraformを採用しています。 しかしながら、Lambdaに関してはzipアーカイブの用意などの事前作業が別途必要など、Terraformだけでデプロイを完結させることは難しいです。
そこで、真っ先に浮かんだのはServerless Frameworkでしたが、 Lambdaとその他リソースではデプロイフローが異なるのではないかという考えから、 シンプルにLambdaリソースだけを管理して、その他リソースはTerraformに任せる構成を模索しました。
その結果、lambrollが候補に上がり、lambrollの思想がマッチしていることやメンテナンスが継続されていることからPoCも兼ねて採用しました。
最後に
今回はサーバレスAPIの新規構築にlambrollを利用しましたが、 既存のLambda関数をlambroll管理下に置くことも容易にできるため、Serverless Frameworkからの置き換えも検討していきたいと考えています。
先日発表されたLambdaのcontainer imageにも即日対応されていたため、近々試して見ようと思います。
ということでLambdaへのcontainer imageのデプロイに対応したlambroll v0.10.0 をリリースしましたよ https://t.co/9dwPqB1zC3
— fujiwara (@fujiwara) 2020年12月2日
使い方はこのへんに軽く書いてあるけどあとでblogも書かないと… https://t.co/7zYoBdrGgF
エンジニア募集中
トレタに興味を持っていただけましたら、是非一度お話しましょう!