Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What is going on with this article?
@nishiemon

AWS CDK × Scala + sbtでAWSサービスをデプロイ + ローカル上に環境構築する

はじめに

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用のプロジェクトを作成しました。

build.sbt
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などのキーを追加します。

cdk.json
{
  "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クラスを定義します。

CdkApp.scala
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です。

SqsStack.scala
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を定義します。

package.json
"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など)で書けてデプロイまでできるので中々いい感じじゃないかなと・・・

現場からは以上です!

5
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
nishiemon
デザイン課 Angular Scala 関数型 Vimが好き

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
5
Help us understand the problem. What is going on with this article?