yikegaya’s blog

yikegayaのブログ

terraformでRDSに接続するAPIサーバをECSにデプロイする

terraformでGoのAPIを動かすECSを作ろうとした時、DBの接続で結構手こずった。

初回のterraform実行でRDS構築してさらにECR(コンテナのレジストリ)からdockerイメージをpullしてECS内にコンテナを立ち上げるんだけど、その時に以下の2点がうまくできずにしばらくハマった。

  1. どうやってRDSのエンドポイントとかDB名、ユーザ、パスワード情報渡そうか
  2. Migrationのタイミング

で、とりあえず作った内容を書いてみる

1のRDSの情報

terraformならECSのresouce定義内でRDSのエンドポイントやDB名を参照できる。ユーザ、パスワードはterraformの変数として定義して同じように渡せる。

以下タスク定義内に書いたコンテナの情報。dockerイメージはAPIエンドポイントを立ち上げるGoで書いたサーバ。

resource "aws_ecs_task_definition" "movie-backend" {
  family = "movie_backend"

  requires_compatibilities = ["FARGATE"]

  cpu    = "256"
  memory = "512"

  network_mode = "awsvpc"

  execution_role_arn    = aws_iam_role.ecs_task_execution_role.arn

  container_definitions = <<EOL
[
  {
    "name": "movie_backend",
    "image": "public.ecr.aws/e9z3g6v3/movie-info-backend:latest",
    "portMappings": [
      {
        "containerPort": 8080,
        "hostPort": 8080
      }
    ],
    "environment": [
      {
        "name": "DB_HOST",
        "value": "${aws_db_instance.movie-backend.endpoint}"
      },
      {
        "name": "DB_USER",
        "value": "${var.db_user}"
      },
      {
        "name": "DB_PASSWORD",
        "value": "${var.db_pass}"
      },
      {
        "name": "DB_NAME",
        "value": "${aws_db_instance.movie-backend.name}"
      },
      {
        "name": "DATA_SOURCE",
        "value": "${var.db_user}:${var.db_pass}@tcp(${aws_db_instance.movie-backend.endpoint})/${aws_db_instance.movie-backend.name}?charset=utf8&parseTime=True&loc=Local"
      }
    ],
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-region": "ap-northeast-1",
        "awslogs-stream-prefix": "movie-backend",
        "awslogs-group": "/ecs/movie-backend"
      }
    }
  }
]
EOL
}

こんな感じでそのままGoのコードに渡せばMySQLにつながるように文字列作れるの便利だな。。

${var.db_user}:${var.db_pass}@tcp(${aws_db_instance.movie-backend.endpoint})/${aws_db_instance.movie-backend.name}?charset=utf8&parseTime=True&loc=Local

2のMigration

ここはとりあえずDB、Migration用のECSのタスク定義を作って手動で実行することにした。今のところ手動だけどここはAWSのCodeBuild使って自動化もできそう

作ったterraformのコード。大体上のサーバ実行用のタスク定義と同じなんだけど、commandオプションでイメージ内で最終的に実行されるコマンドをMigrationに上書きしている

resource "aws_ecs_task_definition" "movie-db-migration" { family = "movie_db_migration"

requires_compatibilities = ["FARGATE"]

cpu = "256" memory = "512"

network_mode = "awsvpc"

execution_role_arn = aws_iam_role.ecs_task_execution_role.arn

container_definitions = <<EOL [ { "name": "movie_db_migrate", "image": "public.ecr.aws/e9z3g6v3/movie-info-backend:latest", "command": ["sql-migrate", "up"], "environment": [ { "name": "DATA_SOURCE", "value": "${var.db_user}:${var.db_pass}@tcp(${aws_db_instance.movie-backend.endpoint})/${aws_db_instance.movie-backend.name}?charset=utf8&parseTime=True&loc=Local" } ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "movie-db-migration", "awslogs-group": "/ecs/movie-db-migration" } } } ] EOL }

以上の作業レポジトリ

github.com