테라폼으로 AWS 환경 구축하기 2장. ALB EC2 RDS S3 구축하기 – 2

초심자도 이해할 수 있도록 테라폼을 이용하여 EC2 RDS S3의 구성을 작성해보는 글입니다.
2021.10.29

안녕하세요 클래스메소드의 이수재입니다.

요즘 테라폼을 전혀 공부하지 않았어서 사용법을 거의 잊어버렸습니다...
기억도 되살릴겸 다시금 테라폼 블로그를 작성하려 합니다.
저번 글에서 이어집니다.

환경

  • terraform 1.0.9
  • tfswitch 0.12.1168
  • AWS Vault 6.3.1-Homebrew

이 글에선 간단하게 다음과 같은 구성을 테라폼으로 작성합니다.


작성되는 주요 리소스는 다음과 같습니다.

  • network (저번 글에서 작성)
    • vpc
    • subnet(public X 2, private X 4)
    • vpc endpoint
    • security group X 2
  • EC2 X 2 (아래로 이번 글에서 작성할 리소스)
    • ALB X 1
  • RDS

해당 글에서 사용한 템플릿은 깃 허브에 업로드되어 있으니 참고해주세요.

작성하기

전체적인 흐름은 다음과 같습니다.

  1. 프로바이더 설정
  2. 네트워크 리소스 작성
  3. EC2 리소스 작성
  4. RDS 리소스 작성
  5. S3 리소스 작성

이 글에선 EC2 리소스 작성 부터 시작합니다.

EC2 리소스 작성

2 개의 EC2 인스턴스를 작성합니다.

# ec2.tf
data "aws_ami" "amazonLinux" {
  most_recent = true
  owners = [ "amazon" ]

  filter {
    name = "name"
    values = [ "amzn2-ami-hvm-2.0.*" ]
  }

  filter {
    name = "virtualization-type"
    values = [ "hvm" ]
  }

  filter {
    name = "architecture"
    values = [ "x86_64" ]
  }
}

resource "aws_instance" "testEC201" {
  ami = data.aws_ami.amazonLinux.id
  instance_type = "t3.medium"
  vpc_security_group_ids = [ 
    aws_security_group.privateEC2SG01.id
   ]
  subnet_id = aws_subnet.privateEC2Subnet1.id
  key_name = "publicTestKey"

  root_block_device {
    volume_size = 50
    volume_type = "gp3"
    tags = {
      "Name" = "test-private-ec2-01-vloume-1"
    }
  }

  tags = {
    "Name" = "test-private-ec2-01"
  }
}

resource "aws_instance" "testEC202" {
  ami = data.aws_ami.amazonLinux.id
  instance_type = "t3.medium"
  vpc_security_group_ids = [ 
    aws_security_group.privateEC2SG01.id
   ]
  subnet_id = aws_subnet.privateEC2Subnet2.id
  key_name = "publicTestKey"

  root_block_device {
    volume_size = 50
    volume_type = "gp3"
    tags = {
      "Name" = "test-private-ec2-02-vloume-1"
    }
  }

  tags = {
    "Name" = "test-private-ec2-02"
  }
}

EC2의 ami 인수에 직접 AMI ID 를 기입해도 되지만 데이터 소스를 활용하여 좀 더 능동적인 값이 설정되도록 하였습니다.
데이터 소스란 테라폼 외부에서 정의된 값을 편하게 사용할 수 있도록 해주는 블록입니다.
프로바이더마다 제공하는 데이터 소스가 다르므로 문서를 참조해야합니다.
선언은 data 블록으로 할 수 있습니다. 필터를 활용하여 검색 범위를 좁힐 수 있습니다.
데이터 소스에 대해선 공식 문서을 참고해주세요.

키 페어는 새로 생성하지 않고 기존에 있던 키 페어를 그대로 사용하였습니다.
AWS 콘솔에서 직접 키 페어를 등록해도 되지만 테라폼을 통하여 새로 생성한다면 예전 글을 참고해주세요.

작성이 끝났다면 plan으로 결과를 확인합니다.

ALB 작성

네트워크 환경과 EC2가 작성되었으니 이어서 로드 밸런서를 작성합니다.

# alb.tf
resource "aws_alb" "test" {
  name = "test-alb"
  internal = false
  load_balancer_type = "application"
  security_groups = [ aws_security_group.publicSG01.id ]
  subnets = [ aws_subnet.publicSubnet1.id , aws_subnet.publicSubnet2.id ]
  enable_cross_zone_load_balancing = true
}


resource "aws_alb_target_group" "test" {
  name = "tset-alb-tg"
  port = 80
  protocol = "HTTP"
  vpc_id = aws_vpc.test.id
}

resource "aws_alb_target_group_attachment" "privateInstance01" {
  target_group_arn = aws_alb_target_group.test.arn
  target_id = aws_instance.testEC201.id
  port = 80
}

resource "aws_alb_target_group_attachment" "privateInstance02" {
  target_group_arn = aws_alb_target_group.test.arn
  target_id = aws_instance.testEC202.id
  port = 80
}

resource "aws_alb_listener" "test" {
  load_balancer_arn = aws_alb.test.arn
  port = 80
  protocol = "HTTP"

  default_action {
    type = "forward"
    target_group_arn = aws_alb_target_group.test.arn
  }
}

콘솔에서 작업하듯이 로드 밸런서를 생성하고 타겟 그룹과 리스너를 작성 후 로드 밸런서에 연결합니다.
HTTP의 80 포트만 포워딩하는 단순한 구성이라 내용이 길지 않지만 HTTPS나 내부 로드 밸런싱 등의 설정도 가능합니다.

RDS 작성

mariaDB를 이용하는 RDS를 작성합니다.

# rds.tf
resource "aws_db_subnet_group" "testSubnetGroup" {
  name = "test"
  subnet_ids = [ 
    aws_subnet.privateRDSSubnet1.id,
    aws_subnet.privateRDSSubnet2.id
  ]

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

}

resource "aws_db_instance" "testDB" {
  allocated_storage = 20
  max_allocated_storage = 50
  availability_zone = "ap-northeast-1a"
  db_subnet_group_name = aws_db_subnet_group.testSubnetGroup.name
  engine = "mariadb"
  engine_version = "10.5"
  instance_class = "db.t3.small"
  skip_final_snapshot = true
  identifier = "test-maridb"
  username = "root"
  password = var.db_password
  name = "testDB"
  port = "3306"
}

서브넷 그룹이 필요하여 같이 작성합니다.
기본 값이 아닌 파라미터 그룹이나 옵션 그룹이 필요하다면 추가로 설정 할 필요가 있습니다.
password에 문자열 값이 아닌 변수를 활용하였습니다.
변수를 사용하기 위해선 변수 파일의 작성이 필요합니다.

# variable.tf
variable "db_password" {
  description = "RDS root user password"
  type        = string
  sensitive   = true
}

이렇게 변수 파일을 만듦으로써 plan이나 apply를 할 때 대화형 콘솔에서 직접 값을 타이핑 할 수 있습니다.

$ aws-vault exec sujae-tes -- terraform plan
Enter token for arn:aws:iam::+++++:mfa/-----:
var.db_password
  RDS root user password

  Enter a value: testtest

입력할 때는 무슨 값을 입력하는지 콘솔에 표시되지만 결과에서 rds의 password 파라미터를 보시면 (sensitive value)로 되어 있습니다.
이는 variable.tf 파일에서 해당 인수의 sensitivetrue로 설정했기 때문입니다.

S3 작성

마지막으로 S3를 작성합니다.

resource "aws_s3_bucket" "testS3" {
  bucket = "sujate-terraform-test-bucket"
  acl    = "private"

  versioning {
      enabled = true
  }

  lifecycle_rule {
    prefix = "image/"
    enabled = true

    noncurrent_version_expiration {
      days = 180
    }
  }

  tags = {
    "Name" = "sujae-test-bucket"
  }
}

간단하게 버전 기록과 수명 주기를 설정한 버킷입니다.
image/test.jpg 등과 같이 이름 접두사가 겹치는 파일 중 최신 버전이 아닌 파일은 180일 이후에 삭제되도록 설정하였습니다.

작성 마무리

여기까지 완성하였다면 apply를 하여 결과를 확인합니다.
전부 잘 되었다면 작성 완료입니다!
이제 인스턴스에 접속하여 서버를 설정합니다.
해당 리소스를 사용하지 않는 다면 destroy로 생성한 리소스를 삭제합니다.

그리고 작성한 소스를 깃허브 등에 업로드 하여 관리합니다.

돌아보기

작성하는 리소스별로 파일을 나누었지만 구성이 한눈에 들어오지 않는 리소스도 있었습니다.
그리고 반복되는 값도 여기저기 있었네요.
또한 실제 환경에선 prd dev stage 등 환경을 나누어 사용하는게 보통이지만 이번엔 환경을 나누지도 않았습니다.
소스를 깃허브에 업로드는 하였지만 state 파일 등은 어떻게 다루어야 할까요?

이어지는 글들에서는 이러한 문제점들을 개선하며 좀 더 실전에 맞는 사용법을 알아보고 다른 구성들도 작성해보겠습니다.

긴 글 읽어주셔서 감사합니다.
오탈자 및 내용 피드백은 언제나 환영합니다. must01940 지메일로 보내주시면 감사합니다.

이전 글

테라폼으로 AWS 환경 구축하기 2장. ALB EC2 RDS S3 구축하기 – 1
테라폼으로 AWS 환경 구축하기 3장. 테라폼 더 잘쓰기