2020. 2. 17. 16:55ㆍIT/SysOps
Terraform은 하시코프에서 오픈소스로 개발 중인 인프라 관리 도구이다. 인프라 환경을 구축하는 도구로써, 셰프와 앤서블과 같은 설정 관리 도구 및 프로비저닝 도구로 분류된다.
본문에서는 Terraform으로 AWS에서 애플리케이션을 배포하기 위한 인프라 프로비저닝을 수행한다.
1. 사전 준비
1.1 Terraform 설치
Terraform 홈페이지 다운로드 파일을 확인하여 설치한다. (https://www.terraform.io/downloads.html)
$ wget https://releases.hashicorp.com/terraform/0.12.12/terraform_0.12.12_linux_amd64.zip$ unzip terraform_0.12.12_linux_amd64.zip
1.2 AWS 연동
AWS Provider를 정의한다. 다음과 같이 AWS 계정 API와 함께 정의한다.
provider "aws" {
access_key = " "
secret_key = " "
region = "ap-northeast-2"
}
Terraform 프로젝트를 초기화한다. 프로젝트 초기화시, provider 설정을 보고, 필요한 플러그인이 설치된다.
$ terraform init
EC2용 SSH 키 페어를 정의한다.
$ ssh-keygen -t rsa -b 4096 -C "<EMAIL_ADDRESS>" -f "$HOME/.ssh/admin" -N ""
"aws_key_pair"는 리소스 타입이고, "admin"은 리소스에 임의로 붙일 수 있는 이름이다.
키를 생성하고, 아래와 같이 생성한 경로를 지정한다.
resource "aws_key_pair" "admin" {
key_name = "admin"
public_key = "${file("~/.ssh/admin.pub")}"
}
2. Terraform 이용한 AWS 리소스 구성
Terraform을 이용하여 프로비저닝하고자 하는 구성은 다음과 같다.
2.1 VPC 구성
aws_vpc 리소스 타입으로 vpc를 생성한다. vpc 이름은 joohyun-vpc가 된다. 생성시 선택사항으로 다음 옵션을 지정할 수 있다.
-
instance_tenancy : VPC로 시작한 인스턴스의 테넌시 옵션
-
enable_dns_support : VPC에서 DNS 활성화
-
enable_dns_hostnames : VPC에서 DNS 호스트 이름 활성화
resource "aws_vpc" "joohyun-vpc" {
cidr_block = "50.0.0.0/22"
instance_tenancy = "default"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "joohyun-vpc"
}
}
2.2 Subnet 설정
위에서 만든 VPC에서 사용할 서브넷을 생성한다.
aws_subnet는 리소스 타입으로 서브넷을 생성한다. 생성시 선택사항으로 다음 옵션을 지정할 수 있다.
-
availability_zone : 서브넷의 AZ
-
map_public_ip_on_launch : 서브넷에 생성된 인스턴스에 퍼블릭 IP 주소 할당
resource "aws_subnet" "joohyun-subnet-pri-2a-1" {
vpc_id = aws_vpc.joohyun-vpc.id
cidr_block = "50.0.1.0/25"
map_public_ip_on_launch = false
availability_zone = "ap-northeast-2a"
tags = {
Name = "joohyun-subnet-pri-2a-1"
}
}
resource "aws_subnet" "joohyun-subnet-pub-2a-1" {
vpc_id = aws_vpc.joohyun-vpc.id
cidr_block = "50.0.0.0/25"
map_public_ip_on_launch = false
availability_zone = "ap-northeast-2a"
tags = {
Name = "joohyun-subnet-pub-2a-1"
}
}
resource "aws_subnet" "joohyun-subnet-pub-2c-1" {
vpc_id = aws_vpc.joohyun-vpc.id
cidr_block = "50.0.0.128/25"
map_public_ip_on_launch = false
availability_zone = "ap-northeast-2c"
tags = {
Name = "joohyun-subnet-pub-2c-1"
}
}
resource "aws_subnet" "joohyun-subnet-pri-2c-1" {
vpc_id = aws_vpc.joohyun-vpc.id
cidr_block = "50.0.1.128/25"
map_public_ip_on_launch = false
availability_zone = "ap-northeast-2c"
tags = {
Name = "joohyun-subnet-pri-2c-1"
}
}
resource "aws_subnet" "joohyun-subnet-db-2a-1" {
vpc_id = aws_vpc.joohyun-vpc.id
cidr_block = "50.0.2.0/25"
map_public_ip_on_launch = false
availability_zone = "ap-northeast-2a"
tags = {
Name = "joohyun-subnet-db-2a-1"
}
}
resource "aws_subnet" "joohyun-subnet-db-2c-1" {
vpc_id = aws_vpc.joohyun-vpc.id
cidr_block = "50.0.2.128/25"
map_public_ip_on_launch = false
availability_zone = "ap-northeast-2c"
tags = {
Name = "joohyun-subnet-db-2c-1"
}
}
2.3 Security Group 설정
aws_security_group는 리소스 타입으로 보안 그룹을 생성한다. 생성시 선택사항으로 다음 옵션을 지정할 수 있다.
-
ingress : 인바운드 규칙
-
egress : 아웃바운드 규칙
-
protocol : 프로토콜 지정 (-1은 모두 허용)
-
description : 규칙에 대한 설명
# create security group
resource "aws_security_group" "joohyun-app-sg" {
vpc_id = "${aws_vpc.joohyun-vpc.id}"
name = "joohyun-app-sg"
tags = {
Name = "joohyun-app-sg"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "joohyun-public-sg" {
vpc_id = "${aws_vpc.joohyun-vpc.id}"
name = "joohyun-public-sg"
tags = {
Name = "joohyun-public-sg"
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "ssh"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["61.34.245.204/32"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "joohyun-bastion-sg" {
vpc_id = "${aws_vpc.joohyun-vpc.id}"
name = "joohyun-bastion-sg"
tags = {
Name = "joohyun-bastion-sg"
}
ingress {
description = "gsitm office 1"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["61.34.245.204/32"]
}
ingress {
description = "gsitm office 2"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["58.124.137.165/32"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "joohyun-db-sg" {
vpc_id = "${aws_vpc.joohyun-vpc.id}"
name = "joohyun-db-sg"
tags = {
Name = "joohyun-db-sg"
}
ingress {
description = "local"
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = ["50.0.0.0/22"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "joohyun-efs-sg" {
vpc_id = "${aws_vpc.joohyun-vpc.id}"
name = "joohyun-efs-sg"
tags = {
Name = "joohyun-efs-sg"
}
ingress {
from_port = 2049
to_port = 2049
protocol = "tcp"
cidr_blocks = ["50.0.0.0/22"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "joohyun-nlb-sg" {
vpc_id = "${aws_vpc.joohyun-vpc.id}"
name = "joohyun-nlb-sg"
tags = {
Name = "joohyun-nlb-sg"
}
ingress {
description = "stfp"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["61.34.245.204/32"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "joohyun-jenkins-sg" {
vpc_id = "${aws_vpc.joohyun-vpc.id}"
name = "joohyun-jenkins-sg"
tags = {
Name = "joohyun-jenkins-sg"
}
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "gsitm-cicd-vpc"
from_port = 0
to_port = 0
protocol = -1
cidr_blocks = ["10.0.0.0/24"]
}
ingress {
description = "office"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["61.34.245.204/32"]
}
ingress {
description = "office"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["58.124.137.165/32"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
#joohyun-app-sg
resource "aws_security_group_rule" "joohyun-app-sg-rule-1" {
type = "ingress"
from_port = 0
to_port = 0
protocol = -1
description = "dmz"
security_group_id = "${aws_security_group.joohyun-app-sg.id}"
source_security_group_id = "${aws_security_group.joohyun-public-sg.id}"
lifecycle { create_before_destroy = true }
}
resource "aws_security_group_rule" "joohyun-app-sg-rule-2" {
type = "ingress"
from_port = 0
to_port = 0
protocol = -1
description = "nlb"
security_group_id = "${aws_security_group.joohyun-app-sg.id}"
source_security_group_id = "${aws_security_group.joohyun-nlb-sg.id}"
lifecycle { create_before_destroy = true }
}
resource "aws_security_group_rule" "joohyun-app-sg-rule-3" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
description = "ssh for bastion"
security_group_id = "${aws_security_group.joohyun-app-sg.id}"
source_security_group_id = "${aws_security_group.joohyun-bastion-sg.id}"
lifecycle { create_before_destroy = true }
}
#joohyun-public-sg
resource "aws_security_group_rule" "joohyun-public-sg-rule-1" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
description = "bastion ssh"
security_group_id = "${aws_security_group.joohyun-public-sg.id}"
source_security_group_id = "${aws_security_group.joohyun-bastion-sg.id}"
lifecycle { create_before_destroy = true }
}
#joohyun-db-sg
resource "aws_security_group_rule" "joohyun-db-sg-rule-1" {
type = "ingress"
from_port = 3306
to_port = 3306
protocol = "tcp"
description = "mariadb connection for app"
security_group_id = "${aws_security_group.joohyun-db-sg.id}"
source_security_group_id = "${aws_security_group.joohyun-app-sg.id}"
lifecycle { create_before_destroy = true }
}
#joohyun-efs-sg
resource "aws_security_group_rule" "joohyun-efs-sg-rule-1" {
type = "ingress"
from_port = 2049
to_port = 2049
protocol = "tcp"
security_group_id = "${aws_security_group.joohyun-efs-sg.id}"
source_security_group_id = "${aws_security_group.joohyun-app-sg.id}"
lifecycle { create_before_destroy = true }
}
2.4 Routing Table 설정
aws_route_table는 리소스 타입으로 라우팅 테이블을 생성한다. 생성시 선택사항으로 다음 옵션을 지정할 수 있다.
-
vpc_id : 라우팅 테이블이 속한 VPC ID
-
subnet_id : 라우팅 테이블에 연결된 서브넷 ID
# create public route table
resource "aws_route_table" "joohyun-public-route-table" {
vpc_id = "${aws_vpc.joohyun-vpc.id}"
tags = {
Name = "joohyun-public-route-table"
}
}
# associate subnets to public route tables
resource "aws_route_table_association" "joohyun-public-subnet1-association" {
subnet_id = "${aws_subnet.joohyun-subnet-pub-2c-1.id}"
route_table_id = "${aws_route_table.joohyun-public-route-table.id}"
}
resource "aws_route_table_association" "joohyun-public-subnet2-association" {
subnet_id = "${aws_subnet.joohyun-subnet-pub-2a-1.id}"
route_table_id = "${aws_route_table.joohyun-public-route-table.id}"
}
# create private route table
resource "aws_route_table" "joohyun-private-route-table" {
vpc_id = "${aws_vpc.joohyun-vpc.id}"
tags = {
Name = "joohyun-private-route-table"
}
}
# associate subnets to private route tables
resource "aws_route_table_association" "joohyun-private-subnet1-association" {
subnet_id = "${aws_subnet.joohyun-subnet-db-2a-1.id}"
route_table_id = "${aws_route_table.joohyun-private-route-table.id}"
}
resource "aws_route_table_association" "joohyun-private-subnet2-association" {
subnet_id = "${aws_subnet.joohyun-subnet-pri-2a-1.id}"
route_table_id = "${aws_route_table.joohyun-private-route-table.id}"
}
resource "aws_route_table_association" "joohyun-private-subnet3-association" {
subnet_id = "${aws_subnet.joohyun-subnet-pri-2c-1.id}"
route_table_id = "${aws_route_table.joohyun-private-route-table.id}"
}
resource "aws_route_table_association" "joohyun-private-subnet4-association" {
subnet_id = "${aws_subnet.joohyun-subnet-db-2c-1.id}"
route_table_id = "${aws_route_table.joohyun-private-route-table.id}"
}
2.5 Internet Gateway 생성
aws_internet_gateway는 리소스 타입으로 인터넷 게이트웨이를 생성한다.
-
vpc_id : 생성 할 VPC ID
# create the igw
resource "aws_internet_gateway" "joohyun-igw" {
vpc_id = aws_vpc.joohyun-vpc.id
tags = {
Name = "joohyun-igw"
}
}
#route table for public subnet
resource "aws_route" "joohyun-public-route-table" {
route_table_id = "${aws_vpc.joohyun-vpc.default_route_table_id}"
destination_cidr_block = "50.0.0.0/22"
gateway_id = "${aws_internet_gateway.joohyun-igw.id}"
}
2.6 NAT Gateway 생성
aws_eip는 리소스 타입으로 Elastic IP를 생성한다.
aws_nat_gateway 리소스 타입으로 NAT 게이트웨이를 생성한다. 다음은 필수로 설정해야 하는 사항이다.
-
allocation_id : 게이트웨이에 대한 EIP 할당
-
subnet_id : 게이트웨이를 배치할 서브넷 ID
# create eip for nat
resource "aws_eip" "joohyun-nat-eip" {
vpc = true
#depends_on = [aws_internet_gateway.joohyun-igw]
}
# create nat gateway
resource "aws_nat_gateway" "joohyun-nat" {
allocation_id = "${aws_eip.joohyun-nat-eip.id}"
subnet_id = "${aws_subnet.joohyun-subnet-pub-2a-1.id}"
#depends_on = [aws_internet_gateway.joohyun-igw]
tags = {
Name = "joohyun-nat"
}
}
# nat gateway for private subnet
resource "aws_route" "application_private" {
route_table_id = "${aws_route_table.joohyun-private-route-table.id}"
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = "${aws_nat_gateway.joohyun-nat.id}"
}
2.7 EC2 생성
aws_instance는 리소스 타입으로 인스턴스를 생성한다. ami는 필수 설정 사항이고, 나머지는 선택 설정 사항이다.
-
ami : 인스턴스에 사용할 AMI
-
availability_zone : 인스턴스를 시작할 AZ
-
key_name : 인스턴스에 사용할 키페어
-
associate_public_ip_address : 인스턴스와 Public IP 연결
resource "aws_instance" "joohyun-dev-web-server-2a-1" {
ami = "ami-0bea7fd38fabe821a"
availability_zone = "${aws_subnet.joohyun-subnet-pub-2a-1.availability_zone}"
instance_type = "t3.small"
key_name = "${aws_key_pair.admin-1.key_name}"
vpc_security_group_ids = ["${aws_security_group.joohyun-public-sg.id}"]
subnet_id = "${aws_subnet.joohyun-subnet-pub-2a-1.id}"
associate_public_ip_address = true
tags = {
Name = "joohyun-dev-web-server-2a-1"
}
}
resource "aws_instance" "joohyun-dev-was-server-2a-1" {
ami = "ami-0bea7fd38fabe821a"
availability_zone = "${aws_subnet.joohyun-subnet-pub-2a-1.availability_zone}"
instance_type = "t3.medium"
key_name = "${aws_key_pair.admin-1.key_name}"
vpc_security_group_ids = ["${aws_security_group.joohyun-app-sg.id}"]
subnet_id = "${aws_subnet.joohyun-subnet-pri-2a-1.id}"
associate_public_ip_address = false
tags = {
Name = "joohyun-dev-was-server-2a-1"
}
}
resource "aws_instance" "joohyun-dev-reley-server-2a-1" {
ami = "ami-0bea7fd38fabe821a"
availability_zone = "${aws_subnet.joohyun-subnet-pri-2a-1.availability_zone}"
instance_type = "t3.small"
key_name = "${aws_key_pair.admin-1.key_name}"
vpc_security_group_ids = ["${aws_security_group.joohyun-app-sg.id}"]
subnet_id = "${aws_subnet.joohyun-subnet-pri-2a-1.id}"
associate_public_ip_address = false
tags = {
Name = "joohyun-dev-reley-server-2a-1"
}
}
resource "aws_instance" "joohyun-dev-bastion-2a-1" {
ami = "ami-0bea7fd38fabe821a"
availability_zone = "${aws_subnet.joohyun-subnet-pub-2a-1.availability_zone}"
instance_type = "t3.micro"
key_name = "${aws_key_pair.admin-1.key_name}"
vpc_security_group_ids = ["${aws_security_group.joohyun-bastion-sg.id}"]
subnet_id = "${aws_subnet.joohyun-subnet-pub-2a-1.id}"
associate_public_ip_address = true
tags = {
Name = "joohyun-dev-bastion-2a-1"
}
}
resource "aws_instance" "joohyun-dev-jenkins-2a-1" {
ami = "ami-0bea7fd38fabe821a"
availability_zone = "${aws_subnet.joohyun-subnet-pub-2a-1.availability_zone}"
instance_type = "t3.medium"
key_name = "${aws_key_pair.admin-1.key_name}"
vpc_security_group_ids = ["${aws_security_group.joohyun-jenkins-sg.id}"]
subnet_id = "${aws_subnet.joohyun-subnet-pub-2a-1.id}"
associate_public_ip_address = true
tags = {
Name = "joohyun-dev-jenkins-2a-1"
}
}
resource "aws_instance" "joohyun-dev-ap-server-2a-1" {
ami = "ami-0bea7fd38fabe821a"
availability_zone = "${aws_subnet.joohyun-subnet-pri-2a-1.availability_zone}"
instance_type = "t3.medium"
key_name = "${aws_key_pair.admin-1.key_name}"
vpc_security_group_ids = ["${aws_security_group.joohyun-app-sg.id}"]
subnet_id = "${aws_subnet.joohyun-subnet-pri-2a-1.id}"
associate_public_ip_address = false
tags = {
Name = "joohyun-dev-ap-server-2a-1"
}
}
resource "aws_instance" "joohyun-dev-b2c-web-server-2a-1" {
ami = "ami-0bea7fd38fabe821a"
availability_zone = "${aws_subnet.joohyun-subnet-pub-2a-1.availability_zone}"
instance_type = "t3.small"
key_name = "${aws_key_pair.admin-1.key_name}"
vpc_security_group_ids = ["${aws_security_group.joohyun-public-sg.id}"]
subnet_id = "${aws_subnet.joohyun-subnet-pub-2a-1.id}"
associate_public_ip_address = true
tags = {
Name = "joohyun-dev-b2c-web-server-2a-1"
}
}
resource "aws_instance" "joohyun-dev-b2c-was-server-2a-1" {
ami = "ami-0bea7fd38fabe821a"
availability_zone = "${aws_subnet.joohyun-subnet-pri-2a-1.availability_zone}"
instance_type = "t3.medium"
key_name = "${aws_key_pair.admin-1.key_name}"
vpc_security_group_ids = ["${aws_security_group.joohyun-app-sg.id}"]
subnet_id = "${aws_subnet.joohyun-subnet-pri-2a-1.id}"
associate_public_ip_address = false
tags = {
Name = "joohyun-dev-b2c-was-server-2a-1"
}
}
resource "aws_instance" "joohyun-dev-ap-file-server-2a-1" {
ami = "ami-0bea7fd38fabe821a"
availability_zone = "${aws_subnet.joohyun-subnet-pub-2a-1.availability_zone}"
instance_type = "t3.medium"
key_name = "${aws_key_pair.admin-1.key_name}"
vpc_security_group_ids = ["${aws_security_group.joohyun-public-sg.id}"]
subnet_id = "${aws_subnet.joohyun-subnet-pub-2a-1.id}"
associate_public_ip_address = true
tags = {
Name = "joohyun-dev-ap-file-server-2a-1"
}
}
2.8 EBS 생성
aws_ebs_volume는 리소스 타입으로 EBS 볼륨을 관리한다. availability_zone은 필수 설정 사항이고, 나머지는 선택 설정 사항이다.
- availability_zone : EBS 볼륨이 존재하는 AZ
- size : 드라이브의 크기(GiB)
aws_volume_attachment는 리소스 타입으로 인스턴스에서 볼륨을 연결 할 수 있도록 한다. 다음은 필수 설정 사항이다.
-
device_name : 인스턴스에 표시 할 이름(예 : /dev/sdh또는 xvdh)
-
volume_id : 선택할 볼륨 ID
-
instance_id : 연결할 인스턴스 ID
resource "aws_ebs_volume" "joohyun-ebs-b2c-was-server" {
availability_zone = "ap-northeast-2a"
size = 20
tags = {
Name = "joohyun-ebs-b2c-was-server"
}
}
resource "aws_volume_attachment" "joohyun-ebs-b2c-was-server" {
device_name = "/dev/sdb"
volume_id = "${aws_ebs_volume.joohyun-ebs-b2c-was-server.id}"
instance_id = "${aws_instance.joohyun-dev-b2c-was-server-2a-1.id}"
}
2.9 EFS 생성
aws_efs_file_system는 리소스 타입으로 EFS를 생성한다.
resource "aws_efs_file_system" "joohyun-efs" {
creation_token = "joohyun-efs"
tags = {
Name = "joohyun-efs"
}
}
resource "aws_efs_mount_target" "joohyun-efs-mount-target" {
file_system_id = "${aws_efs_file_system.joohyun-efs.id}"
subnet_id = "${aws_subnet.alpha.id}"
}
resource "aws_vpc" "joohyun-vpc" {
cidr_block = "50.0.0.0/22"
}
resource "aws_subnet" "alpha" {
vpc_id = "${aws_vpc.joohyun-vpc.id}"
availability_zone = "us-west-2a"
cidr_block = "10.0.1.0/24"
}
3. 구현 및 결과 확인
3.1 Terraform 적용
terraform plan은 현재 정의되어 있는 리소스들을 provider에 적용했을때, 어떠한 작업이 수행될지 확인할 수 있다.
$ terraform plan
terraform apply는 실제로 provider에 적용한다. yes를 입력 후, 리소스는 생성된다.
이때 terraform.tfstate 파일이 생성되고, 실제 상태를 저장하고 리소스가 terraform에서 관리하는 리소스임을 기록한다.
$ terraform apply
3.2 생성 결과
3.2.1 EC2
3.2.2 EBS
3.2.3 Security Group
3.2.4 key pair
3.2.5 VPC
3.2.6 Subnet
3.2.7 Route Table
3.2.8 Internet gateway
3.2.9 NAT gateway
3.2.10 EFS
3.3 Terraform 종료
terraform은 생성뿐만 아니라, 인프라 전체를 종료하는 기능도 지원한다. 명령어 terraform destroy를 통해 생성된 인프라의 일괄 종료가 가능하다.
$ terraform destroy
'IT > SysOps' 카테고리의 다른 글
Ansible을 이용한 AWS 리소스 프로비저닝 (Ansible을 이용한 Apache web server, CodeDeploy agent 설치) (0) | 2020.03.09 |
---|