🥰

http4s で書いたサーバーを aws apprunner にデプロイする(with terraform)

2023/05/26に公開

サーバーのコードは以下の記事で書いたものと同じ想定.

https://zenn.dev/110416/articles/5beb6e34b8b4fd

インフラの設定

aws apprunner を terraform で作成します. まず必要なリソースを作成します.

aws apprunner を利用するために、デプロイ用の iam role, 実行用の iam role と ECR を用意します.

main.tf


resource "aws_iam_role" "runtime" {
  name               = "example-runtime"
  path               = "/"
  assume_role_policy = file("path/to/runtime.json")
}


resource "aws_iam_role" "deploy" {
  name               = "example-deploy"
  path               = "/"
  assume_role_policy = file("path/to/deploy.json")
}

resource "aws_iam_role_policy_attachment" "deploy" {
  role       = aws_iam_role.deploy.name
  // aws が提供する, apprunner ビルド時に ecr にアクセスするためのロール
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess"
}

resource "aws_ecr_repository" "example" {
  name                 = "example"
  image_tag_mutability = "MUTABLE"

  image_scanning_configuration {
    scan_on_push = true
  }
}

runtime.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "tasks.apprunner.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

deploy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "build.apprunner.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
terraform apply

ビルド定義

ビルド定義をゴニョゴニョします. apprunner で latest タグに更新があったら新しい revision をデプロイしたいので dockerUpdateLatest := true を設定します.

build.sbt
val V = new {
  val scala3 = "3.3.0"
  val http4s = "1.0.0-M36"
  val CE = "3.5.0"
}
lazy val server = project.in(file("server"))
  .enablePlugins(JavaAppPackaging)
  .enablePlugins(DockerPlugin)
  .settings(
    run / fork := true,
    scalaVersion := V.scala3,
    libraryDependencies ++= Seq(
      "org.http4s" %% "http4s-core" % V.http4s,
      "org.http4s" %% "http4s-dsl" % V.http4s,
      "org.http4s" %% "http4s-ember-server" % V.http4s,
      "org.typelevel" %% "cats-effect" % V.CE
    )
  )
  .settings(
    Docker /packageName := "example",
    dockerRepository := "<aws account id>.dkr.ecr.<region>.amazonaws.com",
    dockerBaseImage := "openjdk:17-jdk-slim-bullseye",
    dockerExposedPorts ++= Seq(8080),
    dockerUpdateLatest := true,
   )
sbt docker:publish

apprunner の作成

ecr にイメージがプッシュされたのを確認したら以下の設定を terraform に追加します.

main.tf

resource "aws_apprunner_service" "this" {
  service_name = "example"
  // アプリケーションのランタイムで利用する role. このロールに s3 や dynamodb にアクセスする権限を付与する. ecs の task role に相当する.
  instance_configuration {
    instance_role_arn = aws_iam_role.runtime.arn
  }
  source_configuration {
    authentication_configuration {
      // アプリケーションのデプロイに利用する role. プライベートな ECR からイメージを取得したりシークレットを読み出す際に必要. ecs の task execution role に相当する.
      access_role_arn = aws_iam_role.deploy.arn
    }

    image_repository {
      image_configuration {
        port = "8080"
      }
      image_identifier      = "${aws_ecr_repository.example.repository_url}:latest"
      image_repository_type = "ECR"
    }
  }

  lifecycle {
    ignore_changes = [
      source_configuration[0].image_repository[0].image_identifier
    ]
  }
}


terraform apply

Discussion