AWS CDK(Python)を試してみる
概要
これまで使ったことのあるIaCは以下。
- Ansible
- Terraform
あくまでも個人的に思っているだけだけど、これらはインフラエンジニア的視点に立っていると思っていて、これに対して、
- AWS CDK
- AWS SAM
- Serverless Framework
などは、アプリ開発者視点に立っているというふうに感じており、あまり触ったことがない。
とりあえずいくつか触ってみようと思うが、まずはAWS CDKから。
前提
以下を参考にdevcontainerを作った。
githubのテンプレートレポジトリにしている。
最初のサイトにworkspace周りの設定が含まれているが、ここはちょっと自分でハマってみたいので、一旦設定は入れてない。
とりあえず上記テンプレートレポジトリからレポジトリを作って、vscode devcontainerで作業することとする。足りなければ適宜編集していく。
なお、dockerはremote development で使用しているサーバ上で動かしている。Docker Destktopではないので注意。
CDK workshopはこれ
ちなみにこちらも見つかるけど内容が古いみたい。
プロジェクト作成
プロジェクトディレクトリ作成。空ディレクトリじゃないとプロジェクトは作れないらしい。ちょっとレポジトリのディレクトリ構成はあとで考えないといけないかも。
$ mkdir cdk-workshop && cd cdk-workshop
プロジェクト作成
$ cdk init sample-app --language python
出力
Applying project template sample-app for python
# Welcome to your CDK Python project!
You should explore the contents of this project. It demonstrates a CDK app with an instance of a stack (`cdk_workshop_stack`)
which contains an Amazon SQS queue that is subscribed to an Amazon SNS topic.
The `cdk.json` file tells the CDK Toolkit how to execute your app.
This project is set up like a standard Python project. The initialization process also creates
a virtualenv within this project, stored under the .venv directory. To create the virtualenv
it assumes that there is a `python3` executable in your path with access to the `venv` package.
If for any reason the automatic creation of the virtualenv fails, you can create the virtualenv
manually once the init process completes.
To manually create a virtualenv on MacOS and Linux:
```
$ python3 -m venv .venv
```
After the init process completes and the virtualenv is created, you can use the following
step to activate your virtualenv.
```
$ source .venv/bin/activate
```
If you are a Windows platform, you would activate the virtualenv like this:
```
% .venv\Scripts\activate.bat
```
Once the virtualenv is activated, you can install the required dependencies.
```
$ pip install -r requirements.txt
```
At this point you can now synthesize the CloudFormation template for this code.
```
$ cdk synth
```
You can now begin exploring the source code, contained in the hello directory.
There is also a very trivial test included that can be run like this:
```
$ pytest
```
To add additional dependencies, for example other CDK libraries, just add to
your requirements.txt file and rerun the `pip install -r requirements.txt`
command.
## Useful commands
* `cdk ls` list all stacks in the app
* `cdk synth` emits the synthesized CloudFormation template
* `cdk deploy` deploy this stack to your default AWS account/region
* `cdk diff` compare deployed stack with current state
* `cdk docs` open CDK documentation
Enjoy!
Please run 'python3 -m venv .venv'!
Executing Creating virtualenv...
✅ All done!
プロジェクトのディレクトリ構造。
$ tree -a -L 2
.
├── app.py
├── cdk.json
├── cdk_workshop
│ ├── cdk_workshop_stack.py
│ └── __init__.py
├── .gitignore
├── README.md
├── requirements-dev.txt
├── requirements.txt
├── source.bat
├── tests
│ ├── __init__.py
│ └── unit
└── .venv
├── bin
├── include
├── lib
├── lib64 -> lib
└── pyvenv.cfg
8 directories, 11 files
venvで仮想環境が作られていることがわかる。
ではactivateする。ちょっとworkshopの構成が古いようで以下のように行う必要があった。
$ source .venv/bin/activate
仮想環境に入った。
(.venv) vscode ➜ /workspaces/aws-cdk-sample/cdk-workshop (main) $
Pythonモジュールをインストールする
$ pip install -r requirements.txt
app.pyがエントリーポイントになる。
#!/usr/bin/env python3
import aws_cdk as cdk
from cdk_workshop.cdk_workshop_stack import CdkWorkshopStack
app = cdk.App()
CdkWorkshopStack(app, "cdk-workshop")
app.synth()
3行目でインポートされているのがメインとなるコードのファイル。
ということで、cdk_workshop/cdk_workshop_stack.py
を開いてみる。
from constructs import Construct
from aws_cdk import (
Duration,
Stack,
aws_iam as iam,
aws_sqs as sqs,
aws_sns as sns,
aws_sns_subscriptions as subs,
)
class CdkWorkshopStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
queue = sqs.Queue(
self, "CdkWorkshopQueue",
visibility_timeout=Duration.seconds(300),
)
topic = sns.Topic(
self, "CdkWorkshopTopic"
)
topic.add_subscription(subs.SqsSubscription(queue))
ここで、IAM、SQS、SNSが設定されているのがわかる。これを元にCloudFormationテンプレートが生成(synth)される。
デプロイ
ということでcdk synth
する。
$ cdk synth
CloudFormationのテンプレートが出力される。
Resources:
CdkWorkshopQueue50D9D426:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 300
UpdateReplacePolicy: Delete
DeletionPolicy: Delete
Metadata:
aws:cdk:path: cdk-workshop/CdkWorkshopQueue/Resource
CdkWorkshopQueuePolicyAF2494A5:
Type: AWS::SQS::QueuePolicy
Properties:
PolicyDocument:
Statement:
- Action: sqs:SendMessage
Condition:
ArnEquals:
aws:SourceArn:
Ref: CdkWorkshopTopicD368A42F
Effect: Allow
Principal:
Service: sns.amazonaws.com
Resource:
Fn::GetAtt:
- CdkWorkshopQueue50D9D426
- Arn
Version: "2012-10-17"
Queues:
- Ref: CdkWorkshopQueue50D9D426
Metadata:
aws:cdk:path: cdk-workshop/CdkWorkshopQueue/Policy/Resource
CdkWorkshopQueuecdkworkshopCdkWorkshopTopicA7BCA841EC3B13D1:
Type: AWS::SNS::Subscription
Properties:
Protocol: sqs
TopicArn:
Ref: CdkWorkshopTopicD368A42F
Endpoint:
Fn::GetAtt:
- CdkWorkshopQueue50D9D426
- Arn
DependsOn:
- CdkWorkshopQueuePolicyAF2494A5
Metadata:
aws:cdk:path: cdk-workshop/CdkWorkshopQueue/cdkworkshopCdkWorkshopTopicA7BCA841/Resource
CdkWorkshopTopicD368A42F:
Type: AWS::SNS::Topic
Metadata:
aws:cdk:path: cdk-workshop/CdkWorkshopTopic/Resource
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:H4sIAAAAAAAA/1WNQQrCMBBFz9J9MlYFdd8L1Na9tGnEsTVpMwlSQu5uk4DgZv7/jwdzgPMFyqL7EBfDyCfswbe2EyPb0N3TQuCvTjrJqofKJd1aTyjWH8wzMFKb37qehMHZolbR+Ns3PaOINJUQYm0kaWdE+lFpNWA0A6tX+9Rqd4R9CafiRYjcOGXxLaHJ+QVjDGCovgAAAA==
Metadata:
aws:cdk:path: cdk-workshop/CDKMetadata/Default
Condition: CDKMetadataAvailable
Conditions:
CDKMetadataAvailable:
Fn::Or:
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- af-south-1
- Fn::Equals:
- Ref: AWS::Region
- ap-east-1
- Fn::Equals:
- Ref: AWS::Region
- ap-northeast-1
- Fn::Equals:
- Ref: AWS::Region
- ap-northeast-2
- Fn::Equals:
- Ref: AWS::Region
- ap-south-1
- Fn::Equals:
- Ref: AWS::Region
- ap-southeast-1
- Fn::Equals:
- Ref: AWS::Region
- ap-southeast-2
- Fn::Equals:
- Ref: AWS::Region
- ca-central-1
- Fn::Equals:
- Ref: AWS::Region
- cn-north-1
- Fn::Equals:
- Ref: AWS::Region
- cn-northwest-1
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- eu-central-1
- Fn::Equals:
- Ref: AWS::Region
- eu-north-1
- Fn::Equals:
- Ref: AWS::Region
- eu-south-1
- Fn::Equals:
- Ref: AWS::Region
- eu-west-1
- Fn::Equals:
- Ref: AWS::Region
- eu-west-2
- Fn::Equals:
- Ref: AWS::Region
- eu-west-3
- Fn::Equals:
- Ref: AWS::Region
- me-south-1
- Fn::Equals:
- Ref: AWS::Region
- sa-east-1
- Fn::Equals:
- Ref: AWS::Region
- us-east-1
- Fn::Equals:
- Ref: AWS::Region
- us-east-2
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- us-west-1
- Fn::Equals:
- Ref: AWS::Region
- us-west-2
Parameters:
BootstrapVersion:
Type: AWS::SSM::Parameter::Value<String>
Default: /cdk-bootstrap/hnb659fds/version
Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Rules:
CheckBootstrapVersion:
Assertions:
- Assert:
Fn::Not:
- Fn::Contains:
- - "1"
- "2"
- "3"
- "4"
- "5"
- Ref: BootstrapVersion
AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.
上記の実体はcdk.out
ディレクトリ内に出力されているcdk-workshop.template.json
がそれ。他にもいろいろあるみたい。
$ tree -a cdk.out
cdk.out
├── cdk.out
├── cdk-workshop.assets.json
├── cdk-workshop.template.json
├── manifest.json
└── tree.json
0 directories, 5 files
初めてデプロイするときはbootstrapが必要になる。AWSアカウントIDとリージョンを指定してcdk bootstrap
を実行する。アカウントIDとリージョンはaws sts get-caller-identity
とかaws configure get region
で確認すればいちいちマネージメントコンソール開かなくて済む。
$ cdk bootstrap aws://XXXXXXXXXXXX/ap-northeast-1
こんな感じでリソースが作成される。
⏳ Bootstrapping environment aws://XXXXXXXXXXXX/ap-northeast-1...
Trusted accounts for deployment: (none)
Trusted accounts for lookup: (none)
Using default execution policy of 'arn:aws:iam::aws:policy/AdministratorAccess'. Pass '--cloudformation-execution-policies' to customize.
CDKToolkit: creating CloudFormation changeset...
[█████████▋················································] (2/12)
4:19:45 PM | CREATE_IN_PROGRESS | AWS::CloudFormation::Stack | CDKToolkit
4:19:51 PM | CREATE_IN_PROGRESS | AWS::IAM::Role | LookupRole
4:19:51 PM | CREATE_IN_PROGRESS | AWS::IAM::Role | CloudFormationExecutionRole
4:19:51 PM | CREATE_IN_PROGRESS | AWS::IAM::Role | ImagePublishingRole
4:19:51 PM | CREATE_IN_PROGRESS | AWS::IAM::Role | FilePublishingRole
4:19:52 PM | CREATE_IN_PROGRESS | AWS::S3::Bucket | StagingBucket
以下のように表示されればOK。
✅ Environment aws://XXXXXXXXXXXX/ap-northeast-1 bootstrapped.
マネージメントコンソールでCloudFormationを見ると以下のようにスタックが作成されているのがわかる。
ではアプリケーションおよびインフラのデプロイを行いたいところだけど、その前にapp.pyを修正する。
(snip)
app = cdk.App()
CdkWorkshopStack(app, "cdk-workshop",
env=cdk.Environment(account="XXXXXXXXXXXX", region="ap-northeast-1"), # 追加
)
(snip)
これが正しいのかどうかわからないけど、これをせずにcdk deploy
するとus-east-1を見に行くようで、bootstrapされてないからリソース作れないとか言われる。
上記の修正を行ったらデプロイする。
$ cdk deploy
以下のように表示されたらy
ですすめる。これはSNSがSQSにアクセスできるようにアクセス権を修正するらしい。
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
┌───┬─────────────────────┬────────┬─────────────────────┬─────────────────────┬──────────────────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼─────────────────────┼────────┼─────────────────────┼─────────────────────┼──────────────────────┤
│ + │ ${CdkWorkshopQueue. │ Allow │ sqs:SendMessage │ Service:sns.amazona │ "ArnEquals": { │
│ │ Arn} │ │ │ ws.com │ "aws:SourceArn": " │
│ │ │ │ │ │ ${CdkWorkshopTopic}" │
│ │ │ │ │ │ } │
└───┴─────────────────────┴────────┴─────────────────────┴─────────────────────┴──────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)
Do you wish to deploy these changes (y/n)?
リソースのデプロイが行われる。
cdk-workshop: creating CloudFormation changeset...
[███████████████████▎······································] (2/6)
4:38:15 PM | CREATE_IN_PROGRESS | AWS::CloudFormation::Stack | cdk-workshop
4:38:20 PM | CREATE_IN_PROGRESS | AWS::SQS::Queue | CdkWorkshopQueue
以下のように表示されればOK。
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/cdk-workshop/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
✨ Total time: 93.12s
プロジェクト名と同じスタックが作成されているのがわかる。
ということでアプリを作っていくのだけど、続きはまた今度。
リソースの削除
一旦削除しておく。削除はcdk destroy
$ cdk destroy
確認が行われるのでy
で。
Are you sure you want to delete: cdk-workshop (y/n)?
リソースが削除される。
cdk-workshop: destroying... [1/1]
4:57:36 PM | DELETE_IN_PROGRESS | AWS::CloudFormation::Stack | cdk-workshop
4:57:41 PM | DELETE_IN_PROGRESS | AWS::SNS::Topic | CdkWorkshopTopic
4:57:41 PM | DELETE_IN_PROGRESS | AWS::SQS::Queue | CdkWorkshopQueue
以下のように表示されればOK。
✅ cdk-workshop: destroyed
CloudFormationを見てみると、cdk deploy
で作成されたスタックが削除されていることがわかる。cdk bootstrap
のほうは残っていて、こちらはプロジェクトとは別にCDKの利用のためのスタックであることがわかる。
続き
一旦cdk destroy
したので再度deployから。
$ cd cdk-workshop/
$ source .venv/bin/activate
通常はデプロイしたままで終わるはずなので、普段の作業開始のときは↑のようにすればよいと思う。
ではデプロイ。
$ cdk deploy
リソースの追加とデプロイ
ということで今回は実際にサンプルアプリとそれに必要なリソースを足していく。
サンプルのboilerplateではIAM/SQS/SNSの設定が含まれていたがこれらは不要なので削除する。
変更前
from constructs import Construct
from aws_cdk import (
Duration,
Stack,
aws_iam as iam,
aws_sqs as sqs,
aws_sns as sns,
aws_sns_subscriptions as subs,
)
class CdkWorkshopStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
queue = sqs.Queue(
self, "CdkWorkshopQueue",
visibility_timeout=Duration.seconds(300),
)
topic = sns.Topic(
self, "CdkWorkshopTopic"
)
topic.add_subscription(subs.SqsSubscription(queue))
変更後
from constructs import Construct
from aws_cdk import (
Stack,
)
class CdkWorkshopStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
変更後のコードを適用するとリソースにどういう変更が行われるかを確認する。cdk diff
を実行する。
$ cdk diff
出力
Stack cdk-workshop
IAM Statement Changes
┌───┬────────────────────────────┬────────┬─────────────────┬────────────────────────────┬─────────────────────────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼────────────────────────────┼────────┼─────────────────┼────────────────────────────┼─────────────────────────────┤
│ - │ ${CdkWorkshopQueue.Arn} │ Allow │ sqs:SendMessage │ Service:sns.amazonaws.com │ "ArnEquals": { │
│ │ │ │ │ │ "aws:SourceArn": "${CdkWo │
│ │ │ │ │ │ rkshopTopic}" │
│ │ │ │ │ │ } │
└───┴────────────────────────────┴────────┴─────────────────┴────────────────────────────┴─────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)
Resources
[-] AWS::SQS::Queue CdkWorkshopQueue CdkWorkshopQueue50D9D426 destroy
[-] AWS::SQS::QueuePolicy CdkWorkshopQueue/Policy CdkWorkshopQueuePolicyAF2494A5 destroy
[-] AWS::SNS::Subscription CdkWorkshopQueue/cdkworkshopCdkWorkshopTopicA7BCA841 CdkWorkshopQueuecdkworkshopCdkWorkshopTopicA7BCA841EC3B13D1 destroy
[-] AWS::SNS::Topic CdkWorkshopTopic CdkWorkshopTopicD368A42F destroy
コードから削除したリソースが削除対象となっていることがわかる。ではデプロイして削除する。
$ cdk deploy
出力
✨ Synthesis time: 3.15s
cdk-workshop: building assets...
[0%] start: Building c1f0976937c982e5b398d640697ca4de5a97c24183431f0d2c4ac590314544a4:XXXXXXXXXXXX-ap-northeast-1
c1f0976937c982e5b398d640697ca4de5a97c24183431f0d2c4ac590314544a4:XXXXXXXXXXXX-ap-northeast-1
[100%] success: Built c1f0976937c982e5b398d640697ca4de5a97c24183431f0d2c4ac590314544a4:XXXXXXXXXXXX-ap-northeast-1
cdk-workshop: assets built
cdk-workshop: deploying... [1/1]
[0%] start: Publishing c1f0976937c982e5b398d640697ca4de5a97c24183431f0d2c4ac590314544a4:XXXXXXXXXXXX-ap-northeast-1
[100%] success: Published c1f0976937c982e5b398d640697ca4de5a97c24183431f0d2c4ac590314544a4:XXXXXXXXXXXX-ap-northeast-1
cdk-workshop: creating CloudFormation changeset...
[█████████████████████████████████▏························] (4/7)
12:25:21 AM | UPDATE_COMPLETE_CLEA | AWS::CloudFormation::Stack | cdk-workshop
12:25:25 AM | DELETE_IN_PROGRESS | AWS::SQS::Queue | CdkWorkshopQueue50D9D426
CloudFormationのスタックが更新されて、リソースが順に削除されていくのがわかる。以下のように表示されれば削除完了。
✅ cdk-workshop
✨ Deployment time: 85s
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/cdk-workshop/7bff4550-ed35-11ed-9ebb-0ad2deb1c099
✨ Total time: 88.15s
ここからLambdaとAPI Gatewayのコードを書いていく。
まずLambda。
プロジェクトのルートディレクトリにlambda用のディレクトリを作成する。
$ mkdir lambda
Lambdaで実行されるコードを用意する。
import json
def handler(event, context):
print("request: {}".format(json.dumps(event)))
return {
"statusCode": 200,
"headers": {
"Content-Type": "text/plain"
},
"body": "Hello, CDK! You have hist {}\n".format(event["path"])
}
次にCDKでLambdaをデプロイするコードを書いていく。CDKでは各サービスがモジュールとなっているのでこれを呼び出す必要がある。AWS Construct Libraryというらしい。
cdk_workshop/cdk_workshop_stack.py
に追加していく。
変更前
from constructs import Construct
from aws_cdk import (
Stack,
)
class CdkWorkshopStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
ステップ・バイ・ステップでやっていく。Lambdaモジュールをimportする。
from constructs import Construct
from aws_cdk import (
Stack,
aws_lambda as _lambda, # 追加
)
(snip)
Lambdaの定義を追加
(snip)
class CdkWorkshopStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# 以下を追加
my_lambda = _lambda.Function(
self, 'HelloHandler',
runtime=_lambda.Runtime.PYTHON_3_10,
code=_lambda.Code.from_asset('lambda'),
handler="hello.handler",
)
変更内容を見てみる。
$ cdk diff
Stack cdk-workshop
IAM Statement Changes
┌───┬─────────────────────────────────┬────────┬────────────────┬──────────────────────────────┬───────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼─────────────────────────────────┼────────┼────────────────┼──────────────────────────────┼───────────┤
│ + │ ${HelloHandler/ServiceRole.Arn} │ Allow │ sts:AssumeRole │ Service:lambda.amazonaws.com │ │
└───┴─────────────────────────────────┴────────┴────────────────┴──────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬─────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│ │ Resource │ Managed Policy ARN │
├───┼─────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${HelloHandler/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴─────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)
Resources
[+] AWS::IAM::Role HelloHandler/ServiceRole HelloHandlerServiceRole11EF7C63
[+] AWS::Lambda::Function HelloHandler HelloHandler2E4FBA4D
ではデプロイする。
$ cdk deploy
デプロイが完了したらコンソールを見てみるとLambda関数が作成されているのがわかる。関数の名前は"プロジェクト名-ID"にランダムな文字列が付与されている模様。
"API Gateway AWS Proxy"のテストを実行して問題なければOK。
ではLamdbaのコードを変更して反映してみる。
import json
def handler(event, context):
print("request: {}".format(json.dumps(event)))
return {
"statusCode": 200,
"headers": {
"Content-Type": "text/plain"
},
"body": "Good Afternoon, CDK! You have hist {}\n".format(event["path"]) # 変更
}
cdk deploy --hotswap / cdk watch
通常であればcdk deploy
で変更することになるが、lambdaのコード変更だけで、CloudFormationスタックを更新してデプロイ・Lambdaのコードを更新してデプロイになると時間がかかる。たぶん、CloudFormationスタックが見ているのはLambda関数のデプロイだけで中身のコードはS3バケットにあるものを読み込んでいるだけ、つまりCloudFormationとは別で管理されているということになるということなのだろうか?
こういう場合はcdk deploy --hotswap
を使うと、デプロイを高速化できるらしい。やってみる。
$ cdk deploy --hotswap
✨ Synthesis time: 3.15s
⚠️ The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments
⚠️ They should only be used for development - never use them for your production Stacks!
cdk-workshop: building assets...
(snip)
✨ hotswapping resources:
✨ Lambda Function 'cdk-workshop-HelloHandler2E4FBA4D-sBfVPDHNOFp1'
✨ Lambda Function 'cdk-workshop-HelloHandler2E4FBA4D-sBfVPDHNOFp1' hotswapped!
✅ cdk-workshop
✨ Deployment time: 3.69s
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/cdk-workshop/7bff4550-ed35-11ed-9ebb-0ad2deb1c099
✨ Total time: 6.84s
実行時間が先程と比べると非常に短いのがわかる。Lambdaのテストで確認したらちゃんと変更されていた。
ただし、実行時のメッセージにも出ている通り、やはりこれはCloudFormationスタックの設定と乖離が出てしまう様子(TerraformでいうところのOutside of Terraform)なので、開発時にサクサク確認したいみたいな場合にやるもので、本番環境とかではやるべきではないということらしい。
⚠️ The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments
⚠️ They should only be used for development - never use them for your production Stacks!
ちなみにcdk deploy --hotswap
ができるかどうかはリソースによるみたいで、--hotswap
できない場合は通常のcdk deploy
にフォールバックしてくれるらしい。
さらにこれをすすめるためにcdk watch
というのがある。こちらはコードの変更を監視して、変更されたら即反映するというもの。デフォルトだと--hotswap
が有効になるようなので、開発時はサクサク進めたいという場合に便利な様子。
$ cdk watch
変更を検知するとこんな感じのログが流れて、デプロイが行われる。
Detected change to 'lambda/hello.py' (type: change). Triggering 'cdk deploy'
変更監視対象とするファイル等の設定はcdk.jsonで行えば良い様子。
{
"app": "python3 app.py",
"watch": {
"include": [
"**"
],
"exclude": [
"README.md",
"cdk*.json",
"requirements*.txt",
"source.bat",
"**/__init__.py",
"python/__pycache__",
"tests"
]
},
(snip)
とりあえずは理解したのだけど、これドリフトが発生することになるのはどうやって解消するんだろう?最終的にcdk deploy
すればいいということなのかな?やってみる。
$ cdk deploy
ふむ、CloudFormationのスタックも更新されて反映された様子。
(snip)
cdk-workshop: creating CloudFormation changeset...
✅ cdk-workshop
✨ Deployment time: 23.13s
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/cdk-workshop/7bff4550-ed35-11ed-9ebb-0ad2deb1c099
✨ Total time: 26.27s
再度デプロイしてみたけど変更なしになっているので、これでいいみたい。Terraformとか触ってた身からすると差分が起きるのはちょっと躊躇する部分もあるけど、こういうものなのかもしれない。
✅ cdk-workshop (no changes)
次にAPI Gatewayを追加する。Lambdaのときと同じようにコードを追加していく。
from constructs import Construct
from aws_cdk import (
Stack,
aws_lambda as _lambda,
aws_apigateway as apigw, # 追加
)
class CdkWorkshopStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
my_lambda = _lambda.Function(
self, 'HelloHandler',
runtime=_lambda.Runtime.PYTHON_3_10,
code=_lambda.Code.from_asset('lambda'),
handler="hello.handler",
)
# 以下を追加
apigw.LambdaRestApi(
self, 'Endpoint',
handler=my_lambda
)
なるほど、他のリソースのパラメータで使う場合はこういうふうに受け渡すのね。あと、aws_apigatewayv2
というリソースもあるけど、こちらは書き方が違うっぽくてパッと見でわからなかったので、またそのうち調べるということで。
デプロイ・・・ってかdiff取るの忘れたな。このあたりは毎回変更内容を出力してくれてかならず最終確認してくれるTerraformとは違うので意しないといけないなー。
$ cdk deploy
で出力内容にこういうのが含まれている。
Outputs:
cdk-workshop.Endpoint8024A810 = https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/
curlでアクセスしてみるとAPI Gateway経由でLambdaが応答しているのがわかる。
$ curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amaz
onaws.com/prod/
Good Evening, CDK! You have hist /
$ curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/hogehoge
Good Evening, CDK! You have hist /hogehoge
このあともう少し複雑な感じになるのだけど、一旦ここまで。
リソースは削除しておく。
$ cdk destroy
まとめ
あくまでも個人的な感想。
TerraformやAnsibleあたりと比べると、
- コードの量は少なくて済みそう
- 宣言型だといろいろ面倒なロジック的な処理も当然書きやすい
というのがメリットかなと思う。反面、
- 少ないコードで書けてしまうのでいろいろ隠蔽されて見えないことが多い
- Terraformだと何かを追加する場合、関連するリソースとかも見る必要が出てくる。
- これが逆にAWSリソースへの理解が逆に深まるところがあると感じる。
- 初学者にはそのほうがいいかもしれない、特にインフラエンジニアならAnsibleとか触っていれば入りやすい、とか、ふと思った。
- 今回Pythonで書いたけど、TypeScriptのほうが情報が多そうな気がする
- なーんとなく個人的に勝手に感じてるのはTypeScriptのほうがメインの開発ラインなのかなーと。しらんけど。
- 個人的には今ならPythonで書きたい、LLM周りはPython多いし、だいぶ慣れてきたこともあるし。
- CloudFormation全然慣れない
- 状態管理をマネージドに任せれるのはいいんだけど。Terraformのtfstateも結構しんどいし。
- どうしても一歩引いてしまう自分がいる・・・
あたりはちょっと気になるところではある。
とりあえずここまで。気が向いたら続きをやる。
そういえば、AWSアカウントIDをapp.pyにベタ書きしたのだけど、
(snip)
app = cdk.App()
CdkWorkshopStack(app, "cdk-workshop",
env=cdk.Environment(account="XXXXXXXXXXXX", region="ap-northeast-1"),
)
(snip)
ここはenvfileとかを使ったほうがよい。
(snip)
python-dotenv
$ pip install -r requirements.txt
.envファイルを用意する。
AWS_ACCOUNT_ID=XXXXXXXXXXXX
AWS_REGION=ap-northeast-1
.envを読み込むconfig.py
from dotenv import load_dotenv
import os
load_dotenv()
AWS_ACCOUNT_ID = os.getenv('AWS_ACCOUNT_ID')
AWS_REGION = os.getenv('AWS_REGION')
config.pyをapp.pyでインポートする
#!/usr/bin/env python3
import aws_cdk as cdk
from cdk_workshop.cdk_workshop_stack import CdkWorkshopStack
from config import * # 追加
app = cdk.App()
CdkWorkshopStack(app, "cdk-workshop",
env=cdk.Environment(account=AWS_ACCOUNT_ID, region=AWS_REGION), # 変更
)
app.synth()
ちなみに.gitignoreには既に追加されていた。