Go x Next.js(SPA) をTerraformでさっさと構築 2/3

AWS

Go x Next.js(SPA) な環境をTerraformでAWSに構築してみます!

バックエンドのGoには、ECS Fargateで。
フロントエンドのSPAには、CloudFront・S3を使用して静的ホスティングをしてます。
また、System エージェントをインストールすることでFargateコンテナ内に接続できるようにしています。

はじめに

連載記事でこの環境を構築していきます。

本記事では、API用のドメインhttps化・アプリケーションロードバランサー構築・RDSの構築を行います!

フォルダ構成とか書き方、モージュル化などは、【ネットワーク環境構築】terraform AWS環境構築 第1回この記事とほぼ同じなので気になる方は御覧ください!

全体のソースコード:github

環境は以下です。

OS Cataline 10.15.6
Terraform 0.14.4
Go 1.16.3
React 17.0.2

 

 

 

 

基本構文などこちらにまとめてますので、よかったらみてください!
AWS Terraform 基本コード まとめ

連載一覧

やること

以下の定義と作成をします。

API用のドメインACM証明書発行

【ドメインhttps化・ACM(SSL)証明書発行】terraform AWS環境構築 第2回
こことほぼ同じですが、発行するドメインに「api.」を付け加えます。

./main.tf

module "network" {
  source   = "./network"
  app_name = var.app_name
}

module "acm" {
  source = "./acm"
  domain = var.domain
}

module "spa" {
  source   = "./spa"
  app_name = var.app_name
  domain   = var.domain
  acm_id   = module.acm.acm_id
}

#追記
module "subdomain_acm" {
  source = "./subdomain_acm"
  domain = var.domain
}

./subdomain_acm/main.tf

resource "aws_acm_certificate" "this" {
  domain_name = "api.${var.domain}"

  validation_method = "DNS"

  lifecycle {
    create_before_destroy = true
  }
}
resource "aws_route53_record" "this" {
  depends_on = [aws_acm_certificate.this]

  for_each = {
    for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => {
      name   = dvo.resource_record_name
      record = dvo.resource_record_value
      type   = dvo.resource_record_type
    }
  }

  zone_id = data.aws_route53_zone.this.zone_id
  name    = each.value.name
  records = [each.value.record]
  ttl     = 60
  type    = each.value.type
}

resource "aws_acm_certificate_validation" "this" {
  certificate_arn = aws_acm_certificate.this.arn

  validation_record_fqdns = [for record in aws_route53_record.this : record.fqdn]
}

./subdomain_acm/variables.tf

variable "domain" {}

./subdomain_acm/data.tf

data "aws_route53_zone" "this" {
  name         = var.domain
  private_zone = false
}

./subdomain_acm/outputs.tf

output "sub_acm_id" {
  value = aws_acm_certificate.this.id
}
[terraform] $ terraform plan

作成されるリソースの確認。

[terraform] $ terraform apply

リソースの作成。

api.<your domain> のACM証明書が発行されているのが確認できましたね。

アプリケーションロードバランサー

【ロードバランサー構築】terraform AWS環境構築 第3回
こことほぼ同じです。

./main.tf

module "network" {
  source   = "./network"
  app_name = var.app_name
}

module "acm" {
  source = "./acm"
  domain = var.domain
}

module "spa" {
  source   = "./spa"
  app_name = var.app_name
  domain   = var.domain
  acm_id   = module.acm.acm_id
}

module "subdomain_acm" {
  source = "./subdomain_acm"
  domain = var.domain
}

#追記
module "elb" {
  source = "./elb"

  app_name          = var.app_name
  vpc_id            = module.network.vpc_id
  public_subnet_ids = module.network.public_subnet_ids
  sub_acm_id        = module.subdomain_acm.sub_acm_id
  domain            = var.domain
}

./elb/main.tf

resource "aws_security_group" "this" {
  vpc_id = var.vpc_id

  dynamic "ingress" {
    for_each = var.ingress_ports

    iterator = port

    content {
      from_port   = port.value
      to_port     = port.value
      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 = {
    Name = "${var.app_name}-sg"
  }
}

resource "aws_lb" "this" {
  name               = "${var.app_name}-alb"
  load_balancer_type = "application"

  security_groups = [aws_security_group.this.id]
  subnets         = var.public_subnet_ids
}

resource "aws_lb_listener" "http" {
  port     = "80"
  protocol = "HTTP"

  load_balancer_arn = aws_lb.this.arn

  default_action {
    type = "redirect"

    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}

resource "aws_lb_listener" "https" {
  port     = "443"
  protocol = "HTTPS"

  load_balancer_arn = aws_lb.this.arn
  certificate_arn   = var.sub_acm_id

  default_action {
    type = "fixed-response"

    fixed_response {
      content_type = "text/plain"
      status_code  = "200"
      message_body = "ok"
    }
  }
}

resource "aws_route53_record" "this" {
  type    = "A"
  name    = "api.${var.domain}"
  zone_id = data.aws_route53_zone.this.id

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

./elb/variables.tf

variable "app_name" {}

variable "vpc_id" {}

variable "ingress_ports" {
  description = "list of ingress ports"
  default     = [80, 443]
}

variable "public_subnet_ids" {}

variable "sub_acm_id" {}

variable "domain" {}

./elb/data.tf

data "aws_route53_zone" "this" {
  name         = var.domain
  private_zone = false
}

./elb/outputs.tf

output "http_listener_arn" {
  value = aws_lb_listener.http.arn
}
output "https_listener_arn" {
  value = aws_lb_listener.https.arn
}

output "alb_security_group_id" {
  value = aws_security_group.this.id
}

RDSの構築

【RDS構築】terraform AWS環境構築 第5回
ここと同じです。

./main.tf

module "network" {
  source   = "./network"
  app_name = var.app_name
}

module "acm" {
  source = "./acm"
  domain = var.domain
}

module "spa" {
  source   = "./spa"
  app_name = var.app_name
  domain   = var.domain
  acm_id   = module.acm.acm_id
}

module "subdomain_acm" {
  source = "./subdomain_acm"
  domain = var.domain
}

module "elb" {
  source = "./elb"

  app_name          = var.app_name
  vpc_id            = module.network.vpc_id
  public_subnet_ids = module.network.public_subnet_ids
  sub_acm_id        = module.subdomain_acm.sub_acm_id
  domain            = var.domain
}

# 追記
module "rds" {
  source = "./rds"

  app_name    = var.app_name
  db_name     = var.db_name
  db_user     = var.db_user
  db_password = var.db_password

  vpc_id                = module.network.vpc_id
  alb_security_group_id = module.elb.alb_security_group_id
  private_subnet_ids    = module.network.private_subnet_ids
}

./terraform.tfvars

domain = "<your domain>"
db_name = "go-next_db"
db_user = "root"
db_password = "password"

./rds/main.tf

resource "aws_security_group" "this" {
  vpc_id = var.vpc_id

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

  tags = {
    Name = "${var.app_name}-rds-sg"
  }
}

resource "aws_security_group_rule" "this" {
  security_group_id = aws_security_group.this.id

  type = "ingress"

  from_port                = 3306
  to_port                  = 3306
  protocol                 = "tcp"
  source_security_group_id = var.alb_security_group_id
}

resource "aws_db_subnet_group" "this" {
  name        = var.db_name
  description = "db subent group of ${var.db_name}"
  subnet_ids  = var.private_subnet_ids
}

resource "aws_db_instance" "this" {
  allocated_storage = 10
  storage_type      = "gp2"
  engine            = var.engine
  engine_version    = var.engine_version
  instance_class    = var.db_instance

  identifier          = "${var.app_name}-rds"
  username            = var.db_user
  password            = var.db_password
  skip_final_snapshot = true

  enabled_cloudwatch_logs_exports = [
    "error",
    "general",
    "slowquery"
  ]
  vpc_security_group_ids = [aws_security_group.this.id]
  db_subnet_group_name   = aws_db_subnet_group.this.name
}

./rds/variables.tf

variable "app_name" {}

variable "db_name" {}

variable "db_user" {}

variable "db_password" {}

variable "vpc_id" {}

variable "alb_security_group_id" {}

variable "engine" {
  type    = string
  default = "mysql"
}

variable "engine_version" {
  type    = string
  default = "8.0.20"
}

variable "db_instance" {
  type    = string
  default = "db.t2.micro"
}

variable "private_subnet_ids" {}

./rds/outputs.tf

output "db_address" {
  value = aws_db_instance.this.address
}

おわり

これで、ロードバランサーの構築・DB構築が完了しました。

次回は、ECSクラスター・ECSサービス・SSMアクティベーションの作成を行います。

最後までご覧いただきありがとうございます!

何か疑問に思うことがあれば、何でもいいのでコメントくれれば精一杯答えさせていただきます。

Twitterとかフォローしてくれると嬉しいです。では、次回お会いしましょう!

コメント

タイトルとURLをコピーしました