🥳

TerraformでECS on Fargate環境にRedashを構築する

2023/03/31に公開

概要

さまざまなデータソースに接続して、ダッシュボードやクエリーを実行出来て便利なRedashですが、ホスティングサービスが終了してしまい、自前でホスティングする必要があったのと、ECS on Fargateでの構築事例でわかりやすい記事がなかったため、誰でも構築出来るレベルの丁寧さを意識して構築手順を書いていきたいと思います。
なお実用的に使えるように、google ssoまでやっていきます。

環境

私の実行環境は以下です

  • Mac OS X 12.6
  • Terraform 1.2.1

この記事でやらないこと

  • Terraformの細かい説明
  • Terraformの実行ユーザーの作成

手順

  1. ディレクトリの作成
  2. 設定等のtfファイルの作成
  3. ネットワークの構築
  4. データベースの構築
  5. Redisの構築
  6. パラメータストアへの登録
  7. ロードバランサーの構築
  8. DNSレコードの作成
  9. ロググループの作成
  10. ECSの構築
  11. ECS タスク定義用のJSONファイルを作成
  12. Google OAuth SSOの設定
  13. Terraform apply
  14. create_dbタスクを実行
  15. adminユーザーの作成
  16. google認証の設定
ファイル名 ファイル内容 備考
main.tf provider情報などを管理する
locals.tf ローカル変数の管理
vpc.tf vpcの構成情報を管理 terraform aws modulesを使う
rds.tf データベースの構成情報を管理 Postgresqlで構築
redis.tf Elasticcacheの構成情報を管理 Redisで構築
parameter_store.tf 各種接続情報を管理 System Managerのパラメータストアに各種接続情報を登録する
route53.tf ドメインやACMの構成情報を管理
alb.tf ロードバランサーの構成情報を管理
cloudwatch.tf CloudWatchの構成情報を管理
ecs.tf ECSの構成情報を管理 ECSのCluster, Service, Taskをこのファイルに定義
create_db.json create_dbタスクの定義 redashのmigrationのみを行うタスク
server.json redashを起動させるためのタスク定義 常時起動させておくためのタスク
variables.tf google api keyなどを管理 tfvarsから受け取ってterraform内で利用出来る様にする
terraform.tfvars google api keyを格納する terraform.tfvarsは平文が入るので、gitignoreしておく

1. ディレクトリの作成

今回はredashというディレクトリにterraformのコードを書いたファイルを格納していきます。
また後の手順で使用するECSのタスク定義を格納するtask_definitionsというディレクトリも作成しておきます

// redashディレクトリを作成
$ mkdir redash

// redashディレクトリに移動
$ cd redash

// タスク定義JSONファイルを格納するディレクトリ
$ mkdir task_definitions

2. 設定等のtfファイルの作成

main.tf

providerなどを管理するファイル名同様にメインとなるファイルを作成する

今回はサンプルなので、stateファイルはローカルで管理するが、実際にはterraform cloudもしくは、s3で管理するのがいいと思います

main.tf
terraform {
  required_version = "~> 1.2.1"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "4.22.0"
    }
  }
}

locals.tf

ローカル変数を定義するファイルを作成します。

locals.tf
locals {
  app_name = "redash"
  redash_url = "https://redash.hoge.com"
  tags = {
    Terraform = "true"
    App       = local.app_name
  }
}

3. ネットワークの構築

vpcはterraform aws modulesのvpc moduleを使って作成すると楽です。

vpc.tf
module "vpc" {
  source                        = "terraform-aws-modules/vpc/aws"
  version                       = "3.14.0"
  name                          = "vpc-${local.app_name}"
  cidr                          = "10.0.0.0/16"
  azs                           = ["ap-northeast-1a", "ap-northeast-1c"]
  private_subnets               = ["10.0.0.0/24", "10.0.1.0/24"]
  public_subnets                = ["10.0.10.0/24", "10.0.11.0/24"]
  enable_nat_gateway            = true
  single_nat_gateway            = true

  vpc_tags = local.tags
}

4. データベースの構築

Redashの設定などを保存しておくためのデータベース構築します。

rds.tf
resource "random_password" "database-password" {
  length  = 16
  special = false
}

resource "random_string" "database-name" {
  length  = 16
  special = false
}

resource "random_string" "database-username" {
  length  = 16
  special = false
}

resource "aws_security_group" "postgresql" {
  name   = "${local.app_name}-postgresql-sg"
  vpc_id = module.vpc.vpc_id

  ingress {
    # ecsのセキュリティーグループを作るまではコメントアウト
    # security_groups = [aws_security_group.ecs.id]
    from_port = 5432
    to_port   = 5432
    protocol  = "tcp"
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  tags = local.tags
}

resource "aws_db_subnet_group" "redash" {
  name       = "${local.app_name}-db-subnets"
  subnet_ids = module.vpc.private_subnets
  
  tags       = local.tags
}

resource "aws_db_instance" "redash" {
  identifier = local.app_name

  allocated_storage = 10
  engine            = "postgres"
  engine_version    = "13.6"
  instance_class    = "db.m5.large"

  db_name                = "${local.app_name}_${random_string.database-name.result}"
  username               = "${local.app_name}_${random_string.database-username.result}"
  password               = random_password.database-password.result
  db_subnet_group_name   = aws_db_subnet_group.redash.name
  vpc_security_group_ids = [aws_security_group.postgresql.id]

  skip_final_snapshot = true
  
  tags = local.tags
}

5. Redisの構築

ジョブキューライブラリのRQを動作させるために必要となるRedisをElasticcacheで構築していく

redis.tf
resource "aws_security_group" "redis" {
  name   = "${local.app_name}-redis-sg"
  vpc_id = module.vpc.vpc_id

  ingress {
    # ecsのセキュリティーグループを作ったら、コメントインします
    # security_groups = [aws_security_group.ecs.id]
    from_port       = 6379
    to_port         = 6379
    protocol        = "tcp"
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  tags = local.tags
}

resource "aws_elasticache_subnet_group" "redis" {
  name       = "${local.app_name}-redis-subnet"
  subnet_ids = module.vpc.private_subnets
  
  tags       = local.tags
}

resource "aws_elasticache_replication_group" "redash" {
  replication_group_id        = local.app_name
  node_type                   = "cache.t3.micro"
  description                 = "for redis"
  automatic_failover_enabled  = true
  preferred_cache_cluster_azs = ["ap-northeast-1a", "ap-northeast-1c"]
  num_cache_clusters          = 2
  engine_version              = "6.2"
  parameter_group_name        = "default.redis6.x"
  port                        = 6379
  subnet_group_name           = aws_elasticache_subnet_group.redis.name
  security_group_ids          = [aws_security_group.redis.id]

  lifecycle {
    ignore_changes = [num_cache_clusters]
  }
  
  tags = local.tags
}

resource "aws_elasticache_cluster" "redash" {
  count                = 1
  cluster_id           = local.app_name
  replication_group_id = aws_elasticache_replication_group.redash.id
  
  tags = local.tags
}

6. パラメータストアへの登録

データベースの構築でデータベースの接続情報をrandomリソースを使用して作成しましたが、その値をECSのタスク定義のJSONファイルから参照出来るようにAWS System Managerに登録しておきます

parameter_store.tf
resource "aws_ssm_parameter" "secret-db-name" {
  depends_on = [aws_db_instance.redash]
  name       = "/${local.app_name}/database/name"
  type       = "SecureString"
  value      = aws_db_instance.redash.db_name

  tags = local.tags
}

resource "aws_ssm_parameter" "secret-db-username" {
  depends_on = [aws_db_instance.redash]
  name       = "/${local.app_name}/database/username"
  type       = "SecureString"
  value      = aws_db_instance.redash.username

  tags = local.tags
}

resource "aws_ssm_parameter" "secret-db-host" {
  depends_on = [aws_db_instance.redash]
  name       = "/${local.app_name}/database/host"
  type       = "SecureString"
  value      = aws_db_instance.redash.address

  tags = local.tags
}

resource "aws_ssm_parameter" "secret-db-password" {
  depends_on = [aws_db_instance.redash]
  name       = "/${local.app_name}/database/password"
  type       = "SecureString"
  value      = aws_db_instance.redash.password

  tags = local.tags
}

resource "aws_ssm_parameter" "secret-db-url" {
  depends_on = [aws_db_instance.redash]
  name       = "/${local.app_name}/database/url"
  type       = "SecureString"
  value      = "postgres://${aws_db_instance.redash.username}:${aws_db_instance.redash.password}@${aws_db_instance.redash.endpoint}/${aws_db_instance.redash.db_name}"

  tags = local.tags
}

7. ロードバランサーの作成

Redashは起動に時間が掛かり、更にFargateもタスクの起動に時間が掛かるため、albのヘルスチェックが普通の設定ではタイムアウトしてしまうので、猶予を与えてヘルスチェックをヘルシーにしてあげる必要があります。

社内利用でのRedashを想定しているため、albのセキュリティーグループはIPを絞っておきます。

alb.tf
resource "aws_security_group" "alb" {
  name   = "${local.app_name}-alb-sg"
  vpc_id = module.vpc.vpc_id

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = local.tags
}

resource "aws_security_group_rule" "http" {
  security_group_id = aws_security_group.alb.id

  type        = "ingress"
  from_port   = 80
  to_port     = 80
  protocol    = "tcp"
  cidr_blocks = ["許可するIP/32"]
}

resource "aws_security_group_rule" "https" {
  security_group_id = aws_security_group.alb.id

  type        = "ingress"
  from_port   = 443
  to_port     = 443
  protocol    = "tcp"
  cidr_blocks = ["許可するIP/32"]
}

resource "aws_lb" "redash" {
  load_balancer_type = "application"
  name               = "${local.app_name}-alb"

  internal        = false
  subnets         = module.vpc.public_subnets
  security_groups = [aws_security_group.alb.id]
}

resource "aws_lb_target_group" "redash" {
  name   = "${local.app_name}-alb-tg"
  vpc_id = module.vpc.vpc_id
  port   = 80
  deregistration_delay = "10"
  target_type          = "ip"
  protocol             = "HTTP"

  health_check {
    protocol            = "HTTP"
    path                = "/ping"
    interval            = 300
    timeout             = 120
    port                = 5000
    matcher             = "200-302"
    healthy_threshold   = 5
    unhealthy_threshold = 3
  }
}

resource "aws_lb_listener" "http" {
  load_balancer_arn = aws_lb.redash.arn

  port     = 80
  protocol = "HTTP"

  default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.redash.arn
  }
}

resource "aws_lb_listener" "https" {
  load_balancer_arn = aws_lb.redash.arn

  port     = 443
  protocol = "HTTPS"

  ssl_policy      = "ELBSecurityPolicy-2016-08"
  certificate_arn = data.aws_acm_certificate.main.arn

  default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.redash.arn
  }
}

8. DNSの登録

今回はゾーンとACMは既にある前提でTerraformを組みます。
既にあるリソースを使う場合は、dataソースを利用します。

route53.tf
data "aws_route53_zone" "main" {
  name = "hoge.com"
}

data "aws_acm_certificate" "main" {
  domain = "hoge.com"
}

resource "aws_route53_record" "redash" {
  zone_id = data.aws_route53_zone.main.id
  name    = "hoge.com"
  type    = "A"

  alias {
    name                   = aws_lb.redash.dns_name
    zone_id                = aws_lb.redash.zone_id
    evaluate_target_health = true
  }
}

9. ロググループの作成

ECSのログをためておくcloudwatchのロググループを作成します。

cloudwatch.tf
resource "aws_cloudwatch_log_group" "redash" {
  name              = "/ecs/${local.app_name}"
  retention_in_days = 3
  
  tags = local.tags
}

10. タスク定義用JSONファイルの作成

今回二つのタスクを用意します。
二つのタスクの役割としては、create_db.jsonはredash構築後に一回だけ実行して、マイグレーションを行う用途でserver.jsonは常時起動しておくための用途となります。

二つのタスクを作成するためにそれぞれJSONファイルを作成していきます。

create_db.json

create_db.json
[
  {
    "name": "create_db",
    "image": "redash/redash:10.0.0.b50363",
    "cpu": 0,
    "stopTimeout": 60,
    "memoryReservation": null,
    "environment": [
      {
        "name": "REDASH_HOST",
        "value": "${redash_host_url}"
      },
      {
        "name": "PYTHONUNBUFFERED",
        "value": "0"
      },
      {
        "name": "REDASH_LOG_LEVEL",
        "value": "INFO"
      },
      {
        "name": "REDASH_FEATURE_SHOW_PERMISSIONS_CONTROL",
        "value": "true"
      },
      {
        "name": "REDASH_DISABLED_QUERY_RUNNERS",
        "value": "redash.query_runner.graphite,redash.query_runner.mongodb,redash.query_runner.couchbase,redash.query_runner.url"
      },
      {
        "name": "REDASH_WEB_WORKERS",
        "value": "4"
      },
      {
        "name": "REDASH_REDIS_URL",
        "valueFrom": "${redash_redis_url}"
      }
    ],
    "secrets": [
      {
        "name": "REDASH_DATABASE_URL",
        "valueFrom": "/redash/database/url"
      },
      {
        "name": "POSTGRES_PASSWORD",
        "valueFrom": "/redash/database/password"
      }
    ],
    "command": [
      "create_db"
    ],
    "logConfiguration": {
      "logDriver": "awslogs",
      "secretOptions": null,
      "options": {
        "awslogs-group": "${log_group_name}",
        "awslogs-region": "ap-northeast-1",
        "awslogs-stream-prefix": "ecs"
      }
    },
    "entryPoint": null,
    "portMappings": [],
    "dockerLabels": null
  }
]

server.json

server.json

[
  {
    "name": "server",
    "image": "redash/redash:10.0.0.b50363",
    "cpu": 1024,
    "memory": 2048,
    "stopTimeout": 60,
    "memoryReservation": null,
    "environment": [
      {
        "name": "REDASH_HOST",
        "value": "${redash_url}"
      },
      {
        "name": "REDASH_COOKIE_SECRET",
        "value": "${redash_cookie_secret}"
      },
      {
        "name": "REDASH_ADDITIONAL_QUERY_RUNNERS",
        "value": "redash.query_runner.python"
      },
      {
        "name": "REDASH_ALLOW_SCRIPTS_IN_USER_INPUT",
        "value": "true"
      },
      {
        "name": "REDASH_FEATURE_SHOW_PERMISSIONS_CONTROL",
        "value": "true"
      },
      {
        "name": "REDASH_PASSWORD_LOGIN_ENABLED",
        "value": "true"
      },
      {
        "name": "REDASH_WEB_WORKERS",
        "value": "4"
      },
      {
        "name": "REDASH_GOOGLE_CLIENT_ID",
        "value": "${google_client_id}"
      },
      {
        "name": "REDASH_GOOGLE_CLIENT_SECRET",
        "value": "${google_client_secret}"
      },
      {
        "name": "REDASH_REDIS_URL",
        "value": "${redash_redis_url}"
      }
    ],
    "secrets": [
      {
        "name": "REDASH_DATABASE_URL",
        "valueFrom": "/redash/database/url"
      },
      {
        "name": "POSTGRES_PASSWORD",
        "valueFrom": "/redash/database/password"
      }
    ],
    "command": [
      "server"
    ],
    "logConfiguration": {
      "logDriver": "awslogs",
      "secretOptions": null,
      "options": {
        "awslogs-group": "${log_group_name}",
        "awslogs-region": "ap-northeast-1",
        "awslogs-stream-prefix": "ecs"
      }
    },
    "entryPoint": null,
    "portMappings": [
      {
        "hostPort": 5000,
        "protocol": "tcp",
        "containerPort": 5000
      }
    ],
    "dockerLabels": null
  },
  {
    "name": "scheduler",
    "image": "redash/redash:10.0.0.b50363",
    "cpu": 0,
    "stopTimeout": 60,
    "memoryReservation": null,
    "environment": [
      {
        "name": "REDASH_COOKIE_SECRET",
        "value": "${redash_cookie_secret}"
      },
      {
        "name": "PYTHONUNBUFFERED",
        "value": "0"
      },
      {
        "name": "REDASH_ADDITIONAL_QUERY_RUNNERS",
        "value": "redash.query_runner.python"
      },
      {
        "name": "REDASH_LOG_LEVEL",
        "value": "INFO"
      },
      {
        "name": "REDASH_FEATURE_SHOW_PERMISSIONS_CONTROL",
        "value": "true"
      },
      {
        "name": "REDASH_GOOGLE_CLIENT_ID",
        "value": "${google_client_id}"
      },
      {
        "name": "REDASH_GOOGLE_CLIENT_SECRET",
        "value": "${google_client_secret}"
      },
      {
        "name": "REDASH_REDIS_URL",
        "value": "${redash_redis_url}"
      }
    ],
    "secrets": [
      {
        "name": "REDASH_DATABASE_URL",
        "valueFrom": "/redash/database/url"
      },
      {
        "name": "POSTGRES_PASSWORD",
        "valueFrom": "/redash/database/password"
      }
    ],
    "command": [
      "scheduler"
    ],
    "logConfiguration": {
      "logDriver": "awslogs",
      "secretOptions": null,
      "options": {
        "awslogs-group": "${log_group_name}",
        "awslogs-region": "ap-northeast-1",
        "awslogs-stream-prefix": "ecs"
      }
    },
    "entryPoint": null,
    "dockerLabels": null
  },
  {
    "name": "worker",
    "image": "redash/redash:10.0.0.b50363",
    "cpu": 1024,
    "memory": 2048,
    "stopTimeout": 60,
    "memoryReservation": null,
    "environment": [
      {
        "name": "REDASH_COOKIE_SECRET",
        "value": "${redash_cookie_secret}"
      },
      {
        "name": "REDASH_ADDITIONAL_QUERY_RUNNERS",
        "value": "redash.query_runner.python"
      },
      {
        "name": "REDASH_GOOGLE_CLIENT_ID",
        "value": "${google_client_id}"
      },
      {
        "name": "REDASH_GOOGLE_CLIENT_SECRET",
        "value": "${google_client_secret}"
      },
      {
        "name": "REDASH_REDIS_URL",
        "value": "${redash_redis_url}"
      },
      {
        "name": "QUEUES",
        "value": "scheduled_queries,schemas,queries,periodic emails default"
      },
      {
        "name": "WORKERS_COUNT",
        "value": "1"
      }
    ],
    "secrets": [
      {
        "name": "REDASH_DATABASE_URL",
        "valueFrom": "/redash/database/url"
      },
      {
        "name": "POSTGRES_PASSWORD",
        "valueFrom": "/redash/database/password"
      }
    ],
    "command": [
      "worker"
    ],
    "logConfiguration": {
      "logDriver": "awslogs",
      "secretOptions": null,
      "options": {
        "awslogs-group": "${log_group_name}",
        "awslogs-region": "ap-northeast-1",
        "awslogs-stream-prefix": "ecs"
      }
    },
    "entryPoint": null,
    "dockerLabels": null
  }
]

11. ECSの構築

ecs.tf

ecs.tf
resource "aws_iam_role" "ecs-task-execution" {
  name               = "ecsTaskExecutionRole"
  assume_role_policy = data.aws_iam_policy_document.assume.json
}

data "aws_iam_policy_document" "assume" {
  version = "2012-10-17"
  statement {
    effect = "Allow"
    principals {
      identifiers = ["ecs-tasks.amazonaws.com"]
      type        = "Service"
    }
    actions = ["sts:AssumeRole"]
  }
}

data "aws_iam_policy_document" "ecs" {
  version = "2012-10-17"
  statement {
    effect = "Allow"
    actions = [
      "ecr:GetAuthorizationToken",
      "ecr:BatchCheckLayerAvailability",
      "ecr:GetDownloadUrlForLayer",
      "ecr:BatchGetImage",
      "logs:CreateLogStream",
      "logs:PutLogEvents",
      "ssm:GetParameters"
    ]
    resources = ["*"]
  }
}

data "aws_iam_policy_document" "session-manager" {
  version = "2012-10-17"
  statement {
    effect = "Allow"
    actions = [
      "ssmmessages:CreateControlChannel",
      "ssmmessages:CreateDataChannel",
      "ssmmessages:OpenControlChannel",
      "ssmmessages:OpenDataChannel"
    ]
    resources = ["*"]
  }
}

resource "aws_iam_role_policy" "ecs-task-execution" {
  name   = "ecsTaskExecutionPolicy"
  role   = aws_iam_role.ecs-task-execution.id
  policy = data.aws_iam_policy_document.ecs.json
}

resource "aws_iam_role_policy" "session-manager" {
  name   = "sessionManagerPolicy"
  role   = aws_iam_role.ecs-task-execution.id
  policy = data.aws_iam_policy_document.session-manager.json
}

resource "aws_security_group" "ecs" {
  name   = "${local.app_name}-ecs-sg"
  vpc_id = module.vpc.vpc_id

  ingress {
    from_port   = 5000
    to_port     = 5000
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  tags = local.tags
}

resource "aws_ecs_cluster" "redash" {
  name = "${local.app_name}-cluster"
  setting {
    name  = "containerInsights"
    value = "enabled"
  }
  
  tags = local.tags
}

resource "aws_ecs_service" "redash" {
  name            = "${local.app_name}-service"
  cluster         = aws_ecs_cluster.redash.id
  task_definition = aws_ecs_task_definition.server.arn

  desired_count = 1
  launch_type   = "FARGATE"

  deployment_maximum_percent         = 200
  deployment_minimum_healthy_percent = 100
  health_check_grace_period_seconds  = 600
  enable_execute_command             = true

  deployment_circuit_breaker {
    enable   = true
    rollback = true
  }

  network_configuration {
    subnets          = module.vpc.public_subnets
    security_groups  = [aws_security_group.ecs.id]
    assign_public_ip = false
  }

  load_balancer {
    target_group_arn = aws_lb_target_group.redash.arn
    container_name   = "server"
    container_port   = 5000
  }

  tags = local.tags
}

resource "aws_ecs_task_definition" "create-db" {
  family                   = "redash-create-db"
  cpu                      = 256
  memory                   = 512
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]

  execution_role_arn = aws_iam_role.ecs-task-execution.arn
  task_role_arn      = aws_iam_role.ecs-task-execution.arn

  container_definitions = templatefile("./ecs_task_definitions/create_db.json", {
    log_group_name       = aws_cloudwatch_log_group.redash.name
    redash_host          = "https://redash.hoge.com"
    redash_redis_url     = "redis://${aws_elasticache_replication_group.redash.primary_endpoint_address}:${aws_elasticache_replication_group.redash.port}/0"
    google_client_id     = var.google_client_id
    google_client_secret = var.google_client_secret
  })

  tags = local.tags
}

resource "aws_ecs_task_definition" "server" {
  family                   = "server"
  cpu                      = 2048
  memory                   = 4096
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]

  execution_role_arn = aws_iam_role.ecs-task-execution.arn
  task_role_arn      = aws_iam_role.ecs-task-execution.arn

  container_definitions = templatefile("./ecs_task_definitions/server.json", {
    log_group_name       = aws_cloudwatch_log_group.redash.name
    redash_host          = "https://redash.hoge.com"
    redash_redis_url     = "redis://${aws_elasticache_replication_group.redash.primary_endpoint_address}:${aws_elasticache_replication_group.redash.port}/0"
    google_client_id     = var.google_client_id
    google_client_secret = var.google_client_secret
  })

  tags = local.tags
}

rds.tf

ecsのセキュリティーグループのみを許可するようにコメントを外してあげます

rds.tf
resource "aws_security_group" "postgresql" {
  name   = "${local.app_name}-postgresql-sg"
  vpc_id = module.vpc.vpc_id

  ingress {
-    # ecsのセキュリティーグループを作るまではコメントアウト
-    # security_groups = [aws_security_group.ecs.id]
+   security_groups = [aws_security_group.ecs.id]
    from_port = 5432
    to_port   = 5432
    protocol  = "tcp"
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  tags = local.tags
}

redis.tf

ecsのセキュリティーグループのみを許可するようにコメントを外してあげます

redis.tf
resource "aws_security_group" "redis" {
  name   = "${local.app_name}-redis-sg"
  vpc_id = module.vpc.vpc_id

  ingress {
-    # ecsのセキュリティーグループを作ったら、コメントインします
-    # security_groups = [aws_security_group.ecs.id]
+   security_groups = [aws_security_group.ecs.id]
    from_port       = 6379
    to_port         = 6379
    protocol        = "tcp"
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  tags = local.tags
}

12. Google OAuth SSOの設定

事前にGCP Cloud ConsoleでClientIDとClient Secretを作成しておく。
以下の記事を参考に
https://tech.renosys.co.jp/entry/2019/11/23/155438

  • ClientID
  • ClientSecret
    の二つが用意できたら、以下二つのファイルを作成する。
    terraform.tfvarsはterraform applyを実行したときにこのファイルから値を取得して、variableリソースにマッピングしてくれます。
    variables.tfで定義したvariableリソースの変数はterraform内でvar.〇〇として使用出来ます。

variables.tf

variables.tf
variable "google_client_id" {
  type = string
}

variable "google_client_secret" {
  type = string
}

terraform.tfvars

google_client_id     = "作成したclient_idの値を入れる"
google_client_secret = "作成したclient_secretの値を入れる"

13. Terraform apply

Terraformのコードが書けたら、以下を実行していきます

$ cd /path/to/main.tfなどが格納されているディレクトリ

// フォーマットを修正
$ terraform fmt

// バリデーションチェック
$ terraform validate

// 変更内容を確認
$ terraform plan

// Terraformの変更を適用
$ terraform apply

14. create_dbタスクを実行

terraforma applyで各リソースが起動されたら、redashの設定情報などを格納するデータベースにテーブル情報を追加するcreate_dbタスクを実行していきます

AWS Web Consoleにアクセスをして、ECS > タスク定義に移動し、create_dbタスクの詳細ページから、「デプロイ」 -> 「タスクの実行」を行います。

タスクの実行に際し、以下の項目を設定します

  • 環境
    • クラスター: 作成したクラスター
    • コンピューティング設定:起動タイプ
    • 起動タイプ:FARGATE
    • プラットフォームのバージョン:LATEST
  • デプロイ設定
    • アプリケーションタイプ:タスク
    • タスク定義
      • リビジョンの手動指定:チェックしない
      • ファミリー:create-db
      • リビジョン:create-dbの最新リビジョン
    • 必要なタスク:1
    • タスクグループ:設定なし
  • ネットワーキング
    • VPC: terraformで作成したvpc(デフォルトを選択したままにするとコケます)
    • サブネット:terraformで作成したサブネットをとりあえず全部
    • セキュリティーグループ
      • 既存のセキュリティーグループを使用にチェック
      • セキュリティーグループ名:terraformで作成したecsに割り当てたセキュリティーグループを選択

上記を設定したら、作成を押してタスクを実行させます

15. adminユーザーの作成

create_dbタスクが完了したら、設定したredashのurlにアクセスをすると、adminユーザーの作成画面が表示されるのでフローに従います

16. google認証の設定

adminユーザーの作成まで終わったら、redashのサイドメニューのSettings > Generalと遷移し、Google Login項目を入力します

メールアドレスのhoge@hoge.co.jpが設定したいアドレスだとしたら、hoge.co.jpをGoogle Login項目に入力し、保存を押して完了です

Discussion