Lambda で外部ライブラリを使いたいとき
実行環境を Docker イメージにして ECR から実行することで実現できますが、自分でやるのはちょっと面倒です
というわけで、CircleCI に任せてしまいましょう
また、この技術を使ってアイコンを手書きで探せるアプリを開発しました!
ぜひ使ってみてください!
やりたいこと
ローカルで作った Lambda 用のコンテナを、GitHub の main ブランチにプッシュしたら Lambda へ自動デプロイされるようにしたい
フロー
- GitHub の main ブランチの更新を CircleCI が感知
- CircleCI のコンテナ内で Docker イメージをビルド
- Docker イメージを ECR へプッシュ
- Serverless が ECR のイメージを使って Lambda へデプロイ
実装
ECR にリポジトリ作成
ECR のプライベートリポジトリを作成しておきます
リポジトリ名はCircleCI の環境変数に入れるので控えておいてください
IAM ユーザー作成
serverless 用の IAM ユーザーを作成します
プログラムによるアクセスを許可し、アクセスキーとシークレットアクセスキーを控えておきましょう
CircleCI の環境変数設定
- AWS_ACCOUNTID:AWS のアカウントID
- AWS_ACCESS_KEY_ID:IAM のアクセスキー
- AWS_SECRET_ACCESS_KEY:IAM のシークレットアクセスキー
- AWS_DEFAULT_REGION:リージョン
- FUNC_NAME:先ほど作成した ECR のリポジトリ名と同じにする
ファイル構成
project
├── .circleci
│ └── config.yml
├── app.py
├── Dockerfile
├── requirements.txt
└── serverless.yml
app.py
TensorFlow を入れて動作確認
import tensorflow as tf
def handler(event, context):
return {
'statusCode': 200,
'body':
{
'predict': tf.__version__,
}
}
Dockerfile
AWS のパブリックイメージからビルドしていきます
FROM public.ecr.aws/lambda/python:3.8
COPY . ${LAMBDA_TASK_ROOT}
RUN pip install -r requirements.txt
CMD ["app.handler"]
requirements.txt
必要なライブラリを書いておきましょう
tensorflow==2.5.0
serverless.yml
Lambda にデプロイする用の設定を書きます
ECR_DIGEST
の環境変数は、ECR にプッシュしたとき返ってくるダイジェストを入れておきます
プッシュ時に決まるので、その時に環境変数に入れるようにします
service: ecr-lambda-test
provider:
name: aws
stage: dev
region: ${env:AWS_DEFAULT_REGION}
functions:
hoge:
# ECR のプライベートリポジトリからビルドする
image: ${env:AWS_ACCOUNTID}.dkr.ecr.${env:AWS_DEFAULT_REGION}.amazonaws.com/${env:FUNC_NAME}@${env:ECR_DIGEST}
memorySize: 2048
timeout: 180
.circleci/config.yml
イメージは docker を使用しました
これは コンテナ内で Docker ビルドが出来るように整えられている Alpine ベースのイメージです
本当は amazon/aws-cli を使いたかったのですが、Docker ビルドがうまくいかなかったのでこちらを採用しています
version: 2.0
jobs:
deploy_lambda_test:
docker:
- image: docker:19
steps:
# GitHub のリポジトリを持ってくる
- checkout
# Docker でビルドなどを行うためのセットアップ
- setup_remote_docker
- run:
# serverlessをインストール。node が必要なのでそれも込み。あと IAM 情報も登録しておく。
name: serverless install
command: |
apk add --no-cache nodejs npm
npm install -g serverless
serverless config credentials --provider aws --key ${AWS_ACCESS_KEY_ID} --secret ${AWS_SECRET_ACCESS_KEY}
- run:
# aws cli をインストール。alpine には curl が無いのでまずそれをインストールする。
name: aws install
command: |
apk --no-cache add binutils curl
curl -sL https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-2.33-r0.apk
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-bin-2.33-r0.apk
apk add --no-cache glibc-2.33-r0.apk glibc-bin-2.33-r0.apk
curl -sL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip
unzip -q awscliv2.zip
aws/install
aws --version
- run:
# aws の認証を得る。パブリックイメージとプライベートリポジトリの両方。
name: aws auth
command: |
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
aws ecr get-login-password | docker login --username AWS --password-stdin ${AWS_ACCOUNTID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com
- run:
# ビルドしてデプロイ。ECR にプッシュするとダイジェストが返ってくるので、それを環境変数に追加する。(serverless が使う)
name: build image & deploy
command: |
docker build -t ${FUNC_NAME} .
docker tag ${FUNC_NAME} ${AWS_ACCOUNTID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${FUNC_NAME}
export ECR_DIGEST=`docker push ${AWS_ACCOUNTID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${FUNC_NAME} | grep digest | cut -d ' ' -f3`
echo ${ECR_DIGEST}
serverless deploy
workflows:
version: 2
build_and_deploy:
jobs:
- deploy_lambda_test:
filters:
branches:
# main ブランチのみ
only: main
完成
お疲れ様でした
あとは GitHub の main ブランチにプッシュすれば自動的にデプロイされます!
GitHub
コード全体を上げているので良かったらどうぞ