AWS Cloud Development Kit(CDK)でPythonを使ってみた

AWS Cloud Development Kit(CDK)でPython使ってみた

初めに

みなさん初めまして!!!
スカイアーチの石黒と申します!!

最近こんな記事を見かけました。
AWS Cloud Development Kit(CDK)でPythonとTypeScriptが使用可能に!!!

AWS CDKを触ったことがないのですが
何やらPythonでまた便利なことができるようになった様子…
これは試してみねば!!!の精神で今回取り組んでみることにしました。

AWS Cloud Development Kit (CDK)とは?

そもそもAWS CDKとは何なのかというところから調べました。

現在の対応言語は TypeScript、 JavaScript そして Java で、.NET と Python を近々ご案内予定です。
AWS CDK はソフトウェア開発のフレームワークであり、クラウドのインフラストラクチャをコードで定義して
CloudFormation でプロビジョニングできます。CDK は AWS のサービスと統合され、
高レベルかつオブジェクト指向の抽象概念を使ってAWS リソースを定義できます。
CDK によってモダンなプログラミング言語を使ってAWS インフラストラクチャを見通しよく効率よく定義できるため、
アプリケーションからインフラストラクチャまで一貫した開発体験 (development experience) が得られます。

AWS CDKを使えばPythonのコードでAWSの環境構築を行えるようです。

CDK はクラウドインフラストラクチャの「コンパイラ」であると考えてください。
CDKは Constructs というハイレベルなクラスライブラリ群を提供します。
Constructsは抽象化されたAWSリソースで、AWSのベストプラクティスに従った設定を内包します。
Constructsはオブジェクト指向の CDK application に割り当て可能です。
CDK application は個別のアプリケーションのインフラストラクチャを定義し、繰り返し使われる複雑な処理を管理します
CDK application を実行することによって AWS の “アセンブリ言語” である、CloudFormation テンプレートが生成されます。
これでテンプレートを CloudFormation のプロビジョニングエンジンで処理する準備が整います。
CDK tools はアプリケーションインフラストラクチャのスタック定義を容易にし、
CloudFormation サービスがスタックのプロビジョニングを安全性および信頼性高く実施します。

ただし、CDKはあくまでコンパイラという位置付けで、CDKそのものがAWSの環境構築をしてくれるという意味ではないようです。
AWS CDKを用いることでCloudFormationテンプレートが用意とデプロイができ、間接的にAWSの環境構築を行えるようです。

試してみよう

Pythonワークショップを参考にMacで作業を進めます。

まずAWS CDKコマンドラインインターフェイス(CLI) を入れます。
npmのインストールはこちらを参考にしました。

$ npm install -g aws-cdk

CDKプロジェクトを入れるディレクトリを作成します。
$ mkdir cdk-workshop && cd cdk-workshop

サンプルのCDKプロジェクトを作ります。

$ cdk init app --language=python
$ tree
.
├── README.md
├── app.py
├── cdk.json
├── hello
│ ├── __init__.py
│ ├── hello.egg-info
│ │ ├── PKG-INFO
│ │ ├── SOURCES.txt
│ │ ├── dependency_links.txt
│ │ ├── requires.txt
│ │ └── top_level.txt
│ ├── hello_construct.py
│ └── hello_stack.py
├── requirements.txt
├── setup.py
└── tests
├── __init__.py
└── unit
├── __init__.py
└── test_hello_construct.py

virtualenvをアクティブにし、必要な依存関係をインストールします。

$ source .env/bin/activate
(.env)$ pip install -r requirements.txt

サンプルでリージョン別に、アプリが2つ準備されていました。
MyStackクラスをインスタンス化して用意するようです。

(.env)$ cat app.py
#!/usr/bin/env python3

from aws_cdk import core

from hello.hello_stack import MyStack

app = core.App()
MyStack(app, "hello-cdk-1", env={'region': 'us-east-2'})
MyStack(app, "hello-cdk-2", env={'region': 'us-west-2'})

app.synth()

次にスタック(CloudFormationで作成される環境群)の内容を見ていきましょう。

  • hello/hello_stack.py
  • アプリの中核となるメインスタック
  • 4つのバケットを作成する
  • SQSキューを1つ作成する
  • SNSトピックを1つ作成する
(.env)$ cat hello/hello_stack.py
from aws_cdk import (
 aws_iam as iam,
 aws_sqs as sqs,
 aws_sns as sns,
 aws_sns_subscriptions as subs,
 core
)

from hello_construct import HelloConstruct

class MyStack(core.Stack):

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

queue = sqs.Queue(
 self, "MyFirstQueue",
 visibility_timeout=core.Duration.seconds(300),
)

topic = sns.Topic(
 self, "MyFirstTopic",
 display_name="My First Topic"
)

topic.add_subscription(subs.SqsSubscription(queue))

hello = HelloConstruct(self, "MyHelloConstruct", num_buckets=4)
user = iam.User(self, "MyUser")
hello.grant_read(user)
  • hello/hello_construct.py
  • 可変数のS3バケットを作成する
(.env)$ cat hello/hello_construct.py
from aws_cdk import (
 aws_iam as iam,
 aws_s3 as s3,
 core,
)

class HelloConstruct(core.Construct):

@property
def buckets(self):
return tuple(self._buckets)

def __init__(self, scope: core.Construct, id: str, num_buckets: int) -> None:
super().__init__(scope, id)
self._buckets = []
for i in range(0, num_buckets):
 self._buckets.append(s3.Bucket(self, f"Bucket-{i}"))

def grant_read(self, principal: iam.IPrincipal):
 for b in self.buckets:
  b.grant_read(principal, "*")

cdk lsで利用可能なアプリのリストを取得することができます。

$ cdk ls
hello-cdk-1
hello-cdk-2

cdk synthでデプロイする際に利用するアプリをCloudFormationのテンプレートとして標準出力させ、確認します。
デフォルトだとyaml形式のため、json形式で出力したい場合には-jまたは–jsonオプションで出力します。

cdk synth hello-cdk-1
Resources:
MyFirstQueueFF09316A:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 300
Metadata:
aws:cdk:path: hello-cdk-1/MyFirstQueue/Resource
...

さあデプロイしていきましょう。
AWS CDKアプリを初めてデプロイする場合は「bootstrap」をインストールする必要があるようです。
bootstrapはツールキットの操作に必要なものだそうなので必ずインストールしておきましょう。

$ cdk bootstrap
⏳ Bootstrapping environment aws://000000000000/us-east-2...
⏳ Bootstrapping environment aws://000000000000//us-west-2...

今回は米国西部(オレゴン)のアプリをデプロイしていきます。

$ cdk deploy hello-cdk-2
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 │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${MyFirstQueu │ Allow │ sqs:SendMessa │ Service:sns.a │ "ArnEquals": { │
│ │ e.Arn} │ │ ge │ mazonaws.com │ "aws:SourceA │
│ │ │ │ │ │ rn": "${MyFirs │
│ │ │ │ │ │ tTopic}" │
│ │ │ │ │ │ } │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${MyHelloCons │ Allow │ s3:GetBucket* │ AWS:${MyUser} │ │
│ │ truct/Bucket- │ │ s3:GetObject* │ │ │
│ │ 0.Arn} │ │ s3:List* │ │ │
│ │ ${MyHelloCons │ │ │ │ │
│ │ truct/Bucket- │ │ │ │ │
│ │ 0.Arn}/* │ │ │ │ │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${MyHelloCons │ Allow │ s3:GetBucket* │ AWS:${MyUser} │ │
│ │ truct/Bucket- │ │ s3:GetObject* │ │ │
│ │ 1.Arn} │ │ s3:List* │ │ │
│ │ ${MyHelloCons │ │ │ │ │
│ │ truct/Bucket- │ │ │ │ │
│ │ 1.Arn}/* │ │ │ │ │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${MyHelloCons │ Allow │ s3:GetBucket* │ AWS:${MyUser} │ │
│ │ truct/Bucket- │ │ s3:GetObject* │ │ │
│ │ 2.Arn} │ │ s3:List* │ │ │
│ │ ${MyHelloCons │ │ │ │ │
│ │ truct/Bucket- │ │ │ │ │
│ │ 2.Arn}/* │ │ │ │ │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${MyHelloCons │ Allow │ s3:GetBucket* │ AWS:${MyUser} │ │
│ │ truct/Bucket- │ │ s3:GetObject* │ │ │
│ │ 3.Arn} │ │ s3:List* │ │ │
│ │ ${MyHelloCons │ │ │ │ │
│ │ truct/Bucket- │ │ │ │ │
│ │ 3.Arn}/* │ │ │ │ │
└───┴───────────────┴────────┴───────────────┴───────────────┴────────────────┘
Do you wish to deploy these changes (y/n)? y
hello-cdk-2: deploying...
hello-cdk-2: creating CloudFormation changeset...
0/12 | 9:21:13 | CREATE_IN_PROGRESS | AWS::S3::Bucket | MyHelloConstruct/Bucket-2 (MyHelloConstructBucket2C1DA3656)
0/12 | 9:21:13 | CREATE_IN_PROGRESS | AWS::S3::Bucket | MyHelloConstruct/Bucket-0 (MyHelloConstructBucket0DAEC57E1)
...
✅ hello-cdk-2
Stack ARN:
arn:aws:cloudformation:us-west-2:000000000000:stack/hello-cdk-2/00000-00000

これでS3バケットが4つ、SNSトピックが1つ、SQSキューが1つ、作成されるはずです
お疲れ様でした

疑問

cdk synthのコマンドの用途について疑問が出てきました。
synthはsynthesize(合成)という言葉の意味から推察して
最初はスタックをネストする用途だと思っていたのですが、
どうやらそうではなく、
cdk synth helpには
Synthesizes and prints the CloudFormation template for this stack
(このスタックのCloudFormationテンプレートを合成して出力します)とあります。

ここで私は、単純に1つのアプリから1つのCloudFormationテンプレートを作るという用途かと思い、
実行してみると、実際には全てのアプリのテンプレートが作成されています。

今回参考にしたワークショップの例にあるcdk synth hello-cdk-1という書き方だと
まるでhello-cdk-1だけ、テンプレートが作成されるように思いますが
実はhello-cdk-2も作成されています。
引数なしでcdk synthと実行しても同様です。

さらにcdk synth以外のcdk lscdk deployの各コマンド実行時にも
cdk.outディレクトリに全てのスタックのCloudFormationのテンプレートが作成される(すでに存在する場合は全て上書き)ため、

cdk synthはCloudFormationのテンプレートが作成ができるという意味で考えると、このコマンドの必要性が薄く、
あくまでデプロイ前に、CloudFormationのテンプレートを標準出力させて確認する用途がメインなのかと思いました。

これに関してはどこかで思い違いをしているかもしれないので、引き続き調査したいと思います。

投稿者プロフィール

ishiguro
新卒1年目です。
暇なときにはARアプリやLINEBotなどで遊んでいます。

ABOUTこの記事をかいた人

新卒1年目です。 暇なときにはARアプリやLINEBotなどで遊んでいます。

NEW POSTこのライターの最新記事