CDK + Lambdaの開発フローをGitHub Actionsで構築する
依存性の管理
aws_lamdba
とは別にaws_lambda_python
があり、venv, pipenv, poetryそれぞれでの依存ライブラリの自動インストールに対応している。
poetry
公式APIリファレンスのModule Dependenciesに記載の通りだが、各Functionのディレクトリにpyproject.toml
とpoetry.lock
があればOK。
.
├── lambda_function.py # exports a function named 'handler'
├── pyproject.toml # has to be present at the entry path
├── poetry.lock # your poetry lock file
poetry自体学習中なので正しいやり方か自信はないが、各Functionごとにpoetry initで別々に依存関係を管理する場合には以下のような流れになる。
# functionのディレクトリに移動
cd sample_lambda_dir
# poetryのプロジェクトをセットアップ
poetry init
# ライブラリの追加
poetry add requests
# デプロイの実行
cdk deploy
すると、cdk deploy
時に設定ファイルを見て自動でライブラリがインストールされていることが確認できる。
#12 [7/7] RUN [ -f 'Pipfile' ] && pipenv lock -r >requirements.txt; [ -f 'poetry.lock' ] && poetry export --with-credentials --format requirements.txt --output requirements.txt; [ -f 'requirements.txt' ] && pip install -r requirements.txt -t .;
#12 sha256:a72a89fe061d6e76d239058139abe393325aad12b02ee66eb01ad1eb9e8e1397
#12 0.874 Collecting certifi==2020.12.5
#12 0.876 Using cached certifi-2020.12.5-py2.py3-none-any.whl (147 kB)
#12 0.893 Collecting chardet==4.0.0
#12 0.894 Using cached chardet-4.0.0-py2.py3-none-any.whl (178 kB)
#12 0.923 Collecting idna==2.10
#12 0.924 Using cached idna-2.10-py2.py3-none-any.whl (58 kB)
#12 0.976 Collecting requests==2.25.1
#12 0.977 Using cached requests-2.25.1-py2.py3-none-any.whl (61 kB)
#12 1.017 Collecting urllib3==1.26.3
#12 1.018 Using cached urllib3-1.26.3-py2.py3-none-any.whl (137 kB)
#12 1.202 Installing collected packages: urllib3, idna, chardet, certifi, requests
#12 1.464 Successfully installed certifi-2020.12.5 chardet-4.0.0 idna-2.10 requests-2.25.1 urllib3-1.26.3
#12 DONE 1.5s
aws_lambda_python
CDKの基本
基本的なコマンド
- cdk synth
- CDKのコードからCloudFormationのコードを出力する
- cdk diff
- 差分を
- cdk bootstrap
- cdkで利用する環境(デプロイ用のS3バケットなど)を作成するためのコマンド
Lambdaの定義
Workshopのコードほぼそのままだが、aws_lambda
を使って関数の定義をしてあげればOK
#!/usr/bin/env python3
from aws_cdk import core
from resources.awslambda.infra.python_lambda_stack import CDKSample
app = core.App()
# PythonFunction(app, 'hello')
CDKSample(app, "cdkworkshop", env={'region': 'ap-northeast-1'})
app.synth()
from aws_cdk import (
core,
aws_lambda as _lambda,
)
class CDKSample(core.Stack):
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
# Defines an AWS Lambda resource
my_lambda = _lambda.Function(
self, 'HelloHandler',
runtime=_lambda.Runtime.PYTHON_3_7,
code=_lambda.Code.asset('../cdk/resources/awslambda/functions/twitter'),
handler='hello.handler',
)
GitHub Actionsでの実行
Securityに関する確認
LambdaにX-Rayの設定を後から追加してGitHub Actionsで実行したところ以下のメッセージが表示されJobがエラーになった。
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:
IAM Statement Changes
┌───┬──────────┬────────┬──────────────────────────┬───────────────────────────────┬───────────┐
"--require-approval" is enabled and stack includes security-sensitive updates, but terminal (TTY) is not attached so we are unable to get a confirmation from the user
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼──────────┼────────┼──────────────────────────┼───────────────────────────────┼───────────┤
│ + │ * │ Allow │ xray:PutTelemetryRecords │ AWS:${MyFunction/ServiceRole} │ │
│ │ │ │ xray:PutTraceSegments │ │ │
└───┴──────────┴────────┴──────────────────────────┴───────────────────────────────┴───────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)
CDKのドキュメントに記載されている通りSecurityに関連した変更が発生した場合には設定値に応じて承認を求められる。
GitHub CIではもちろんターミナルでの入力ができないので、それが原因でエラーが発生してしまった。
ドキュメントに記載されている限りでは以下3種類の設定を行うことができる。
設定値 | 説明 |
---|---|
never | 承認を求めない |
any-change | IAMかSecurity Groupに関連した変更がある場合には必ず承認を求める |
broadening | IAM StatementかTraffic Rulesが追加された場合に承認を求める。削除の場合には求めない |
設定自体はcdk.json
に記載すればOKのようだ。
{
"app": "...",
"requireApproval": "never"
}
CDKで使用する言語
Lambda等の開発のために使用していたため混乱してしまったが、CDK自体はTypeScriptで書かれたもの。(npm install -g aws-cdk
でインストールする)
そのため、Pythonを使ってLambdaを構築する場合でも以下大きく分けて2通りの選択肢がある。
- Lambdaの開発言語はPython、CDK自体の定義はPython
- Lambdaの開発言語はPython、CDK自体の定義は別言語(TypeScript、Ruby等)
Lambdaの開発言語をPythonにする関係上CDKの定義もPythonを使用するつもりだったが、以下の点を考慮すると特別な理由がない限りTypeScriptを使った方がいい気がしてきた。
- 事例が豊富
- 公式ドキュメントやQiita等の記事での実例は大抵がTypeScriptで書かれており、単純に参考となる情報が豊富(Pythonで書こうとすると公式ドキュメントを見て書き換える手間が発生する)
- 環境が整っている(整うのが早い)
- 十分な調査をしたわけではないが以下のテストに関する例やCDK自体がTypeScriptで書かれていることを考えるとライブラリ等の周辺環境はTypeScriptが最も充実したものになると考えられる
-
Currently, TypeScript is the only supported language for testing AWS CDK infrastructure, though we intend to eventually make this capability available in all languages supported by the AWS CDK. Testing constructs
参考資料
CDK TypeScriptでのエラー
Argument of type 'this' is not assignable to parameter of type 'Construct'.
Template作成時にインストールされたCDKのバージョンと追加でインストールしたCDK関係(@aws-cdk/aws-lambda
等)でバージョンの不整合があるとこのエラーが発生してしまうみたい。
以下の記事を参考にpackage.json
に記載されたライブラリのバージョンを合わせたらエラーが解消した。
AWS CDK の Argument of type 'this' is not assignable to parameter of type 'Construct'. エラーの対応方法
GitHub Actionsのローカル実行
actというライブラリを使用してローカルで実行ができる。
-
act -l
- 実行可能なジョブの一覧を表示
-
act -j <JOB_NAME>
- <JOB_NAME>を実行
参考資料
Python(Poetry)でのGitHub Actions
- cdkのインストールとpoetryのインストールが必要
- poetry環境のアクティベートに苦戦した。
-
run
ごとにactivateの指定が必要? -
poetry shell
コマンドはCIだと使えない
-
name: cdk_lambda
on: [push]
jobs:
deploy-staging:
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend/cdk
steps:
- uses: actions/checkout@v2
- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Setup cdk
run: npm -g install aws-cdk@1.90.1
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.9.x'
architecture: 'x64'
- name: Install and Setup Poetry
run: |
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
source $HOME/.poetry/env
poetry config virtualenvs.in-project true
# インストールした Poetry を使って必要な Python パッケージをインストールする
- name: Install Dependencies and Activate
run: |
source $HOME/.poetry/env
poetry install --no-interaction
source .venv/bin/activate
echo pip list
- name: deploy
run: |
source .venv/bin/activate
cdk deploy
env:
AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
環境変数
GitHub Actionでの使用を前提にすると以下の2パターンがある。
- GitHub Actions上で環境変数を使用する
- Lambda上で環境変数を使用する
どこで環境変数の値を使うかによって必要な設定は異なるので、
- GitHub Actionsで環境変数を設定
- CDKで環境変数にアクセス
- 「GitHub Actions上で環境変数を使用する」だけならここまででOK
- CDKでLambdaに対して環境変数を設定
- Lambdaの中で環境変数にアクセス
- 「Lambda上で環境変数を使用する」ならここまでやらないといけない
GitHub Actions上で環境変数を使用する
クレデンシャル以外
envでjob単位、run単位に環境変数を設定することができる。
jobs:yaml
deploy-staging:
runs-on: ubuntu-latest
env:
STAGE: dev
クレデンシャル情報
GitHubのSecrets機能を使う。
Secretsを登録したら、GitHub Actionsから以下の形式でアクセスができる。
jobs:
deploy-staging:
runs-on: ubuntu-latest
env:
CONTENTFUL_ACCESS_TOKEN: ${{ secrets.CONTENTFUL_ACCESS_TOKEN }}
CONTENTFUL_SPACE_ID: ${{ secrets.CONTENTFUL_SPACE_ID }}
Lambda上で環境変数を使用する
Lambdaで環境変数にアクセスするには以下3つの手順を踏まなければならない。
- GitHub Actionsで環境変数を設定
- CDKでLambdaに対して環境変数を設定
- Lambdaの中で環境変数にアクセス
参考資料
ローカルでの稼働
SAM CLIのインストール
AWS SAM CLI のインストールを参照してインストールする。
Macの場合には以下の通りHomeBrewで実施すればOK
brew tap aws/tap
brew install aws-sam-cli
ローカル稼働
- CDKでCloudFormation Templateの出力
- SAM CLIでローカル実行
CDKでCloudFormation Templateの出力
cdk synth
コマンドを実行してSAM CLIで利用するためのテンプレートファイルを生成する。
依存ライブラリのインストールが不安だったが、このステップでライブラリのインストールまでやってくれる。
% cdk synth --no-staging > template.yaml
[+] Building 1.0s (12/12) FINISHED
=> [internal] load build definition from Dockerfile.dependencies 0.0s
=> => transferring dockerfile: 50B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/amazon/aws-sam-cli-build-image-python3.8:latest 0.9s
=> [internal] load build context 0.0s
=> => transferring context: 67B 0.0s
=> [1/7] FROM docker.io/amazon/aws-sam-cli-build-image-python3.8@sha256:7df8129fff00fd1e4968c60f7d18196a74a68ee9d86e326b98ee55968bc 0.0s
=> CACHED [2/7] RUN yum -q list installed rsync &>/dev/null || yum install -y rsync 0.0s
=> CACHED [3/7] RUN pip install --upgrade pip 0.0s
=> CACHED [4/7] RUN pip install pipenv poetry 0.0s
=> CACHED [5/7] WORKDIR /var/dependencies 0.0s
=> CACHED [6/7] COPY Pipfile* pyproject* poetry* requirements.tx[t] ./ 0.0s
=> CACHED [7/7] RUN [ -f 'Pipfile' ] && pipenv lock -r >requirements.txt; [ -f 'poetry.lock' ] && poetry export --with-credenti 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:cb01754512af2dd82170de71c8e3a9c3ec430c0b86fd8b8a32b385f83749e215 0.0s
=> => naming to docker.io/library/cdk-14b758d725a2623beb8a7e8c99fbc20c5fa4c3ff2a9c2c3fab9242aa06c76a89 0.0s
SAM CLIでローカル実行
出力されたテンプレートファイルからテスト対象のLambdaの名前を見つけ、local invoke
コマンドで実行する。
詳細はsam local invoke参照
eventを指定しない場合
sam local invoke sampleLambdaE3A04DFC --no-event
eventを指定する場合
-e
で対象となるeventのJSONファイルを指定する
sam local invoke sampleLambdaE3A04DFC -e lib/event/twitter/singleSqs.json
参考資料
SQS
エラー
cdk deployで以下のエラーが出た
Invalid request provided: Queue visibility timeout: 30 seconds is less than Function timeout: 600 seconds (Service: Lambda, Status Code: 400, Request ID: 100
4648f-21b8-4d0e-9f56-b88ef8f8f188, Extended Request ID: null)
CDKでQueueの定義を行なった際のvisibilityTimeoutの設定値(デフォルトは30秒)が対象のQueueをイベントソースとするLambdaのタイムアウト時間より長いためにエラーが発生している。
以下のようにSQSとLambdaそれぞれの設定値に整合性を持たせればエラーは解消する。
// SQSの定義
const queue = new sqs.Queue(this, `Queue-${stage}`, {
visibilityTimeout: cdk.Duration.seconds(400),
})
...
const getContentfulLambda = new lambdapython.PythonFunction(
this,
'fetchBeerFromContentful',
{
...
timeout: cdk.Duration.seconds(600),
...
},
}
)