はじめに
本記事は、私自身の備忘録を兼ねてAWS CDKをこれから始める方の一助になればと思い、AWS CDKの使い方等をまとめたものです。
今回は、AWS CDKを実行する際にスタックの中でS3にファイルをアップロードする方法を確認しています。
なお、本記事は私自身の経験を基に記載していますが、間違いがあったらすみません。
CDKでS3にファイルをアップロードしたい状況
主にzipにまとめたソース、ライブラリからLambda Functionを作成する際ですが、CDKスタックの実行でファイルをS3にアップロードしたくなることがあります。また、S3で静的webページをホスティングする際もCDKで直接S3にファイルをアップロードしたくなる状況かもしれませんね。
通常のリソースタイプでは、S3へのアップロードはできませんので、こういった場合にアップロードする方法を確認します。
環境
本記事は以下の環境を使用して記載しています。
- AWS Cloud9
- AWS CDK:2.80.0
- Python: 3.10.11
- Node.js: 16.20.0
また、以下の記事に基づいてAWS CDKの環境を作成しています。
CDKスタックでS3にファイルをアップロードする方法
では、本題のS3にファイルをアップロードする方法を確認します。今回は、S3バケットを作成し、そのS3バケットにCloud9のローカルファイルをアップロードするCDKスタックを作成したいと思います。
アップロードするためには、aws_cdk.aws_s3_deployment
を使用します。
まず、準備として、アップロードするファイルを以下のように用意します。
(.venv) user_name:~/environment/cdk-app (master) $ tree ./upload-test/
./upload-test/
└── upload-dir
└── upload-file.txt
1 directory, 1 file
(.venv) user_name:~/environment/cdk-app (master) $ cat ./upload-test/upload-dir/upload-file.txt
test file.
アップロードするファイルの準備ができたので、スタックのプログラムを作成します。S3バケットの作成とそのS3バケットにアップロードするaws_s3_deploymentの処理を以下のように記述しました。
1点注意点として、file_pathに指定可能なのは、ディレクトリかzipファイルになります。zipでないファイルを直接指定はできません。ここでは、ディレクトリを指定しました。
from aws_cdk import (
Stack,
aws_s3_deployment as s3deploy,
aws_s3 as s3,
RemovalPolicy
)
from constructs import Construct
import random, string
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-yyyymmdd",
versioned=True,
removal_policy=RemovalPolicy.DESTROY
)
file_path = "./upload-test/upload-dir/"
s3_deploy = s3deploy.BucketDeployment(
self,
"FileUploadS3",
sources=[s3deploy.Source.asset(file_path)],
destination_bucket=s3bucket,
)
この状態でデプロイします。
(.venv) user_name:~/environment/cdk-app (master) $ cdk deploy
✨ Synthesis time: 18.38s
(中略)
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 │
├───┼───────────────────────────────────────────────────────┼────────┼───────────────────────────────────────────────────────┼────────────────────────────────────────────────────────┼───────────┤
│ + │ ${Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC │ Allow │ sts:AssumeRole │ Service:lambda.amazonaws.com │ │
│ │ 9EB8756C/ServiceRole.Arn} │ │ │ │ │
├───┼───────────────────────────────────────────────────────┼────────┼───────────────────────────────────────────────────────┼────────────────────────────────────────────────────────┼───────────┤
│ + │ ${MyS3Bucket.Arn} │ Allow │ s3:Abort* │ AWS:${Custom::CDKBucketDeployment8693BB64968944B69AAFB │ │
│ │ ${MyS3Bucket.Arn}/* │ │ s3:DeleteObject* │ 0CC9EB8756C/ServiceRole} │ │
│ │ │ │ s3:GetBucket* │ │ │
│ │ │ │ s3:GetObject* │ │ │
│ │ │ │ s3:List* │ │ │
│ │ │ │ s3:PutObject │ │ │
│ │ │ │ s3:PutObjectLegalHold │ │ │
│ │ │ │ s3:PutObjectRetention │ │ │
│ │ │ │ s3:PutObjectTagging │ │ │
│ │ │ │ s3:PutObjectVersionTagging │ │ │
├───┼───────────────────────────────────────────────────────┼────────┼───────────────────────────────────────────────────────┼────────────────────────────────────────────────────────┼───────────┤
│ + │ arn:${AWS::Partition}:s3:::{"Fn::Sub":"cdk-hnb659fds- │ Allow │ s3:GetBucket* │ AWS:${Custom::CDKBucketDeployment8693BB64968944B69AAFB │ │
│ │ assets-${AWS::AccountId}-${AWS::Region}"} │ │ s3:GetObject* │ 0CC9EB8756C/ServiceRole} │ │
│ │ arn:${AWS::Partition}:s3:::{"Fn::Sub":"cdk-hnb659fds- │ │ s3:List* │ │ │
│ │ assets-${AWS::AccountId}-${AWS::Region}"}/* │ │ │ │ │
└───┴───────────────────────────────────────────────────────┴────────┴───────────────────────────────────────────────────────┴────────────────────────────────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬────────────────────────────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│ │ Resource │ Managed Policy ARN │
├───┼────────────────────────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴────────────────────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘
(中略)
Do you wish to deploy these changes (y/n)? y
CdkAppStack: deploying... [1/1]
CdkAppStack: creating CloudFormation changeset...
✅ CdkAppStack
✨ Deployment time: 127.91s
Stack ARN:
(中略)
✨ Total time: 146.29s
cdk deploy
するとなぜか記載してないIAMロールを作成して良いか確認されます。合成されたCloudFormation Templateを確認すると解りますが、IAMロールだけでなく、Lambda Functionも作成されます。aws_s3_deploymentは、実体としてはLambda Functionのようですね。
では、S3バケットを確認してみます。
アップロードされていることが分かります。
次にzipファイルのアップロードを確認してみます。(一度cdk destroy
してます。)
以下のようにzipファイルを準備しました。
(.venv) user_name:~/environment/cdk-app (master) $ tree ./upload-test/
./upload-test/
└── upload-dir
└── upload-file.zip
1 directory, 1 file
(.venv) user_name:~/environment/cdk-app (master) $ unzip -l ./upload-test/upload-dir/upload-file.zip
Archive: ./upload-test/upload-dir/upload-file.zip
Length Date Time Name
--------- ---------- ----- ----
11 06-06-2023 12:26 upload-file.txt
--------- -------
11 1 file
この状態でデプロイします。(コードは変更してません。=file_pathの指定はディレクトリ)
(.venv) user_name:~/environment/cdk-app (master) $ cdk deploy
S3バケットを確認すると、zipファイルがアップロードされていることが分かります。
今度は、コードは変更してfile_pathの指定をディレクトリではなく、zipファイルを直接指定してみます。
from aws_cdk import (
Stack,
aws_s3_deployment as s3deploy,
aws_s3 as s3,
RemovalPolicy
)
from constructs import Construct
import random, string
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-yyyymmdd",
versioned=True,
removal_policy=RemovalPolicy.DESTROY
)
# ↓↓ zipファイルを直接指定するように変更
file_path = "./upload-test/upload-dir/upload-file.zip"
s3_deploy = s3deploy.BucketDeployment(
self,
"FileUploadS3",
sources=[s3deploy.Source.asset(file_path)],
destination_bucket=s3bucket,
)
デプロイしてS3バケットを確認します。
(.venv) user_name:~/environment/cdk-app (master) $ cdk deploy
zipファイルが展開されてS3バケットにアップロードされていることが分かります。このようにzipファイルを直接指定する場合とディレクトリを指定する場合で、S3へのアップロードのされ方が異なるので、注意が必要ですね。Lambda Functionを作成する場合はディレクトリを指定するなど、用途に応じて制御する必要がありそうです。
まとめ
AWS CDKでデプロイの際にS3にファイルをアップロードする方法を確認しました。手動操作を挟むことなく一連の流れとしてファイルアップロード→Lambda Functionの作成などが行えるのは助かりますね。
最後まで読んでいただいてありがとうございます。
少しでも参考になれば幸いです。