Terraform을 처음 이용해보는 사람의 입장에서 작성하는 시리즈다.
해당 글은 AWS와 연결해 접근 가능한 인스턴스를 하나 띄워보는 것을 목표로 한다.
이어지는 시리즈에서 서비스 별 모듈화, 구조 연결 등을 진행할 계획이니 차근차근 따라오면 된다.
백엔드 프로젝트의 루트 디렉토리에 terraform 디렉토리를 생성하자.
mkdir terraform
해당 디렉토리에 VSCode의 명령어 ⌘ + N 로 main.tf 파일을 하나 생성한다.
(참고)
이번 글에서는 실행해보는 것을 목표로 하기 때문에 main.tf 파일에 모든 정보를 기재할 예정이다.
다음 글에서부터 variable.tf, provider.tf 파일을 생성해 민감한 정보를 담은 코드를 분리하고
리소스를 역할 별로 디렉토리를 만들어 분류할 예정이다.
in /terraform/main.tf,
# Provider
provider "aws" {
region = {your_region}
}
in /terraform/main.tf,
# DB Instance
resource "aws_db_instance" "db_instance" {
identifier = {your_db_instance_name}
instance_class = "db.t3.micro" // free tier
engine = "mysql"
engine_version = "8.0.34"
username = {db_username}
password = {db_password}
db_name = {db_name}
allocated_storage = 20
skip_final_snapshot = true
publicly_accessible = true
}
Terraform Registry
registry.terraform.io
공식 문서에서 필요한 프로퍼티를 찾아 기입하자.
identifier | AWS console에 노출될 이름을 지정 |
instance_class | Free tier 에 해당하는 "db.t3.micro" 클래스로 정의한다. |
engine, engine_version | engine, engine_version: 사용할 엔진, 버전을 지정한다. (Docs가 불친절해서 AWS에서 옵션을 보고 기입하자.) |
username, password | RDS는 master 계정과 동일한 권한의 계정을 추가 생성해 우리에게 제공해준다. 해당 계정의 이름, 비밀번호를 설정하자. |
db_name | 사용할 db의 이름을 지정한다. 이 옵션을 넣으면 자동으로 db를 만들어준다. 나중에 진입해서 테이블은 만들어놔야 한다. |
allocated_storage | Storage 양, GB 단위이다. |
skip_final_snapshot | 해당 DB instance를 삭제할 때 final snapshot을 만들지 물어보는 항목 |
publicly_accessible | AWS 내부 네트워크에서만 통신할건지 물어보는 항목 |
이제 위에서 정의한 db instance가 배포되었을 때 public network를 통해 접근할 수 있도록 정의해주자.
in /terraform/main.tf,
# DB Network
data "aws_availability_zones" "available" {}
resource "aws_vpc" "db_vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "db-vpc"
}
}
resource "aws_subnet" "db_subnet" {
count = 2
vpc_id = aws_vpc.db_vpc.id
cidr_block = element(["10.0.1.0/24", "10.0.2.0/24"], count.index)
availability_zone = element(data.aws_availability_zones.available.names, count.index)
tags = {
Name = "db-subnet-${count.index}"
}
}
resource "aws_internet_gateway" "db_igw" {
vpc_id = aws_vpc.db_vpc.id
tags = {
Name = "db-igw"
}
}
resource "aws_route_table" "db_route_table" {
vpc_id = aws_vpc.db_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.db_igw.id
}
tags = {
Name = "db-route-table"
}
}
resource "aws_route_table_association" "db_route_table_assoc" {
count = 2
subnet_id = element(aws_subnet.db_subnet[*].id, count.index)
route_table_id = aws_route_table.db_route_table.id
}
resource "aws_db_subnet_group" "db_subnet_group" {
name = "db-subnet-group"
subnet_ids = aws_subnet.db_subnet[*].id
tags = {
Name = "db-subnet-group"
}
}
# DB Instance
resource "aws_db_instance" "db_instance" {
...
db_subnet_group_name = aws_db_subnet_group.db_subnet_group.name // New!
}
다음은 접근 가능 ip, port를 제한하는 Security Group을 정의한다.
in /terraform/main.tf,
resource "aws_security_group" "db_sg" {
description = "Allow DB instance access"
vpc_id = aws_vpc.db_vpc.id
ingress {
from_port = 3306
to_port = 3306
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 = "db-sg"
}
}
해당 security group은,
ingress - 모든 ip로부터 3306 포트의 통신만 받는다.
egress - 모든 ip, 모든 포트에 정보를 전달 가능하다.
resource "aws_db_instance" "db_instance" {
...
vpc_security_group_ids = [aws_security_group.db_sg.id] // New!
}
aws configure
Access Key ID, Access Key, region 입력
해당 과정에 성공하면 AWS에 인스턴스가 생성된다.
무료 티어의 인스턴스이더라도, 네트워크 송수신 비용이 발생하니 꼭 주의해야한다.
아래의 명령어들을 순서대로 터미널에 입력한다.
terraform init
terraform validate
terraform apply
배포에 성공했으니, 접속되는지 mysql client로 확인해보자.
필자는 Sequel Ace를 사용하고 있다.
이제 삭제까지 연습해보자.
terraform destroy
terraform apply 명령어로 생성된 모든 리소스를 제거한다.
권한이나 종속관계 문제로 해당 명령어로 삭제되지 않는 경우가 있으니,
로그를 꼭 확인하고 AWS 콘솔에서 확실히 삭제해 불필요한 비용 지출을 막자.
현재까지 디렉토리 구조
/project_root
│
├── terraform
│ ├── main.tf
│ ├── .terraform.lock.hcl
│ ├── terraform.tfstate
│ ├── terraform.tfstate.backup
│ ├── .terraform
│ │ ├── ...
.terraform.lock.hcl, terraform.tfstate, terraform.tfstate.backup 파일, .terraform 디렉토리는 .gitignore에 추가하자.
현재 main.tf 파일은 다음과 같을 것이다.
# Provider
provider "aws" {
region = {your_region}
}
# DB Network
data "aws_availability_zones" "available" {}
resource "aws_vpc" "db_vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "db-vpc"
}
}
resource "aws_subnet" "db_subnet" {
count = 2
vpc_id = aws_vpc.db_vpc.id
cidr_block = element(["10.0.1.0/24", "10.0.2.0/24"], count.index)
availability_zone = element(data.aws_availability_zones.available.names, count.index)
tags = {
Name = "db-subnet-${count.index}"
}
}
resource "aws_internet_gateway" "db_igw" {
vpc_id = aws_vpc.db_vpc.id
tags = {
Name = "db-igw"
}
}
resource "aws_route_table" "db_route_table" {
vpc_id = aws_vpc.db_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.db_igw.id
}
tags = {
Name = "db-route-table"
}
}
resource "aws_route_table_association" "db_route_table_assoc" {
count = 2
subnet_id = element(aws_subnet.db_subnet[*].id, count.index)
route_table_id = aws_route_table.db_route_table.id
}
resource "aws_db_subnet_group" "db_subnet_group" {
name = "db-subnet-group"
subnet_ids = aws_subnet.db_subnet[*].id
tags = {
Name = "db-subnet-group"
}
}
# DB Security
resource "aws_security_group" "db_sg" {
description = "Allow DB instance access"
vpc_id = aws_vpc.db_vpc.id
ingress {
from_port = 3306
to_port = 3306
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 = "db-sg"
}
}
# DB Instance
resource "aws_db_instance" "db_instance" {
identifier = {your_db_instance_name}
instance_class = "db.t3.micro" // free tier
engine = "mysql"
engine_version = "8.0.34"
username = {db_username}
password = {db_password}
db_name = {db_name}
allocated_storage = 20
db_subnet_group_name = aws_db_subnet_group.db_subnet_group.name
vpc_security_group_ids = [aws_security_group.db_sg.id]
skip_final_snapshot = true
publicly_accessible = true
}
다음 글에서는 main.tf 하나의 파일을 역할에 맞게 분리, 연결하는 작업을 진행할 것이다.
이 때 variable.tf 등 보안과 관련된 파일을 .gitignore에 추가해 공개되는 것을 막는 작업 등도 포함되어 있으니,
커밋은 다음 글까지 진행한 다음 찍어주자.
[Spring Boot] 초기 프로젝트 403 error request 처리 실패 해결 (0) | 2024.07.20 |
---|---|
[Terraform] 리소스 모듈화 - Terraform 가이드 (4) (0) | 2024.07.16 |
[Terraform] Terraform 환경 설정 - Terraform 가이드 (1) (0) | 2024.07.15 |
[Docker] Docker 자주 쓰는 명령어 정리 (0) | 2024.07.14 |
[Docker] Docker 설치, 개념 정리 (1) | 2024.07.14 |