Apex の --env オプションを使って Lambda を複数環境にデプロイする

最近仕事で必要になり,CircleCI + Apex を使って,Lambda を複数環境 (prd / stg / dev など) にデプロイできる仕組みを作ったので,実現したかったこと,工夫したことなどを紹介したいと思う.ちなみに,以前も似たような事例で CloudWatch Events + Lambda + CircleCI + Apex を使ったアーキテクチャを紹介したが,これはあくまで開発ツールの位置付けなので,複数環境の考慮が必要なく,単純に apex deploy を実行するだけの非常にシンプルな構成になっていた点が異なる.

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

エイリアスは採用しなかった

「実践 AWS Lambda」にも書いてある通り,Lambda にはエイリアスという機能があり,特定のバージョンに prd / stg / dev など,任意のエイリアスを付けて識別することができる.単純にバージョンと環境を紐付けるだけなら便利だと思うが,今回は以下の要件を満たしたいと考えていて,エイリアスで環境を識別するアプローチは採用しなかった.プロダクションで Lambda を使う場合,基本的には以下の要件はあると思う.

  • 環境ごとに異なる環境変数を設定する
  • 環境ごとに制御した IAM ロールを設定する
  • 環境ごとに異なるコンピューティングリソースを設定する

kakakakakku.hatenablog.com

複数環境デプロイ

公式ドキュメントにも記載がある通り,Apex は複数環境 (Multiple Environments) のデプロイに対応している.特に難しいことはなく,環境ごとの設定ファイルを用意して --env オプションを指定することで,環境別にデプロイを行うことができる.なお,環境ごとの設定ファイルには大きく2種類あり,粒度によって使い分けることができる.

  • project.json … 複数の Lambda 関数で共通して参照する設定ファイル
  • function.json … Lambda 関数ごとに参照する設定ファイル

今回作ったデプロイフローはザッと以下のようになる.

f:id:kakku22:20170620212838j:plain

事前作業

環境ごとに IAM ロールが必要になるため,事前に作成しておく.今回サンプルとして prd / stg / dev を作成した.

  • arn:aws:iam::00000000000:role/prd-myfunc_lambda_function
  • arn:aws:iam::00000000000:role/stg-myfunc_lambda_function
  • arn:aws:iam::00000000000:role/dev-myfunc_lambda_function

IAM ポリシーの設定は割愛するが,公式ドキュメントに Lambda のポリシーテンプレートが公開されていて,様々なユースケースを網羅しているため,非常に便利!

docs.aws.amazon.com

Apex ディレクトリ構造

Apex ディレクトリ構造は以下のようになる.project.*.json はルートディレクトリに配置して,function.*.json は Lambda 関数のメイン処理と同じディレクトリに配置している.なお,今回は2個の Lambda 関数をデプロイできるようにした(ランタイムは Python).

├── circle.yml
├── functions
│   ├── myfunc1
│   │  ├── function.dev.json
│   │  ├── function.prd.json
│   │  ├── function.stg.json
│   │  ├── main.py
│   │  └── requirements.txt
│   └── myfunc2
│       ├── function.dev.json
│       ├── function.prd.json
│       ├── function.stg.json
│       ├── main.py
│       └── requirements.txt
├── project.dev.json
├── project.prd.json
└── project.stg.json

project.*.jsonfunction.*.json

設定項目としては同じで,粒度が異なるだけなので,今回は project.dev.json を例に載せる.

{
  "name": "dev-myfunc",
  "description": "dev-myfunc",
  "memory": 128,
  "timeout": 5,
  "role": "arn:aws:iam::00000000000:role/dev-myfunc_lambda_function",
  "environment": {
    "XXX": "xxx",
    "YYY": "yyy",
    "ZZZ": "zzz"
  }
}

このように設定することで,今回の要件を全て満たすことができた.

  • 環境ごとに異なる環境変数を設定する
  • 環境ごとに制御した IAM ロールを設定する
  • 環境ごとに異なるコンピューティングリソースを設定する

デプロイする

残るはデプロイするだけとなる.

$ apex deploy --env prd
$ apex deploy --env stg
$ apex deploy --env dev

CircleCI で自動デプロイ

今回も CircleCI で自動デプロイをできるようにした.以下にサンプルの circle.yml を載せておく.これで,プルリクを出すと dev / stg 環境にデプロイされて,master にマージをすると dev / stg / prd 環境にデプロイされる.便利!なお,テストを書かないと CircleCI でエラーになるため,今回は echo を設定して回避している.

machine:
  timezone: Asia/Tokyo

dependencies:
  post:
    - curl https://raw.githubusercontent.com/apex/apex/master/install.sh | sudo sh
    - apex version

deployment:
  prd:
    branch: master
    commands:
      - pip install --requirement functions/myfunc1/requirements.txt --target functions/myfunc1
      - pip install --requirement functions/myfunc2/requirements.txt --target functions/myfunc2
      - apex deploy --env dev
      - apex deploy --env stg
      - apex deploy --env prd
  stg_dev:
    branch: /^(?!master$).*$/
    commands:
      - pip install --requirement functions/myfunc1/requirements.txt --target functions/myfunc1
      - pip install --requirement functions/myfunc2/requirements.txt --target functions/myfunc2
      - apex deploy --env dev
      - apex deploy --env stg

test:
  override:
    - echo 'ok'

まとめ

  • Apex 本当に便利!
    • API Gateway / DynamoDB なども必要なら Serverless Framework や AWS SAM なども候補になる
  • Apex の --env オプションを使うと Lambda を複数環境にデプロイすることができる
  • 環境変数,IAM ロール,コンピューティングリソースを環境ごとに設定ファイルで変えることもできる

コントリビュート

公式ドキュメントを見ていたら --env の部分が -env になっていて,検索できずハマったので,修正のプルリクを投げたらすぐにマージしてもらえた!やった!

github.com