AWS CDK Pythonで外部ライブラリを含むLambda Function(runtime: python3.7)をデプロイする
2019-07-21

AWS SAMでは次のようなファイルを用意し sam build / sam package を実行することでデプロイするための外部ライブラリのダウンロード, zipファイル作成を行ってくれます。
今回はrequirements.txtにslackclientを記述してるので, sam build を実行すると ./.aws-sam/build/MyFunction/ 配下にslackclientをダウンロードしてくれます。


.
├── function
│   ├── requirements.txt
│   └── lambda_function.py
└── template.yaml
  • template.yaml

MyFunction:
  Type: AWS::Serverless::Function
  Properties:
    CodeUri: function/
    Handler: lambda_function.lambda_handler
    Runtime: python3.7
    Timeout: 30
    MemorySize: 128
  • requirements.txt

slackclient==2.1.0

これをAWS CDK Pythonで同じようなノリで記述すると次のようになります。


from aws_cdk import (
    core,
    aws_lambda as lambda_,
)


class AppStack(core.Stack):
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        lambda_.Function(
            self,
            'function',
            function_name='my-function',
            code=lambda_.Code.asset('./function/'),
            handler='lambda_function.lambda_handler',
            runtime=lambda_.Runtime.PYTHON_3_7,
        )


app = core.App()
AppStack(app, "my-stack")
app.synth()

この状態で cdk deploy を実行しても, デプロイされたファンクションはうまいこと動いてくれません。requirements.txtに書かれている外部ライブラリが含まれていないからです。

cdk deploy の前にpip installする

code=lambda_.Code.asset('directory/') はディレクトリ配下のファイル類をzipファイルにしてデプロイしてくれます。なのでそのディレクトリに事前にダウンロードしてあげます。

ただ素直に function/ にダウンロードしてしまうとそのあとの管理がしんどいので, ディレクトリ構成を変更して function/src/ にソースコード類を置いて function/artifacts/ をデプロイのたびに作成してそこにダウンロードするようにしました。


.
├── app.py
├── cdk.json
├── function
│   └── src
│       ├── app.py
│       └── requirements.txt
└── requirements.txt

from aws_cdk import (
    core,
    aws_lambda as lambda_,
)


class AppStack(core.Stack):
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        lambda_.Function(
            self,
            'function',
            function_name='my-function',
            code=lambda_.Code.asset('./function/artifacts/'),
            handler='lambda_function.lambda_handler',
            runtime=lambda_.Runtime.PYTHON_3_7,
        )


app = core.App()
AppStack(app, "my-stack")
app.synth()
  • デプロイ!

$ rm -rf function/artifacts
$ cp -a function/src function/artifacts
$ pip install -r function/artifacts/requirements.txt -t function/artifacts/
$ cdk deploy --require-approval never

とりあえずこれでやってみてますが運用でカバーって感じもあり, もうちょっといい方法あればいいな~という気持ちです。
sam build 相当のコマンドがあれば嬉しいなと思いました。