Pythonで始めるAWS CDK
最近までいろいろと触る機会があったのと、AWS CDK+Pythonの記事が少なかったので書いてみた。
内容はAWS CDKのインストール〜デプロイまで。ついでにLambda関係でよく使いそうなところをいくつか。
実行環境
- Python 3.7.4
- OSX Catalina 10.15.5
Python、Pipが実行可能な環境であることが前提で書いています。
はじめに
AWS CDKってなに?
AWS クラウド開発キット (AWS CDK) は、使い慣れたプログラミング言語を使用してクラウドアプリケーションリソースをモデル化およびプロビジョニングするためのオープンソースのソフトウェア開発フレームワークです。
かなり大雑把にまとめると、使い慣れたプログラミング言語でAWSのリソースを定義、作成できるIaC(Infrastructure as Code)ツールですよっと。
なんでAWS CDKなの?
環境設定をコードで管理したい。けどterraformとかに手を出すほどでもないし、template.ymlは書きたくない…。何よりAWSの公式!
なんでPythonなの?
(TypeScriptやったことないから…)
LambdaをPythonで書いていたからその延長線上でPythonでやってみた
使ってみた感想
- 後述するが間接的にCloudFormationを使用しているので、実務で使用する場合はAWS CloudFormation の制限は一読しておくことをお勧めする。
- リリースは頻繁にされているので日々改善されているようだが、使い込んでいくと正直、現状では痒いところに手が届かない感が否めない。少なくともクロススタック参照はなんとかして欲しい。
- 調べて出てくるのはTypeScriptがほとんどなので、わざわざPythonを使うメリットはそこまでない
AWS CDKのインストール
- Getting started with the AWS CDKを参考に進めていく。
Node.jsのインストール
前提として、Node.jsが必要なのでインストールされていない場合はまずこちらをインストールする
なぜNode.jsが必要かというと、AWS CDK自体はTypeScriptで書かれており、Pythonなど他の言語はjsiiというライブラリで自動的にTypeScriptに変換してくれているらしい。すごい。
Q: AWS CDK を使用するために JavaScript ランタイムをインストールする必要があるのはなぜですか?
AWS は、AWS Construct ライブラリパッケージのビジネスロジックを TypeScript で構築し、サポートされている各プログラミング言語へのマッピングを提供します。これにより、AWS CDK コンストラクトの動作が異なる言語間で一貫していることを確認でき、すべての言語で利用できる包括的なコンストラクトパッケージのセットを提供できます。AWS CDK プロジェクトで作成したコードはすべてお客様ご希望のプログラミング言語でネイティブになっています。JavaScript ランタイムはお客様のプログラミング経験の実施詳細です。jsii プロジェクトは https://github.com/aws/jsii で参照できます。
Node.jsのインストール自体は簡単で、Node.jsの公式からインストーラをダウンロード。あとはインストーラに従ってポチポチしていけば勝手にインストールしてくれる。
インストールが完了したらバージョンを確認
$ node -v
v12.18.2
$ npm -v
6.14.5
AWS認証情報の設定
AWS CLIがインストールされている場合はaws configure
コマンドを実行すればプロンプトで設定可能だが、わざわざAWS CLIインストールしたくない場合は手動で設定する。
以下はmac or linuxの設定手順。Windowsの場合は%USERPROFILE%\.aws\config
と %USERPROFILE%\.aws\credentials
を作成し、認証情報、リージョンを設定する
$ mkdir ~/.aws
$ touch ~/.aws/config
$ touch ~/.aws/credentials
エディタで~/.aws/config
を開き、以下の通りリージョンを設定し、保存する
[default]
region=ap-northeast-1
エディタで~/.aws/credentials
を開き、以下の通り認証情報を設定し、保存する。
[default]
aws_access_key_id={アクセスキーID}
aws_secret_access_key={シークレットアクセスキー}
AWS CDKのインストール
npmを使用してインストールする
$ sudo npm install -g aws-cdk
バージョンを表示し、インストールされていることを確認。
$ cdk --version
1.52.0 (build 5263664)
デプロイ用S3バケットの作成
cdk bootstrap
コマンドでCloudFormationで使用するS3バケットを作成する
これはリージョンごとに実施する必要があるので注意。
$ cdk bootstrap
⏳ Bootstrapping environment aws://323617333195/ap-northeast-1...
CDKToolkit: creating CloudFormation changeset...
✅ Environment aws://323617333195/ap-northeast-1 bootstrapped.
CDK appを作る
- Your first AWS CDK appを参考に進めていく。
- 参考までに、今回作成したコードはここに置いてあります。
プロジェクトディレクトリを作成
mkdir hello-cdk
cd hello-cdk
cdk init
コマンドを実行
cdk init app --language python
実行が終わったらvirtualenvを起動する
(pip3を使用している場合はpip3に読み替えて実行すること)
source .env/bin/activate
pip install -r requirements.txt
pipenvを使用したい場合は、virtualenvを起動せずに.env
ディレクトリを削除して代わりにpipenvを起動する
S3バケットを作成してみる
pip install aws-cdk.aws-s3
hello_cdk_stack.pyにs3バケットを作成するコードを追加する
(bucket_nameは既存のバケット名と重複するとデプロイ時にエラーになるため、重複しないものへ書き換えること)
from aws_cdk import core
from aws_cdk import aws_s3 as _s3
class HelloCdkStack(core.Stack):
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
# The code that defines your stack goes here
bucket = _s3.Bucket(self, "MyFirstBucket", bucket_name="kimi-first-cdk-bucket")
デプロイコマンドを実行
$ cdk deploy
hello-cdk: deploying...
hello-cdk: creating CloudFormation changeset...
✅ hello-cdk
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:323617333195:stack/hello-cdk/3497b790-ca3f-11ea-9236-0eb7b90bbf8e
デプロイ完了後にAWSマネジメントコンソールでS3バケットが作成されていることを確認できた
AWSマネジメントコンソールでCloudFormationを開くとhello-cdk
というスタックができている。
これはAWS CDKがリソースを作成するのにCloudFormationを使用しているため。
cdk synth
コマンドを実行すればCloudFormationテンプレートを出力することもできる。
$ cdk synth
また、作成したリソースを全て削除したい場合はcdk destroy
コマンドでスタック単位でリソースを削除することが可能。
ただし、S3バケットなど削除されないリソースが一部あるので注意が必要。
$ cdk destroy
Lambdaをデプロイしてみる
- 参考までに、今回作成したコードはここに置いてあります。
シンプルなLambda関数をデプロイする
新しいプロジェクトを作成。
$ mkdir cdk-lambda
$ cd cdk-lambda/
$ cdk init app --language python
せっかくなのでPipenvを使ってみる。
$ rm -rf .env
$ rm -rf source.bat
$ rm -rf requirements.txt
$ pipenv shell
必要なパッケージをインストール
$ pipenv install aws_cdk.core
$ pipenv install aws_cdk.aws_lambda
Lambda関数を置くディレクトリを作成し、Lambda関数のPythonファイルを作成
$ mkdir function
$ touch function/index.py
今回はあくまでもサンプルなので、Lambdaのコードは適当
import json
print('Loading function')
def lambda_handler(event, context):
print("value1 = " + event['key1'])
print("value2 = " + event['key2'])
print("value3 = " + event['key3'])
return event['key1'] # Echo back the first key value
cdk_lambda_stack.py
にLambda関数を作成するコードを追記
from aws_cdk import core
from aws_cdk import aws_lambda as _lambda
class CdkLambdaStack(core.Stack):
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
# The code that defines your stack goes here
lambdaFn = _lambda.Function(self, "SampleLambdaFunction",
code=_lambda.Code.from_asset('function/'),
runtime=_lambda.Runtime.PYTHON_3_7,
handler="index.lambda_handler",
function_name="sample_lambda_function"
)
いざ、デプロイ!
$ cdk deploy
AWSマネジメントコンソールでデプロイされていることを確認。
Lambda関数に環境変数を設定する
Functionを作成する際にenvironment
パラメータを指定するか、add_environment
メソッドで設定する
# 環境変数を追加
lambdaFn.add_environment(key="STAGE", value="DEV")
s3トリガーを設定する
必要なライブラリをインストール
$ pipenv install aws_cdk.aws_s3
$ pipenv install aws_cdk.aws_s3_notifications
ライブラリをインポート
from aws_cdk import (
core,
aws_lambda as _lambda,
aws_s3 as _s3,
aws_s3_notifications,
)
s3バケットを作成し、通知イベントを設定。
今のところ、この方法では既存のS3バケットには設定できない。既存のS3バケットにイベントを設定したい場合はカスタムリソースを使用する。
bucket = _s3.Bucket(self, "SampleBucket", bucket_name="kimi-first-cdk-bucket")
notification = aws_s3_notifications.LambdaDestination(lambdaFn)
bucket.add_event_notification(_s3.EventType.OBJECT_CREATED, notification, _s3.NotificationKeyFilter(prefix="hoge", suffix=".csv"))
Cloudwatch Eventsから定期的に起動する
必要なライブラリをインストール
$ pipenv install aws_cdk.aws_events
$ pipenv install aws_cdk.aws_events_targets
インストールしたライブラリをインポート
from aws_cdk import (
core,
aws_lambda as _lambda,
aws_s3 as _s3,
aws_s3_notifications,
aws_events as _events,
aws_events_targets as _targets
)
イベントルールを作成するコードを追加。
今回スケジュール文字列を使用して設定しているが、Schedule.cron
やSchedule.rate
など別の方法でも指定可能。
rule = _events.Rule(self, "SampleEventRule",
rule_name="schedule_trigger_event",
schedule=_events.Schedule.expression("cron(10 * * * ? *)")
)
rule.add_target(_targets.LambdaFunction(lambdaFn))
参考
-
AWS CDK Examples サンプルコード集。言語によって差はあるが、いろいろ揃っているのでかなりありがたい