5
9

More than 1 year has passed since last update.

CircleCI + Serverless でコンテナ環境を AWS Lambda に自動デプロイ

Last updated at Posted at 2021-06-07

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 にプッシュしたとき返ってくるダイジェストを入れておきます
プッシュ時に決まるので、その時に環境変数に入れるようにします

serverless.yml
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 ビルドがうまくいかなかったのでこちらを採用しています

.circleci/config.yml
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

コード全体を上げているので良かったらどうぞ

参考

Alpine ベースのコンテナイメージで AWS CLI v2 を使う

5
9
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
5
9