Closed10

CDK + Lambdaの開発フローをGitHub Actionsで構築する

依存性の管理

aws_lamdbaとは別にaws_lambda_pythonがあり、venv, pipenv, poetryそれぞれでの依存ライブラリの自動インストールに対応している。

poetry

公式APIリファレンスのModule Dependenciesに記載の通りだが、各Functionのディレクトリにpyproject.tomlpoetry.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時に設定ファイルを見て自動でライブラリがインストールされていることが確認できる。

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

(app.py)
#!/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()
(python_lambda_stack.py)
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のようだ。

cdk.json
{
  "app": "...",
  "requireApproval": "never"
}

CDKで使用する言語

Lambda等の開発のために使用していたため混乱してしまったが、CDK自体はTypeScriptで書かれたもの。(npm install -g aws-cdkでインストールする)

そのため、Pythonを使ってLambdaを構築する場合でも以下大きく分けて2通りの選択肢がある。

  1. Lambdaの開発言語はPython、CDK自体の定義はPython
  2. 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'. エラーの対応方法

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上で環境変数を使用する

どこで環境変数の値を使うかによって必要な設定は異なるので、

  1. GitHub Actionsで環境変数を設定
  2. CDKで環境変数にアクセス
    • 「GitHub Actions上で環境変数を使用する」だけならここまででOK
  3. CDKでLambdaに対して環境変数を設定
  4. 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つの手順を踏まなければならない。

  1. GitHub Actionsで環境変数を設定
  2. CDKでLambdaに対して環境変数を設定
  3. Lambdaの中で環境変数にアクセス

参考資料

[AWS CDK] スタック名に本番環境と開発環境の名前を含めて、それぞれデプロイしてみた

ローカルでの稼働

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),
        ...
        },
      }
    )

エラー2

参考資料

このスクラップは2021/11/16にクローズされました
ログインするとコメントできます