LoginSignup
3
4

More than 1 year has passed since last update.

【AWS CDK (Python)】 AWS CDKの始め方

Posted at

はじめに

本記事は、私自身の備忘録を兼ねてAWS CDKをこれから始める方の一助になればと思い、AWS CDKの使い方等をまとめたものです。
今回は、Cloud9を使用しAWS CDKの導入~簡単なリソースの作成、削除までの一連の流れを確認しています。
なお、本記事は私自身の経験を基に記載していますが、間違いがあったらすみません。

AWS CDKとは

AWS CDK(AWS Cloud Development Kit)は、AWSのリソースをPythonやTypeScript等のコードで定義して、AWS CloudFormationでデプロイすることができます。
本記事の記載時点で、JavaScript、TypeScript、Python、Java、C#、Goに対応していて、AWS CDKを使用することで、使い慣れたプログラミング言語でAWSリソースのデプロイができます。
また、YAMLやJsonで記載するCloudFormation Templateと違い、ループ等が使用できるため、効率的にコードを記載することができます。

環境

本記事は以下の環境を使用して記載しています。

  • AWS Cloud9
  • AWS CDK:2.80.0
  • Python: 3.10.11
  • Node.js: 16.20.0

AWS CDKの始め方

以下の流れでAWS CDKの環境作成および実行確認をしていきます。

1. Cloud9の作成
2. Pythonのバージョンアップ
3. AWS CDKのインストール、初期化
4. コード変更
5. デプロイ
6. リソース変更
7. リソース削除


1. Cloud9の作成

まず、AWS CDKを実行するCloud9を作成します。
マネージメントコンソールのサービスメニューから開発者用ツール>Cloud9を選び、Create environmentをクリックしてCloud9の環境作成する画面を開きます。
image.png

作成するCloud9の名前を入力し、Instance typeを選びます。
image.png

CreateをクリックしてCloud9を作成します。
image.png

作成完了のメッセージが出たら、OpenをクリックしてCloud9を起動します。
image.png

Cloud9のIDEが開きました。下部にあるTerminalでAWS CDKの実行を行います。(レイアウトは自由に変更可能です。)
image.png

これでCloud9の作成完了です。

2. Pythonのバージョンアップ

Cloud9に標準でインストールされているPythonが古いので、バージョンアップします。
ここからは、主にCloud9のTerminalでコマンドを実行していきます。

user_name:~/environment $ python --version
Python 3.7.16

まず、Pythonのバージョンアップに必要なpyenvをインストールします。

user_name:~/environment $ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
user_name:~/environment $ ~/.pyenv/bin/pyenv --version
pyenv 2.3.17-10-g920ef145

インストールしたpyenvにパスを通します。

user_name:~/environment $ cat << 'EOT' >> ~/.bashrc
> export PATH="$HOME/.pyenv/bin:$PATH"
> eval "$(pyenv init -)"
> EOT
user_name:~/environment $ source ~/.bashrc

インストール可能なPythonの最新バージョンが3.10.11のようなので、インストールするとOpenSSLが見つからないとERRORが出ました。

user_name:~/environment $ pyenv install --list | grep 3.10
  3.10.0
 (中略)
  3.10.10
  3.10.11
user_name:~/environment $ pyenv install 3.10.11
Downloading Python-3.10.11.tar.xz...
-> https://www.python.org/ftp/python/3.10.11/Python-3.10.11.tar.xz
Installing Python-3.10.11...
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/ec2-user/.pyenv/versions/3.10.11/lib/python3.10/ssl.py", line 99, in <module>
    import _ssl             # if we can't import it, let the error propagate
ModuleNotFoundError: No module named '_ssl'
ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?

Please consult to the Wiki page to fix the problem.
https://github.com/pyenv/pyenv/wiki/Common-build-problems

BUILD FAILED (Amazon Linux 2 using python-build 2.3.17-10-g920ef145)

Inspect or clean up the working tree at /tmp/python-build.20230523135937.12069
Results logged to /tmp/python-build.20230523135937.12069.log

Last 10 log lines:
        LD_LIBRARY_PATH=/tmp/python-build.20230523135937.12069/Python-3.10.11 ./python -E -m ensurepip \
                $ensurepip --root=/ ; \
fi
Looking in links: /tmp/tmpvfgc3rev
Processing /tmp/tmpvfgc3rev/setuptools-65.5.0-py3-none-any.whl
Processing /tmp/tmpvfgc3rev/pip-23.0.1-py3-none-any.whl
Installing collected packages: setuptools, pip
  WARNING: The scripts pip3 and pip3.10 are installed in '/home/ec2-user/.pyenv/versions/3.10.11/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed pip-23.0.1 setuptools-65.5.0

openssl11とopenssl11-develをインストールするとopenssl11-develがopenssl-develとコンフリクトしていると言われるので、openssl-develをアンインストールし、再度openssl11-develをインストールします。

user_name:~/environment $ sudo yum install -y openssl11 openssl11-devel
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
244 packages excluded due to repository priority protections
Package 1:openssl11-1.1.1g-12.amzn2.0.14.x86_64 already installed and latest version
Resolving Dependencies
--> Running transaction check
---> Package openssl11-devel.x86_64 1:1.1.1g-12.amzn2.0.14 will be installed
--> Processing Conflict: 1:openssl11-devel-1.1.1g-12.amzn2.0.14.x86_64 conflicts openssl-devel
--> Finished Dependency Resolution
Error: openssl11-devel conflicts with 1:openssl-devel-1.0.2k-24.amzn2.0.6.x86_64
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest
user_name:~/environment $ sudo yum remove -y openssl-devel
user_name:~/environment $ sudo yum install -y openssl11-devel

再度Python3.10.11をインストールすると、ERRORが取れました。

user_name:~/environment $ pyenv install 3.10.11
Downloading Python-3.10.11.tar.xz...
-> https://www.python.org/ftp/python/3.10.11/Python-3.10.11.tar.xz
Installing Python-3.10.11...
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/ec2-user/.pyenv/versions/3.10.11/lib/python3.10/lzma.py", line 27, in <module>
    from _lzma import *
ModuleNotFoundError: No module named '_lzma'
WARNING: The Python lzma extension was not compiled. Missing the lzma lib?
Installed Python-3.10.11 to /home/ec2-user/.pyenv/versions/3.10.11

WARNINGが出ているので、xz-develをインストールします。もう一度Python3.10.11のインストールを確認するとWARNINGも取れました。

user_name:~/environment $ sudo yum -y update
user_name:~/environment $ sudo yum -y install xz-devel
user_name:~/environment $ pyenv install 3.10.11
pyenv: /home/ec2-user/.pyenv/versions/3.10.11 already exists
continue with installation? (y/N) y
Downloading Python-3.10.11.tar.xz...
-> https://www.python.org/ftp/python/3.10.11/Python-3.10.11.tar.xz
Installing Python-3.10.11...
Installed Python-3.10.11 to /home/ec2-user/.pyenv/versions/3.10.11

Pythonのバージョンをインストールした3.10.11に切り替えます。

user_name:~/environment $ pyenv global 3.10.11
user_name:~/environment $ python --version
Python 3.10.11

これでPythonのバージョンアップができました。

3. AWS CDKのインストール、初期化

次はAWS CDKのインストールですが、Cloud9を使用する場合、Cloud9にはAWS CDKが既にインストールされているため、インストールは不要です。

user_name:~/environment $ cdk --version
2.79.1 (build 2e7f8b7)

最新でない場合は、アップデートしましょう。

user_name:~/environment $ npm update -g cdk
user_name:~/environment $ cdk --version
2.80.0 (build bbdb16a)

AWS CDKの作業ディレクトリを作成して、AWS CDKプロジェクトを初期設定します。

user_name:~/environment $ mkdir cdk-app
user_name:~/environment $ cd cdk-app
user_name:~/environment/cdk-app $ cdk init app --language python

Python仮想環境をアクティブ化し、必要なモジュールをインストールします。

user_name:~/environment/cdk-app (master) $ source .venv/bin/activate
(.venv) user_name:~/environment/cdk-app (master) $ python -m pip install -r requirements.txt

4. コード変更

この時点で作業ディレクトリの下は以下のような構造になっています。
app.pyが、このアプリケーションのメインプログラム、cdk_app/cdk_app_stack.pyが、CDKスタックになり、S3などのAWSリソースを作成するコードを書いていくプログラムになります。(初期状態だと何も記載がないので、何も作成されない状態です。)

(.venv) user_name:~/environment/cdk-app (master) $ tree 
.
├── app.py
├── cdk_app
│   ├── cdk_app_stack.py
│   └── __init__.py
├── cdk.json
├── README.md
├── requirements-dev.txt
├── requirements.txt
├── source.bat
└── tests
    ├── __init__.py
    └── unit
        ├── __init__.py
        └── test_cdk_app_stack.py
app.py
#!/usr/bin/env python3
import os
import aws_cdk as cdk
from cdk_app.cdk_app_stack import CdkAppStack

app = cdk.App()
CdkAppStack(app, "CdkAppStack",
    # If you don't specify 'env', this stack will be environment-agnostic.
    # Account/Region-dependent features and context lookups will not work,
    # but a single synthesized template can be deployed anywhere.

    # Uncomment the next line to specialize this stack for the AWS Account
    # and Region that are implied by the current CLI configuration.

    #env=cdk.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION')),

    # Uncomment the next line if you know exactly what Account and Region you
    # want to deploy the stack to. */

    #env=cdk.Environment(account='123456789012', region='us-east-1'),

    # For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html
    )

app.synth()
cdk_app/cdk_app_stack.py
from aws_cdk import (
    # Duration,
    Stack,
    # aws_sqs as sqs,
)
from constructs import Construct

class CdkAppStack(Stack):

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

        # The code that defines your stack goes here

        # example resource
        # queue = sqs.Queue(
        #     self, "CdkAppQueue",
        #     visibility_timeout=Duration.seconds(300),
        # )

サンプルとして記載されているコードを試しにS3バケットを作成するように変更します。

cdk_app/cdk_app_stack.py
from aws_cdk import (
    # Duration,
    Stack,
    # ↓↓ コード変更 ↓↓
    aws_s3 as s3,
    RemovalPolicy
    # ↑↑ コード変更 ↑↑
)
from constructs import Construct

class CdkAppStack(Stack):

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

        # ↓↓ コード変更 ↓↓
        s3bucket = s3.Bucket(
            self,
            "MyS3Bucket",
            bucket_name = "cdk-test-bucket-2023aabb",
            removal_policy=RemovalPolicy.DESTROY
        )
        # ↑↑ コード変更 ↑↑

cdk diffを実行すると作成されるリソースの確認ができます。(今回だと、ResourcesにS3バケットが作成されることが確認できます。)

(.venv) user_name:~/environment/cdk-app (master) $ cdk diff
Stack CdkAppStack
Parameters
[+] Parameter BootstrapVersion BootstrapVersion: {"Type":"AWS::SSM::Parameter::Value<String>","Default":"/cdk-bootstrap/xxxxxxxxx/version","Description":"Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"}

Conditions
[+] Condition CDKMetadata/Condition 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"]}]}]}

Resources
[+] AWS::S3::Bucket MyS3Bucket MyS3BucketXXXXXXXX 

Other Changes
[+] Unknown 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."}]}}

5. デプロイ

では、実際にS3バケットを作成(デプロイ)していきますが、今回は初回なので、cdk bootstrapを実行します。
cdk bootstrapは、AWS CDKでデプロイする際に初回だけ必要なコマンドで、実行することで、デプロイに必要なリソース(S3バケットやCloudFormationの実行ロールなど)が作成されます。
なお、cdk bootstrapは"初回だけ"必要と書きましたが、リージョンの単位で実行する必要があるので、一度cdk bootstrapした後に利用するリージョンが増えた場合は再度cdk bootstrapを実行する必要があります。

(.venv) user_name:~/environment/cdk-app (master) $ cdk bootstrap

ブートストラップが終わったら、いよいよデプロイです。デプロイは、cdk deployを実行します。

(.venv) user_name:~/environment/cdk-app (master) $ cdk deploy

✨  Synthesis time: 17.62s

CdkAppStack:  start: Building
(中略)
CdkAppStack: deploying... [1/1]
CdkAppStack: creating CloudFormation changeset...

 ✅  CdkAppStack

✨  Deployment time: 36.93s

Stack ARN:
(中略)
✨  Total time: 54.55s

これで、デプロイが完了しました。実際にマネージメントコンソールでS3バケットを確認してみます。ちゃんと出来てますね!
image.png

6. リソース変更

次にデプロイしたリソースを変更してみましょう。先ほど作成したS3バケットのバージョニングを無効から有効に変更してみたいと思います。
まず、現在のS3バケットのバージョニングの設定を確認すると、無効になってます。
image.png

では、AWS CDKで設定を変更していきます。
バージョニングを有効にするには、先ほどのコードにversioned=True,を追加します。

cdk_app/cdk_app_stack.py
from aws_cdk import (
    # Duration,
    Stack,
    # ↓↓ コード変更 ↓↓
    aws_s3 as s3,
    RemovalPolicy
    # ↑↑ コード変更 ↑↑
)
from constructs import Construct

class CdkAppStack(Stack):

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

        # ↓↓ コード変更 ↓↓
        s3bucket = s3.Bucket(
            self,
            "MyS3Bucket",
            bucket_name = "cdk-test-bucket-2023aabb",
            # ↓↓ バージョニング有効 ↓↓
            versioned=True,
            # ↑↑ バージョニング有効 ↑↑
            removal_policy=RemovalPolicy.DESTROY
        )
        # ↑↑ コード変更 ↑↑

コードを変更して、cdk diffを実行するとVersioningConfigurationの設定が追加されることが確認できます。

(.venv) user_name:~/environment/cdk-app (master) $ cdk diff
Stack CdkAppStack
Resources
[~] AWS::S3::Bucket MyS3Bucket MyS3BucketXXXXXXXX 
 └─ [+] VersioningConfiguration
     └─ {"Status":"Enabled"}

cdk deployを実行します。

(.venv) user_name:~/environment/cdk-app (master) $ cdk deploy

S3バケットのバージョニングの設定を確認すると、有効に変更されていました!
image.png

7. リソース削除

最後に作成したリソースを削除します。削除は、cdk destroyを実行します。

(.venv) user_name:~/environment/cdk-app (master) $ cdk destroy
Are you sure you want to delete: CdkAppStack (y/n)? y
CdkAppStack: destroying... [1/1]

 ✅  CdkAppStack: destroyed

マネージメントコンソールでS3バケットを確認すると削除されていることが確認できました。
image.png

まとめ

Cloud9を作成し、AWS CDKの導入~リソースのデプロイ、削除までの一連の流れを確認できました。今回は、S3バケット1つだけだったのであまり感じないですが、作成するリソースが沢山だったり何度も作成する状況だとマネージメントコンソールから作成するより楽で間違いもなく作成できそうです。
最後まで読んでいただいてありがとうございます。
少しでも参考になれば幸いです。

参考文献

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4