はじめに
AWS CDK × Scala + sbtでCloudformationのスタックやローカルにテスト環境を構築する方法をまとめてみた記事になります。
誰かの助けになれば嬉しいです。
対象読者
・AWS CDK × Scala + sbtを使って AWSサービスをデプロイしたいと考えている方
・CDKで出力した Cloudformationから localStack上に AWSサービスの環境を構築したい方
実行環境
・scala: 2.13.3
・sbt: 1.3.13
・aws-cdk: 1.57.0
・localStack: 0.10.0
・awscli-local: 0.7
・node: 12.18.3
サンプルリポジトリ
あわせて読むといいドキュメント
AWS CDK Developer Guide
https://docs.aws.amazon.com/cdk/latest/guide/home.html
AWS CDK API Reference
https://docs.aws.amazon.com/cdk/api/latest/docs/aws-construct-library.html
インストール
まずは、AWS CDKのcdkコマンドを実行できるようにaws-cdkをインストールします。
npm i aws-cdk@1.57.0 -g
built.sbtを作成する
次に、AWS CDKの cdkコマンドを実行できるように build.sbtを整えていきます。
root 直下にプロジェクトを作成してもいいのですが、sbt はマルチプロジェクトを作成できるので
今回は別途 cdk用のプロジェクトを作成しました。
lazy val commonSettings = Seq(
organization := "sample",
scalaVersion := "2.13.3",
scalacOptions := Seq(
"-deprecation",
"-feature"
),
scalafmtOnCompile in ThisBuild := true,
test in assembly := {}
)
lazy val cdkDependencies = Seq(
"software.amazon.awscdk" % "core" % awsCdkVersion,
"software.amazon.awscdk" % "apigateway" % awsCdkVersion,
"software.amazon.awscdk" % "lambda" % awsCdkVersion,
"software.amazon.awscdk" % "s3" % awsCdkVersion,
"software.amazon.awscdk" % "dynamodb" % awsCdkVersion,
"software.amazon.awscdk" % "stepfunctions" % awsCdkVersion,
"software.amazon.awscdk" % "stepfunctions-tasks" % awsCdkVersion,
"software.amazon.awscdk" % "ecr" % awsCdkVersion,
"software.amazon.awscdk" % "ecs-patterns" % awsCdkVersion,
"software.amazon.awscdk" % "ec2" % awsCdkVersion,
"software.amazon.awscdk" % "codecommit" % awsCdkVersion,
"software.amazon.awscdk" % "codebuild" % awsCdkVersion,
"software.amazon.awscdk" % "codepipeline" % awsCdkVersion,
"software.amazon.awscdk" % "codepipeline-actions" % awsCdkVersion
)
... (略)
lazy val cdk = (project in file("modules/cdk"))
.settings(commonSettings: _*)
.settings(
libraryDependencies ++= cdkDependencies
)
cdk.jsonを変更する
cdkをsbtで起動するために、**"app"**に書かれているものをsbt用に変更します。
別プロジェクト(cdk)として作成しているので起動は cdk/run を指定
また、後でローカル上に環境を構築したいのでsbt runが実行される際に出力される情報などを出力されないようにパラメータを追加しておきます。
また、マルチアカウントで運用されている場合、環境変数などを指定したい場合があると思いますので
cdk.jsonに必要そうな regionなどのキーを追加します。
{
"app": "sbt --error 'set showSuccess := false' cdk/run",
"context": {
"@aws-cdk/core:enableStackNameDuplicates": "true",
"aws-cdk:enableDiffNoFail": "true",
"local": {
"env": "local",
"region": "us-east-1",
"account_id": "000000000000"
},
"dev": {
"env": "dev",
"region": "ap-northeast-1",
"account_id": "xxxxxxxxxxxxx"
}
}
}
CDKでスタックを作成する
実際に AWS CDKを使ってスタック作成していきます。
ディレクトリ構成はこのような感じです。
├── README.md
├── build.sbt
├── buildspec.yml
├── cdk.json
├── modules
│ └── cdk
│ └── src
│ └── main
│ └── scala
│ ├── CdkApp.scala (Mainクラス)
│ ├── CodePipeLineStack.scala (CodeCommit+CodeBuild+CodePipelineのスタック)
│ ├── DynamoDBStack.scala (DynamoDB用のスタック)
│ ├── EcrStacks.scala(ECR用のスタック)
│ ├── FargateStack.scala(Fargate用のスタック)
│ ├── LambdaStack.scala(Lambda用のスタック)
│ ├── S3Stack.scala(S3用のスタック)
│ ├── SqsStack.scala(SQS用のスタック)
│ └── StepFunctionsStack.scala(StepFunctions用のスタック)
├── tmp
│
└── version.sbt
例えば、CDKで SQSのスタックを作成したい場合
Mainクラスとなる CdkApp.scalaに SQSを作成する Stackクラスを定義します。
object CdkApp {
def main(args: Array[String]): Unit = {
val app = new App
new SqsStack(app, "sqs", null)
app.synth
}
}
次に、SQSを作成するスタックには Stackクラスを継承したクラスを作成していきます。
AWS SDK v2 のように Builderパターンで Propsを書いてスタックを作ればOKです。
import software.amazon.awscdk.core.{Construct, Stack, StackProps}
import software.amazon.awscdk.services.sqs.{Queue, QueueProps}
import software.amazon.awscdk.core.Duration
class SqsStack(val scope: Construct, val id: String, val props: StackProps)
extends Stack(scope, id, props) {
private val env = this.getNode.tryGetContext("env").asInstanceOf[String]
private val testSqs = new Queue(
this,
s"test-sign-sqs-$env", // スタック内で一意となるidを指定
QueueProps
.builder()
.queueName(s"test-sign-$env") // キュー名
.visibilityTimeout(Duration.seconds(180)) // 可視性タイムアウト
.build()
)
}
定義するパラメータなどは、yamlなどでCloudfomarionを書く際のドキュメントを読むなり
AWS CDK API Referenceを参照しながら書いていきましょう。
・AWS Cloudformation: AWS::SQS::Queue
・AWS CDK API
ローカル上に環境を構築してみる
CDKを使い、プロファイル指定などをしてAWS上にデプロイする際は以下のコマンドで実行できます。
cdk deploy sqs --profile <任意のプロファイル> -c env=dev
また、実際にデプロイする前に、ローカル上で環境を構築して動作確認などができるように localStack を利用してローカル上に環境を構築してテストできるようにしてみました。
コマンドを毎回打つのが面倒なので、package.jsonなどに以下のような scriptを定義します。
"create-stack:sqs": "cdk synth sqs --c env=local > tmp/sqs.template.yml; awslocal cloudformation create-stack --stack-name local-sqs-stack --template-body file://./tmp/sqs.template.yml",
"delete-stack:sqs": "awslocal cloudformation delete-stack --stack-name local-sqs-stack"
あとは、localStackをdockerで起動しておき
以下のnpm run コマンドを実行すれば、ローカル上に SQSが作成されると思います。
npm run create-stack:sqs
作成した SQSを削除したい場合は以下のコマンドを実行してください。
npm run delete-stack:sqs
まとめ
普段、Cloudformatonをyamlなどで書き慣れていないといきなりCDKで書くのはシンドイかなと思いつつも
慣れ親しんだ、言語(Scala、Typescript、Pythonなど)で書けてデプロイまでできるので中々いい感じじゃないかなと・・・
現場からは以上です!