Slide 1

Slide 1 text

サーバーレスパターンを元に AWS CDKでデータ基盤を構築する 2024.7.31 データ事業本部 笠原 宏

Slide 2

Slide 2 text

Xへの投稿の際は、 ハッシュタグ #cm_odyssey でお願いいたします。 2 お願い

Slide 3

Slide 3 text

⾃⼰紹介 l 笠原 宏 l データ事業本部ビジネスソリューション部SAチーム ソリューションアーキテクト l 新潟県新潟市在住 l JAWS-UG新潟⽀部 / Python機械学習勉強会in新潟 / JaSST新潟 / SWANII / Cloudflare Meetup Niigata l AWS Community Builder / 2024 Japan AWS All Certifications Engineer l 好きなAWSサービス: S3 / Lambda / Step Functions 3 @kasacchiful @kasacchiful

Slide 4

Slide 4 text

⽬次 4 1. 背景 2. サーバーレスパターン 3. CDK環境の準備 4. ⼩規模データ基盤構築 5. 中‧⼤規模データ基盤構築 6. 考慮事項 7. まとめ

Slide 5

Slide 5 text

1. 背景 5

Slide 6

Slide 6 text

背景 6 l 移⾏ l 新規構築

Slide 7

Slide 7 text

背景 7 l サーバーレスパターンを参考にデータ基盤 を構築中 l CDKでサーバーレスなデータ基盤構築時に 参考になるテンプレートをいくつか⽤意

Slide 8

Slide 8 text

2. サーバーレスパターン 8

Slide 9

Slide 9 text

サーバーレスパターン 9 https://aws.amazon.com/jp/serverless/patterns/serverless-pattern/

Slide 10

Slide 10 text

サーバーレス for AI/機械学習もある 10 https://aws.amazon.com/jp/serverless/patterns/serverless-pattern/

Slide 11

Slide 11 text

サーバーレスパターンを参考に 11 l 基本形から少しずつ取り⼊れてみる l いくつかのパターンを組み合わせて作る

Slide 12

Slide 12 text

3. CDK環境の準備 12

Slide 13

Slide 13 text

今回の構成 13 l CDK: TypeScript l Lambda: Python

Slide 14

Slide 14 text

今回の構成 14 l CDK: TypeScript l Lambda: Python l CDKは、サンプルコードが多い TypeScriptが理解しやすく扱いやすい l Lambdaは、Pythonがデータを扱いやすく、 Glueへの転⽤もしやすい l CDKで使うライブラリとLambdaで使うライブラリを 分けて管理しやすい

Slide 15

Slide 15 text

サンプルソースコード 15 l GitHubで公開 https://github.com/kasacchiful/serverless-pattern- on-cdk

Slide 16

Slide 16 text

CDK環境構築 16 npx cdk init --language typescript # cdkを初めて利用するアカウントに初回一度だけ実行 npx cdk bootstrap

Slide 17

Slide 17 text

4. ⼩規模データ基盤構築 17

Slide 18

Slide 18 text

まずは基本形 18 https://aws.amazon.com/jp/serverless/patterns/serverless-pattern/

Slide 19

Slide 19 text

今回の構成 19 l SourceとDestinationのバケットを分けた⽅が Lambda無限ループ実⾏を防ぎやすい l 慣れているなら同⼀バケットにしても良いが、 パスを分けることを忘れずに

Slide 20

Slide 20 text

CDKでのファイル構成 20 ├── README.md ├── bin │ └── serverless-pattern-on-cdk.ts ├── cdk.json ├── env ├── jest.config.js ├── lib │ └── simple-s3-data-processing-stack.ts ## Stack: SimpleS3DataProcessingStack の定義 ├── node_modules ├── package-lock.json ├── package.json ├── requirements.txt ├── resources │ └── simple-s3-data-processing ## Stack: SimpleS3DataProcessingStack のLambda関数リソース │ └── lambda │ └── data-processing.py ├── test └── tsconfig.json l 今回はサンプルコード毎に CDKスタックを分けている l Lambda関数のコードは resources ディレクトリ内に格納

Slide 21

Slide 21 text

スタック定義 (S3) 21 // S3 Buckets const sourceBucket = new Bucket(this, 'SourceBucket', { bucketName: `${props?.projectName}-source-bucket`, removalPolicy: cdk.RemovalPolicy.RETAIN, blockPublicAccess: BlockPublicAccess.BLOCK_ALL, encryption: BucketEncryption.S3_MANAGED, }); const destinationBucket = new Bucket(this, 'DestinationBucket', { bucketName: `${props?.projectName}-destination-bucket`, removalPolicy: cdk.RemovalPolicy.RETAIN, blockPublicAccess: BlockPublicAccess.BLOCK_ALL, encryption: BucketEncryption.S3_MANAGED, }); l バケットを2つ定義

Slide 22

Slide 22 text

スタック定義 (IAM Role) 22 FullAccessDestinationBucket: new PolicyDocument({ statements: [new PolicyStatement({ effect: Effect.ALLOW, actions: [ 's3:*', ], resources: [ destinationBucket.bucketArn, `${destinationBucket.bucketArn}/*`, ], })] }), } }); lambdaRole.addManagedPolicy( cdk.aws_iam.ManagedPolicy.fromAwsManagedPolicyName( 'service-role/AWSLambdaBasicExecutionRole' )); // IAM Role for Lambda const lambdaRole = new Role(this, 'LambdaRole', { roleName: `${props?.projectName}-lambda-role`, assumedBy: new ServicePrincipal('lambda.amazonaws.com'), inlinePolicies: { ReadOnlySourceBucket: new PolicyDocument({ statements: [new PolicyStatement({ effect: Effect.ALLOW, actions: [ 's3:Get*', 's3:List*', ], resources: [ sourceBucket.bucketArn, `${sourceBucket.bucketArn}/*`, ], })] }), l LambdaにアタッチするIAMロールを定義

Slide 23

Slide 23 text

スタック定義 (Lambda Layer) 23 // Lambda for Data Processing const awsSdkForPandasLayer = LayerVersion.fromLayerVersionArn( this, 'AwsSdkForPandasLayer', 'arn:aws:lambda:ap-northeast-1:336392948345:layer:AWSSDKPandas-Python312- Arm64:12' ); l AWS SDK for Pandasを利⽤したいので、 今回はManagedで⽤意されているLambda Layerを利⽤する l 詳細はAWS SDK for Pandasのドキュメントを参照 https://aws-sdk-pandas.readthedocs.io/en/stable/install.html

Slide 24

Slide 24 text

スタック定義 (Lambda Function) 24 const dataProcessingFunction = new Function(this, 'DataProcessingFunction', { functionName: `${props?.projectName}-data-processing-function`, runtime: Runtime.PYTHON_3_12, architecture: Architecture.ARM_64, timeout: cdk.Duration.seconds(30), memorySize: 512, handler: 'data-processing.lambda_handler', code: Code.fromAsset('./resources/simple-s3-data-processing/lambda/'), role: lambdaRole, layers: [ awsSdkForPandasLayer, ], environment: { 'DESTINATION_BUCKET_NAME': destinationBucket.bucketName, }, });

Slide 25

Slide 25 text

スタック定義 (イベントソース) 25 // add event source. dataProcessingFunction.addEventSource( new cdk.aws_lambda_event_sources.S3EventSourceV2(sourceBucket, { events: [EventType.OBJECT_CREATED,], })); l Lambda関数のトリガーを設定 l 今回はソースバケットにファイルが置かれた際に起動するようにした

Slide 26

Slide 26 text

Lambda関数コード 26 import awswrangler as wr def lambda_handler(event, context): ## <省略> ## to parquet (ex: sample.csv => sample.parquet) sourcePath = f's3://{os.path.join(sourceBucket, sourceObject)}' destinationPath = f's3://{os.path.join(destinationBucket, os.path.dirname(sourceObject))}{os.path.splitext(os.path.basename(sourceObject))[0]}.parquet' df = wr.s3.read_csv(sourcePath, dtype_backend='pyarrow') wr.s3.to_parquet(df, path=destinationPath, index=False) ## <省略> l AWS SDK for Pandasを使って、 ソースバケットにあるCSVファイルを読み込み、 デスティネーションバケットにParquetファイルを書き出す

Slide 27

Slide 27 text

デプロイ 27 ## Cloudformationテンプレート確認 npx cdk synth SimpleS3DataProcessingStack ## 変更内容の比較 npx cdk diff SimpleS3DataProcessingStack ## デプロイ npx cdk deploy SimpleS3DataProcessingStack

Slide 28

Slide 28 text

動作確認 28 ソースバケットに CSVファイルを配置すると デスティネーションバケットに Parquetファイルが配置された

Slide 29

Slide 29 text

応⽤編: 並列実⾏する 29 https://aws.amazon.com/jp/serverless/patterns/serverless-pattern/

Slide 30

Slide 30 text

年度毎のファイルを並列で処理してマージ 30 https://dev.classmethod.jp/articles/data-analysis-infrastructure-from-serverless-patterns-devio2022/

Slide 31

Slide 31 text

応⽤編: SNS/SQSで繋げる 31 https://aws.amazon.com/jp/serverless/patterns/serverless-pattern/

Slide 32

Slide 32 text

SQSの前段にはSNSを 32 https://dev.classmethod.jp/articles/sns-topic-should-be-placed-behind-sqs-queue/

Slide 33

Slide 33 text

FIFOトピック‧キューで順序保証‧重複排除 33 l FIFOトピック‧FIFOキューで順序保証‧ 重複排除が簡単に実現

Slide 34

Slide 34 text

今回の構成 34 l 2つの処理をSNS/SQSで繋げる l 2つの処理は⾮同期で実⾏される

Slide 35

Slide 35 text

CDKでのファイル構成 35 ├── README.md ├── bin │ └── serverless-pattern-on-cdk.ts ├── cdk.json ├── env ├── jest.config.js ├── lib │ └── event-driven-collaboration-stack.ts ## Stack: EventDrivenCollaborationStack の定義 ├── node_modules ├── package-lock.json ├── package.json ├── requirements.txt ├── resources │ └── event-driven-collaboration-stack ## Stack: EventDrivenCollaborationStack のLambda関数リソース │ └── lambda │ ├── t-_change_format.py │ └── t-_change_type.py ├── test └── tsconfig.json l 今回はサンプルコード毎に CDKスタックを分けている l Lambda関数のコードは resources ディレクトリ内に格納

Slide 36

Slide 36 text

スタック定義 (SNS‧SQS) 36 // SNS const snsTopic = new Topic(this, 'SnsTopic', { topicName: `${props?.projectName}-sns-topic.fifo`, fifo: true, contentBasedDeduplication: false, }); // SQS const sqs_queue = new Queue(this, 'SqsQueue', { queueName: `${props?.projectName}-sqs-queue.fifo`, fifo: true, contentBasedDeduplication: false, }); snsTopic.addSubscription( new SqsSubscription(sqs_queue, { rawMessageDelivery: true, })); l FIFOトピックとFIFOキューを定義 l トピックのサブスクリプション先は キューとなる

Slide 37

Slide 37 text

スタック定義 (SNS‧SQS) 37 sqs_queue.addToResourcePolicy(new PolicyStatement({ effect: Effect.ALLOW, actions: [ 'sqs:*', ], resources: [ sqs_queue.queueArn, ], principals: [ new AccountRootPrincipal, ], })); l キューのリソースポリシーには、 SNSトピックからの「SendMessage」 およびLambda関数への 「ReceiveMessage」「DeleteMessage」は CDKが付与してくれる l 今回はポリシー定義例として、 AWSアカウントでのキュー操作を 全て許可する設定を追加している

Slide 38

Slide 38 text

スタック定義 (Lambda関数1) 38 ## <省略> ## to parquet (ex: sample.csv => sample.parquet) sourcePath = f's3://{os.path.join(sourceBucket, sourceObject)}' destinationPath = f's3://{os.path.join(destinationBucket, os.path.dirname(sourceObject))}{os.path.splitext(os.path.basename(sourceObject))[0]}.parquet' df = wr.s3.read_csv(sourcePath, dtype_backend='pyarrow') wr.s3.to_parquet(df, path=destinationPath, index=False) sns = boto3.client('sns') sns.publish( TopicArn=snsTopicArn, Message=json.dumps({ 'bucket_name': destinationBucket, 'object_key': f'{os.path.dirname(sourceObject)}{os.path.splitext(os.path.basename(sourceObject))[0]}.parquet' }), MessageDeduplicationId=str(uuid.uuid4()), MessageGroupId='toChangeFormat', ) l 最初の処理では、Parquetファイルに変換後、 SNSトピックにメッセージを送信している l 重複排除として、今回は MessageDedupulicationIdと MessageGroupIdを設定する⽅法を⽤いている

Slide 39

Slide 39 text

スタック定義 (Lambda関数2) 39 def lambda_handler(event, context): msg = json.loads(event['Records'][0].get('body', {})) ## <省略> ## to change type (ex: column: date, string => date) sourcePath = f's3://{os.path.join(sourceBucket, sourceObject)}' destinationPath = f's3://{os.path.join(destinationBucket, os.path.dirname(sourceObject))}{os.path.basename(sourceObject)}' df = wr.s3.read_parquet(sourcePath) df = df.astype({'date': 'date64[pyarrow]'}) wr.s3.to_parquet(df, path=destinationPath, index=False) l 次の処理では、キューのポーリング実装不要で キューのメッセージを取得してから ⼀部のカラムの型を変更する処理を⼊れている

Slide 40

Slide 40 text

デプロイ 40 ## Cloudformationテンプレート確認 npx cdk synth EventDrivenCollaborationStack ## 変更内容の比較 npx cdk diff EventDrivenCollaborationStack ## デプロイ npx cdk deploy EventDrivenCollaborationStack

Slide 41

Slide 41 text

応⽤編: EventBridgeで繋げる 41 https://aws.amazon.com/jp/serverless/patterns/serverless-pattern/

Slide 42

Slide 42 text

Lambdaをメッセージ通知のためだけに使わない 42 SQSキューメッセージを受け取 って、Step Functionsのステー トマシンを起動したい場合: キューのメッセージをポーリン グしてステートマシン起動のた めのLambdaを使っている

Slide 43

Slide 43 text

Lambdaをメッセージ通知のためだけに使わない 43 l Lambdaの代わりに EventBridge Pipesを使え ばキューのメッセージをポ ーリングしてステートマシ ンを起動できる Pipes

Slide 44

Slide 44 text

応⽤編: Step Functionsで繋げる 44 https://aws.amazon.com/jp/serverless/patterns/serverless-pattern/

Slide 45

Slide 45 text

ETLフローをステートマシンで制御 45 l Lambda / Glue / ECS / EKS / Batch な どのリソース使って ETLフロー制御 l 並列実⾏制御も容易

Slide 46

Slide 46 text

Expressワークフローで⾼速にフロー制御 46 l アプリのBFFや、5 分以内で⾼速に処 理したい制御に

Slide 47

Slide 47 text

5. 中‧⼤規模データ基盤構築 47

Slide 48

Slide 48 text

基本形をどう繋げるか 48 ステートマシン内で繋げる? SNS/SQSで⾮同期に繋げる?

Slide 49

Slide 49 text

基本形をどう繋げるか 49 l 制御が容易 l イベント履歴等のクォー タに注意 l 処理毎に分離 l 処理間I/Fをあらかじめ決 めておくとよい

Slide 50

Slide 50 text

巨⼤なステートマシンを分割する 50 https://dev.classmethod.jp/articles/data-analysis-infrastructure-from-serverless-patterns-devio2022/ ステートマシンを⼊れ⼦にするのも⼀つの⼿段

Slide 51

Slide 51 text

今回の構成 51 l 2つのステートマシン制御の処理をSNS/SQS/Pipesで繋げる l 最初のステートマシンは時間起動 l 2つの処理は⾮同期で実⾏される

Slide 52

Slide 52 text

CDKでのファイル構成 52 ├── README.md ├── bin │ └── serverless-pattern-on-cdk.ts ├── cdk.json ├── env ├── jest.config.js ├── lib │ ├── state-machine-chain │ │ ├── common │ │ │ └── s3.ts │ │ ├── first-processing │ │ │ ├── lambda.ts │ │ │ └── step-functions.ts │ │ ├── inter-processing │ │ │ └── sns-sqs.ts │ │ └── second-processing │ │ │ ├── lambda.ts │ │ │ └── step-functions.ts │ └── state-machine-chain-stack.ts ## Stack: StateMachineChainStack ...(省略)... ├── resources │ └── state-machine-chain-stack │ ├── first-processing │ │ ├── lambda │ │ │ └── to-change-format.py │ │ └── step-functions │ │ └── first-processing-state-machine.asl.yaml │ └── second-processing │ ├── lambda │ │ └── to-change-type.py │ └── step-functions │ └── second-processing-state-machine.asl.yaml ...(省略)... l 今回はサンプルコード毎に CDKスタックを分けている l Lambda関数のコードは resources ディレクトリ内に格納 l 処理毎にリソースを分けた

Slide 53

Slide 53 text

スタック定義 (Step Functions1) 53 // State Machine this.stateMachine = new StateMachine(this, 'FirstProcessingStateMachine', { stateMachineName: `${props.projectName}-first-processing-state-machine`, role: stateMachineRole, definitionBody: DefinitionBody.fromFile( 'resources/state-machine-chain/first-processing/step-functions/first-processing-state-machine.asl.yaml' ), definitionSubstitutions: { ToChangeFormatFunctionArn: props.toChangeFormatFunction.functionArn, SnsTopicArn: props.snsTopic.topicArn, } }); // event schedule rule new Rule(this, 'FirstProcessStateMachineScheduleRule', { ruleName: `${props.projectName}-first-state-machine-rule`, schedule: Schedule.cron({ minute: '0', hour: '21', }), targets: [new SfnStateMachine(this.stateMachine)], enabled: false, }); l ステートマシンはASL YAMLで定義

Slide 54

Slide 54 text

スタック定義 (Step Functions1) 54

Slide 55

Slide 55 text

スタック定義 (Lambda関数1) 55 def lambda_handler(event, context): sourceBucket = os.environ.get('SOURCE_BUCKET_NAME') destinationBucket = os.environ.get('DESTINATION_BUCKET_NAME') destinationPaths = [] s3 = boto3.resource('s3') obj_list = [ k.key for k in s3.Bucket(sourceBucket).objects.all() if (os.path.splitext(os.path.basename(k.key))[1] == '.csv')] for sourceObject in obj_list: ## to parquet (ex: sample.csv => sample.parquet) sourcePath = f's3://{os.path.join(sourceBucket, sourceObject)}' destinationPath = f's3://{os.path.join(destinationBucket, os.path.dirname(sourceObject), os.path.splitext(os.path.basename(sourceObject))[0])}.parquet' df = wr.s3.read_csv(sourcePath, dtype_backend='pyarrow') wr.s3.to_parquet(df, path=destinationPath, index=False) destinationPaths.append({"bucket": destinationBucket, "path": destinationPath}) return { 'code': 200, 'msg': { 'destination': destinationPaths }, } l SNSトピックへの送信は ステートマシンに任せる

Slide 56

Slide 56 text

スタック定義 (Step Functions2) 56 // State Machine this.stateMachine = new StateMachine(this, 'SecondProcessingStateMachine', { stateMachineName: `${props.projectName}-second-processing-state-machine`, role: stateMachineRole, definitionBody: DefinitionBody.fromFile( 'resources/state-machine-chain/second-processing/step-functions/second-processing-state-machine.asl.yaml' ), definitionSubstitutions: { ToChangeTypeFunctionArn: props.toChangeTypeFunction.functionArn, } }); // Pipe new CfnPipe(this, 'Pipe', { source: props.sqsQueue.queueArn, sourceParameters: { sqsQueueParameters: { batchSize: 1, }, }, target: this.stateMachine.stateMachineArn, targetParameters: { stepFunctionStateMachineParameters: { invocationType: 'FIRE_AND_FORGET’, } // Invoke asynchronously }, roleArn: pipeRunnerRole.roleArn }); l EventBridge Pipesは、 L1コンストラクトで定義 l v2.150.0時点ではL2は まだ⽤意されていない

Slide 57

Slide 57 text

スタック定義 (Step Functions2) 57

Slide 58

Slide 58 text

スタック定義 (Lambda関数2) 58 def lambda_handler(event, context): sourceBucket = event.get('bucket') sourcePath = event.get('path') sourceObject = re.match(f'^s3://{sourceBucket}/(.+)', sourcePath).group(1) destinationBucket = os.environ.get('DESTINATION_BUCKET_NAME') ## to change type (ex: column: date, string => date) destinationPath = f's3://{os.path.join(destinationBucket, os.path.dirname(sourceObject), os.path.basename(sourceObject))}' df = wr.s3.read_parquet(sourcePath) df = df.astype({'date': 'date64[pyarrow]'}) wr.s3.to_parquet(df, path=destinationPath, index=False) return { 'code': 200, 'msg': { 'destination': destinationPath }, } l 変換対象が複数あっても、 ステートマシンのMapによって 渡されるs3パスは1つだけ

Slide 59

Slide 59 text

デプロイ 59 ## Cloudformationテンプレート確認 npx cdk synth StateMachineChainStack ## 変更内容の比較 npx cdk diff StateMachineChainStack ## デプロイ npx cdk deploy StateMachineChainStack

Slide 60

Slide 60 text

動作確認 60 ソースバケットに CSVファイルを配置して デスティネーションバケットに Parquetファイルが配置された 最初の処理のステートマシンを 実行すると

Slide 61

Slide 61 text

6. 考慮事項 61

Slide 62

Slide 62 text

コンピュートリソースを考える 62 l Lambda以外にも、Glue / ECS / EKS / Batch / EMR などのコンピュートリソース を使うこともある l 必要に応じて使い分けておくとよい

Slide 63

Slide 63 text

ざっと⽐較 63 サービス名 起動速度 処理速度 スケール 速度 処理時間 開発 しやすさ 管理 しやすさ Lambda ◎ ◯ ◎ △ ◎ ◎ Glue △ ◎ △ ◎ ◯ ◯ ECS/EKS ◯ ◯ △ ◎ ◎ ◯ Batch △ ◎ ◯ ◎ ◯ ◯ EMR △ ◎ △ ◎ ◯ △ l どのコンピュートリソースを使用したら良いか、検討すること l 処理毎にコンピュートリソースを変えることも検討すること ※個人主観込

Slide 64

Slide 64 text

処理毎に変える 64 l データファイルに応じてLambdaまたはGlueジョブで処理

Slide 65

Slide 65 text

処理毎に配置する 65 ├── README.md ├── bin │ └── serverless-pattern-on-cdk.ts ├── cdk.json ├── env ├── jest.config.js ├── lib │ ├── state-machine-chain │ │ ├── common │ │ │ └── s3.ts │ │ ├── first-processing │ │ │ ├── lambda.ts │ │ │ └── step-functions.ts │ │ ├── inter-processing │ │ │ └── sns-sqs.ts │ │ └── second-processing │ │ │ ├── lambda.ts │ │ │ └── step-functions.ts │ └── state-machine-chain-stack.ts ## Stack: StateMachineChainStack ...(省略)... ├── resources │ └── state-machine-chain-stack │ ├── first-processing │ │ ├── lambda │ │ │ └── to-change-format.py │ │ └── step-functions │ │ └── first-processing-state-machine.asl.yaml │ └── second-processing │ ├── lambda │ │ └── to-change-type.py │ └── step-functions │ └── second-processing-state-machine.asl.yaml ...(省略)... l 規模が⼤きくなれば、 処理毎にファイルを分けて 配置した⽅が⾒通しが良くなる

Slide 66

Slide 66 text

環境毎のパラメータ設定 66 import { Environment } from "aws-cdk-lib"; export interface AppParameter { env: Environment; envName: string; projectName: string; } export const devParameter: AppParameter = { envName: "dev", projectName: "sls-patterns", env: {}, }; export const prodParameter: AppParameter = { envName: "prod", projectName: "sls-patterns", env: {}, }; #!/usr/bin/env node import 'source-map-support/register'; import * as cdk from 'aws-cdk-lib'; import { devParameter, prodParameter } from "../env_parameters"; import { SlsPatternsStack } from ‘../lib/sls-patterns-stack.ts’; const app = new cdk.App(); const envKey = app.node.tryGetContext("environment") ?? "dev"; // default: dev let parameter; if (envKey === "dev") { parameter = devParameter; } else { parameter = prodParameter; } new SlsPatternsStack(app, `SlsPatternsStack-${parameter.envName}`, { description: `${parameter.projectName}-${parameter.envName}`, env: { account: parameter.env?.account || process.env.CDK_DEFAULT_ACCOUNT, region: parameter.env?.region || process.env.CDK_DEFAULT_REGION, }, projectName: parameter.projectName, envName: parameter.envName, }); l cdk.jsonに定義するか、 パラメータ定義ファイルを作成して、 読み込ませる ./env_parameters.ts ./bin/sls-patterns.ts

Slide 67

Slide 67 text

インフラ定義とアプリ定義 67 l VPC等インフラ定義をCDKで⾏うか否か? l インフラとアプリのスタックを分ける l インフラはCDKではなくCfnテンプレー トで定義する

Slide 68

Slide 68 text

インフラはCfnテンプレートで定義 68 l 我々の開発では、インフラはCfnテンプレートで分 けた⽅が都合が良いケースが多い l そもそもインフラはすでに⽤意されていて我々に 変更権限がない場合がある l クロスアカウント連携は事前に構築して疎通を確 認してから、アプリをその上で動かしたい

Slide 69

Slide 69 text

CDKでのファイル構成 69 ├── README.md ├── bin │ └── serverless-pattern-on-cdk.ts ├── cdk.json ├── cfn │ └── infrastructure.yaml ├── env ├── jest.config.js ├── lib │ └── event-driven-collaboration-stack.ts ## Stack: EventDrivenCollaborationStack の定義 ├── node_modules ├── package-lock.json ├── package.json ├── requirements.txt ├── resources │ └── event-driven-collaboration-stack ## Stack: EventDrivenCollaborationStack のLambda関数リソース │ └── lambda │ ├── t-_change_format.py │ └── t-_change_type.py ├── test └── tsconfig.json l Cfnテンプレートも CDKプロジェクト配下に 配置しておいて、 リポジトリ内で管理 l CDKのデプロイとは別に AWS CLI等で適⽤

Slide 70

Slide 70 text

でもやっぱりCDKで管理したい 70 l CDKスタックを分けて、スタック参照 l インフラコードのテストはCDKの⽅がしや すいはず l もう少しチーム内での知⾒がたまったら、 改めて⾒直したい

Slide 71

Slide 71 text

どれをインフラに含めるか問題 71 l VPC等ネットワーク系: インフラスタック l RDS等データベース系: インフラスタック l S3等ストレージ系: インフラスタック? l S3バケットをアプリスタックで: 複数⼈で開発やテストの際でも、簡単にデプロイできて確認 しやすい l S3バケットをインフラスタック: 複数⼈で開発やテストの際に、オブジェクトパスが被ってし まうケースもあるので、やりにくい 現状は、プロジェクト毎に判断してインフラとアプリを分けている

Slide 72

Slide 72 text

7. まとめ 72

Slide 73

Slide 73 text

まとめ 73 l サーバーレスパターンを参考にデータ基盤を構築 中 l CDKでサーバーレスなデータ基盤構築時に参考にな るテンプレートをいくつか⽤意 l 処理間をどう繋いでいくかがポイント l まだ考慮事項がいろいろあるので、知⾒がたまっ たら改めて⾒直したい

Slide 74

Slide 74 text

JAWS PANKRATION 2024 74 l 8/24 (⼟) 20:40 ‒ 21:00 で登壇予定 l TT-28「Serverless FrameworkからAWS CDKとAWS SAMに移⾏する際に⼼がけてい ること」をお話しします

Slide 75

Slide 75 text

No content