tl;dr
社内に Serverless Framework を使って実装したサーバーレスアプリケーションが増えつつあるので, 福岡で最も CircleCI を愛しているであろう企業で働く者として, CircleCI から Lambda に \デプローイ// してみることにしました. あくまでも, この記事は三ヶ月後の自分に向けての内容が多く含まれており, もしかすると, 全く以て汎用的ではないかもしれません.
この記事は JAWS-UG 福岡 もくもく会 #33 〜愛サンサンと〜 で書きました.
\\デプローイ//
\\デプローイ// したいアプリケーション
要件
deployment/xx
というブランチがついている時だけ, Lambda にデプロイする- 上記以外はテストのみ実行
.circleci/config.yml
.circleci/config.yml は以下のように書きました.
--- version: 2.1 jobs: build: docker: - image: circleci/python:3.6.8-jessie working_directory: ~/work steps: - checkout - restore_cache: keys: - v1-dependencies-{{ checksum "requirements.txt" }} - v1-dependencies- - run: name: install dependencies command: | python3 -m venv venv . venv/bin/activate make init - save_cache: paths: - ./venv key: v1-dependencies-{{ checksum "requirements.txt" }} - run: name: run tests command: | . venv/bin/activate make test - store_artifacts: path: test-reports destination: test-reports deploy: docker: - image: circleci/python:3.6.8-jessie working_directory: ~/work steps: - checkout - run: name: Install Dependency Package (nodejs, npm) command: | curl -sL https://deb.nodesource.com/setup_10.x | sudo bash - sudo apt-get install -y nodejs - restore_cache: keys: - v1-dependencies-{{ checksum "package.json" }} - v1-dependencies- - run: name: Install Serverless Framework command: | sudo npm install -g serverless - run: name: Install Serverless Framework's some plugins command: | npm install - save_cache: paths: - node_modules key: v1-dependencies-{{ checksum "package.json" }} - run: name: Deploy command: | case ${CIRCLE_BRANCH} in "deployment/dev" ) DEPLOY_STAGE="dev" ;; "deployment/production" ) DEPLOY_STAGE="prd" ;; esac sls deploy --stage=${DEPLOY_STAGE} workflows: pr-build: jobs: - build: filters: branches: ignore: - /deployment\/.*/ dev-deploy: jobs: - deploy: filters: branches: only: - deployment/dev prd-deploy: jobs: - deploy: filters: branches: only: - deployment/prd
長めの YAML ですが, とてもシンプルな内容になりました. Docker イメージは色々あって circleci/python:3.6.8-jessie を使っています. make
コマンドで実行している部分を適宜読み替えて頂くことで, Python を使った他のプロジェクトにも流用は可能です. 今回の Makefile は以下のような内容です.
help: ## ヘルプを表示する @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' init: ## pip install を実行 @npm install && python3 -m venv venv && . venv/bin/activate && pip install -r requirements.txt deploy-dev: ## sls deploy を実行 (dev 環境) @sls deploy --stage=dev -v deploy-prd: ## sls deploy を実行 (prd 環境) @sls deploy --stage=prd -v test: ## pytest を実行 @python3 -m venv venv && . venv/bin/activate && pytest -p no:warnings yamllint: ## yamllint を実行 @python3 -m venv venv && . venv/bin/activate && yamllint serverless.yml invoke-dev: ## sls invoke を実行 (dev 環境) @sls invoke --stage=dev --function=rotation --path=invoke.json invoke-prd: ## sls invoke を実行 (dev 環境) @sls invoke --stage=prd --function=rotation --path=invoke.json
invoke.json は関数に動的に渡したい JSON を設定しています.
AWS の認証情報
Lambda へのデプロイ, AWS の各種リソースを操作する為に IAM ユーザーをこさえました. ポリシー主に以下のようなポリシーを適用しています.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "apigateway:GET", "apigateway:POST", "apigateway:PUT", "apigateway:DELETE", "cloudformation:CreateStack", "cloudformation:Describe*", "cloudformation:ValidateTemplate", "cloudformation:UpdateStack", "cloudformation:List*", "ec2:CreateNetworkInterface", "ec2:Describe*", "ec2:DeleteNetworkInterface", "iam:GetRole", "iam:PassRole", "iam:CreateRole", "iam:DeleteRole", "iam:CreateServiceLinkedRole", "iam:DetachRolePolicy", "iam:PutRolePolicy", "iam:AttachRolePolicy", "iam:DeleteRolePolicy", "lambda:*", "s3:CreateBucket", "s3:DeleteObject", "s3:GetObject", "s3:GetBucketLocation", "s3:ListBucket", "s3:PutObject", "s3:DeleteBucket", "s3:GetEncryptionConfiguration", "s3:PutEncryptionConfiguration", "logs:Describe*", "logs:CreateLogGroup", "logs:DeleteLogGroup", "events:PutRule", "events:DescribeRule", "events:PutTargets" ], "Resource": "*" } ] }
もしかしたら, これでは冗長かもしれません (apigateway:*
あたりは不要かも) し, 不足しているかもしれません. Serverless Framework によって作成される AWS リソースによって調整する必要があると思います. 特筆すべきなのは, 今回は VPC 内で Lambda を動かす為, ec2:*
周りを設定している点です.
Lambda Layers
CircleCI を離れて, Serverless Framework の話です.
サードパーティー製のパッケージを毎回 zip で固めてアップロードする生活を送っていましたが, Lambda Layers に切り替えました. また, Python の場合, serverless-python-requirements という requirements.txt に書かれたパッケージをバンドルしてくれる便利プラグインが個人的なデファクトですが, このプラグインが Lambda Layers に対応していて, 以下のように設定するだけでした.
... custom: pythonRequirements: dockerizePip: 'non-linux' layer: true ...
macOS 上で開発やデプロイを進める場合には, dockerizePip
を true
にしておいて Docker を使ってパッケージをビルドさせる必要があります.
Docker イメージの妥協
circleci/python:3.6.8-jessie ではなく, circleci/python:3.7.1-stretch を使いたかったんですが, elasticsearch-curator という Python モジュールをビルドしようとして失敗してしまいました. なぜだろう.
以上
あとは
適当なブランチ名でコードを修正して Github に push すればテストが動いて, deployment/xx
にマージすれば Lambda にデプロイされるはずです.