Amazon RDS를 통한 MySQL 데이터베이스 이중화(Multi-AZ) 구성

Chori·2025년 2월 10일
0
post-thumbnail

스스로 구축하는 AWS 클라우드 인프라 - 기본편을 수강하며 AWS 인프라를 Terraform으로 작성한 내용입니다.


복수의 가용 영역에 생성하는 RDS

  • 서로 다른 가용 영역의 Private Subnet에 3개의 RDS를 배치
  • 하나는 Master 데이터베이스, 또 다른 하나는 Standby 데이터베이스, 마지막은 Read Replica 데이터베이스
  • 기본적으로 Master 데이터베이스와 서버가 연결되어서 시스템이 운영되는데 만약 Master 데이터베이스에 장애가 발생하면 자동으로 서버와 Standby 데이터베이스가 연결됨
    • 이 과정에서 Standby 데이터베이스가 Master 데이터베이스로 변경되고 Master 데이터베이스가 Standby 데이터베이스가 되어 서로 역할이 바뀜
  • 읽기 전용 복제본인 Read Replica는 Master 데이터베이스와 싱크를 맞추며 DB의 변동 내역을 실시간으로 업데이트

Security group 생성

  • 데이터베이스 인스턴스에 대한 Security group 만들기
  • security_group.tf 파일에 아래 내용 추가
# Security group for RDS
resource "aws_security_group" "rds_sg" {
  name = "rds-sg"
  description = "Security group for RDS"
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "rds-sg"
  }
}

# Inbound rule allowing MySQL for RDS
resource "aws_vpc_security_group_ingress_rule" "allow_mysql_for_rds" {
  security_group_id = aws_security_group.rds_sg.id
  cidr_ipv4 = aws_vpc.main.cidr_block
  from_port = "3306"
  ip_protocol = "tcp"
  to_port = "3306"
}

# Outbound rule allowing all traffic for RDS
resource "aws_vpc_security_group_egress_rule" "allow_all_outbound_traffic_for_rds" {
  security_group_id = aws_security_group.rds_sg.id
  cidr_ipv4 = "0.0.0.0/0"
  ip_protocol = "-1"
}
  • 특정 VPC에서 출발한 트래픽을 허용하도록 인바운드 규칙 설정

DB Subnet group 생성

  • 데이터베이스 인스턴스가 위치할 서브넷 그룹 만들기
  • subnet.tf 파일을 아래와 같이 변경
# Public Subnet for ec2
# Subnet will use cidr with /24 -> The number of availability IP is 256
resource "aws_subnet" "public_for_ec2" {
  count = length(var.availability_zones)
  vpc_id = aws_vpc.main.id
  
  cidr_block = "10.0.${var.cidr_numeral_public_ec2[count.index]}.0/24"
  availability_zone = element(var.availability_zones, count.index)

  tags = {
    Name = "public-${count.index}-${var.vpc_name}"
  }
}

# Private Subnet for ec2
# Subnet will use cidr with /24 -> The number of availability IP is 256
resource "aws_subnet" "private_for_ec2" {
  count = length(var.availability_zones)
  vpc_id = aws_vpc.main.id

  cidr_block = "10.0.${var.cidr_numeral_private_ec2[count.index]}.0/24"
  availability_zone = element(var.availability_zones, count.index)

  tags = {
    Name = "private-${count.index}-${var.vpc_name}"
  }
}

# Private Subnet for rds
# Subnet will use cidr with /24 -> The number of availability IP is 256
resource "aws_subnet" "private_for_rds" {
  count = length(var.availability_zones)
  vpc_id = aws_vpc.main.id

  cidr_block = "10.0.${var.cidr_numeral_private_rds[count.index]}.0/24"
  availability_zone = element(var.availability_zones, count.index)

  tags = {
    Name = "private-${count.index}-${var.vpc_name}"
  }
}
  • db_subnet.tf 파일을 만들고 아래와 같이 작성
resource "aws_db_subnet_group" "rds_subnet_group" {
  name = "rds-subnet-group"
  description = "Subnet group for rds-subnet-group"
  subnet_ids = aws_subnet.private_for_rds.*.id

  tags = {
    Name = "rds-subnet-group"
  }
}

KMS Key 생성 및 암호화

KMS Key 만들기

  • kms_key.tf 파일을 만들고 아래 내용 추가
data "aws_caller_identity" "current" {}

resource "aws_kms_key" "rds_password_key" {
  description             = "KMS key for encrypting RDS password"
  enable_key_rotation     = true
  deletion_window_in_days = 7
  rotation_period_in_days = 90
}

resource "aws_kms_key_policy" "rds_password_key_policy" {
  key_id = aws_kms_key.rds_password_key.id
  policy = jsonencode({
    Version = "2012-10-17"
    Id      = "key-default-1"
    Statement = [
      {
        Sid    = "Enable IAM User Permissions"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
        },
        Action   = "kms:*"
        Resource = "*"
      }
    ]
  })
}

resource "aws_kms_alias" "rds_password_key" {
  name          = "alias/rds-password-key"
  target_key_id = aws_kms_key.rds_password_key.key_id
}

RDS에 사용할 비밀번호 암호화

  • terraform.dec.json 파일을 만들고 비밀번호 작성
{
    "secret": "Write-your-own-password"
}
  • SOPS 명령어를 사용하여 비밀번호 암호화
sops --encrypt --kms=arn:aws:kms:<AWS_REGION>:<AWS_ACCOUNT_ID>:key/<AWS_KMS_KEY_ID> terraform.dec.json > terraform.enc.json
  • terraform.dec.json 파일은 Git에서 관리되지 않도록 삭제하거나 .gitignore에 추가

RDS 생성

  • rds.tf 파일을 만들고 아래와 같이 작성
data "external" "sops_secret" {
  program = ["sh", "-c", "sops -d terraform.enc.json | jq -r '{secret: .secret}'"]
}

resource "aws_db_instance" "rds" {
  identifier                      = "rds"
  db_name                         = "vpcrds"
  instance_class                  = "db.t3.micro"
  storage_type                    = "gp2"
  allocated_storage               = 20
  max_allocated_storage           = 0
  engine                          = "mysql"
  engine_version                  = "8.0"
  auto_minor_version_upgrade      = true
  username                        = "admin"
  password                        = data.external.sops_secret.result["secret"]
  multi_az                        = true
  db_subnet_group_name            = aws_db_subnet_group.rds_subnet_group.name
  vpc_security_group_ids          = [aws_security_group.rds_sg.id]
  publicly_accessible             = false
  parameter_group_name            = "default.mysql8.0"
  backup_retention_period         = 7
  copy_tags_to_snapshot           = true
  enabled_cloudwatch_logs_exports = ["general"]
  deletion_protection             = false
  skip_final_snapshot             = true
}
  • multi_aztrue로 설정하여 복수의 가용 영역에 데이터베이스를 생성
    • Subnet group에 등록된 Subnet 중 하나에는 Master 데이터베이스가 만들어지고 다른 Subnet에는 Standby 데이터베이스가 만들어짐
  • parameter_group은 데이터베이스 인스턴스 엔진의 기본적인 구성값들이 설정되어 있는 집합
profile
전부인 것처럼, 전부가 아닌 것처럼

0개의 댓글