오늘은 Terraform을 이용하여 3-Tier Test 환경을 구축하는 방법을 알아보겠습니다.
우선 Terraform이 무엇인지 간단하게 알아보겠습니다.
Terraform 다운로드 페이지에서 로컬 PC의 운영체제에 맞는 파일을 다운로드 합니다.이후 압축을 해제하고 원하는 경로에 삽입한 뒤, 환경설정에 해당 경로를 추가하면 설치가 완료됩니다.설치가 끝나면 로컬에 aws 인증 설정을 적용해 줍니다. AWS 계정에서 발급한 IAM 사용자의 AWS AccessKey와 Secret Access Key를 등록해줍니다. (aws cli가 설치되어 있어야 합니다.)
aws configure
Provider를 직역하면 제공자 입니다. 인프라의 타입이라고 생각하면 됩니다. 대표적인 Provider의 종류로는 AWS, GCP, Azure가 있습니다.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# Configure the AWS Provider
provider "aws" {
region = "us-east-1"
}
# Create a VPC
resource "aws_vpc" "example" {
cidr_block = "10.0.0.0/16"
}
위 코드는 Terraform 공식 docs에 있는 사용 사례입니다.
terraform의 provider로 aws를 지정하고 provider의 version은 5.0버전 이상을 사용하겠다고 선언한 코드입니다.
이 때 provider의 설정을 작성해 주어야 하는데 하드코딩 하는 방법과 변수로 입력하는 방법이 있습니다.
(하드코딩 하는 방법은 보안상의 이유로 추천하지 않습니다.)
provider "aws" {
region = "us-west-2"
access_key = "my-access-key"
secret_key = "my-secret-key"
}
↑ 하드 코딩 하는 방법
↓ 하드 코딩을 하지 않는 방법
- 이 경우에는 credential 파일에 정보를 저장하고 profile을 선택하는 방법입니다.
provider "aws" {
region = "ap-northeast-2"
shared_credentials_file = "/Users/tf_user/.aws/creds" # Credential 파일 위치
profile = "chaechae" # Credential 파일 내의 저장된 profile 중 선택
}
Resource Block은 아래와 같은 형태로 작성합니다.
resource "RESOURCE_TYPE" "NAME" {
ARGUMENT = VALUE
}
AWS provider의 Data Resource는 링크를 참고해 주시기 바랍니다.
예를 들면 아래와 같이 작성할 수 있습니다.
resource "aws_instance" "bastion_server" {
ami = "ami-23409c2"
instance_type = "t3.medium"
tags = {
Name = "TestBastionServer"
}
}
terraform init
Terraform을 initializing하는 명령어 입니다.
현재 터미널이 위치한 디렉토리에서 초기화를 진행하므로 Terraform main.tf파일이 있는 위치에서 진행해 줍니다.
초기화를 진행하게 되면 .terraform 폴더가 생성됩니다.
※ 이 폴더는 직접 수정하거나 혹은 공유하면 안됩니다.
terraform fmt
새로운 파일을 작성하거나 기존 파일을 변경 할 때 실행하는 명령어입니다. 생략할 수 있습니다.
terraform plan
적용을 하기 전 실행하는 명령어로 terraform을 적용 했을 때의 출력을 검토할 수 있습니다.
소스의 양이 방대할 경우 [ -target=resource ] 옵션을 활용하여 해당 리소스와 의존관계에 있는 리소스만 검사 할 수 있습니다.
terraform apply
Terraform을 provider에 적용 시키는 명령어 입니다. 이후 정말 승인 할지 한번 더 물어봅니다.
[ --auto-approve ] 옵션을 입력하면 자동으로 승인됩니다.
terraform destroy
provider에 배포된 Terraform의 리소스들을 삭제하는 명령어 입니다.
이후 정말 삭제할 것인지 묻는 터미널의 질문에 yes라고 입력하면 삭제 됩니다.
Terraform은 변수를 사용할 때 따옴표를 사용하지 않습니다.
숫자를 사용할 때는 따옴표를 사용하지 않습니다.
예를들어 variable.tf 파일에 아래와 같이 입력합니다.
variable "instance_name" {
type = string
description = "aws instance"
default = "WEB Server instance"
}
일반적으로 type, default, description 세가지를 정의합니다.
오늘 실습에서 생성할 아키텍쳐는 위와 같습니다
Region(ap-northeast-2)에 새로운 VPC를 생성하고 2개의 AZ 위에 각각 Public, Private, Database Subnet을 만들것입니다.
Private Subnet에 있는 서버는 NAT Gateway를 통해 외부와 소통하고
Public Subnet에 있는 Bastion 서버는 Internet Gateway를 통해 외부와 소통합니다.
본격적으로 Terraform을 이용하여 3-tier test 환경을 구축해 보는 실습을 진행하겠습니다.
폴더 구조는 아래와 같습니다.
│ bastion.tf
│ iam.tf
│ output.tf
│ private_ec2.tf
│ rds.tf
│ security_groups.tf
│ variables.tf
│ vpc.tf
└───env
└───dev
│ main.tf
│ variables.tf
.terraform 폴더와 provider 폴더 등등 우리가 작성하지 않아도 되는 폴더 구조는 생략하고
실습시 작성해야 할 tf 파일들만 나열해 보았습니다.
terraform의 기본 골자가 되는 폴더입니다. Root module의 기본 진입점이며 Child Module의 Source위치 또는 Module들의 연결을 정의하는 파일이 됩니다.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
provider "aws" {
region = "ap-northeast-2"
}
module "dev" {
source = "../../"
# prj
project_name = var.project_name
enviroment = var.enviroment
# VPC
cidr_vpc = var.cidr_vpc
cidr_public1 = var.cidr_public1
cidr_public2 = var.cidr_public2
cidr_private1 = var.cidr_private1
cidr_private2 = var.cidr_private2
cidr_rds2a = var.cidr_rds2a
cidr_rds2c = var.cidr_rds2c
# Public EC2
bastion_instance_type = var.bastion_instance_type
bastion_key_name = var.bastion_key_name
bastion_volume_size = var.bastion_volume_size
# Private EC2
Private_EC2_instance_type = var.Private_EC2_instance_type
Private_EC2_key_name = var.Private_EC2_key_name
Private_EC2_volume_size = var.Private_EC2_volume_size
}
# prj
variable "project_name" { default = "NAME" }
variable "enviroment" { default = "ec2-test" }
variable "key_pair" { default = "INSERT YOUR KEYPAIR" }
# VPC
variable "cidr_vpc" { default = "192.168.0.0/16"}
variable "cidr_public1" { default = "192.168.1.0/24" }
variable "cidr_public2" { default = "192.168.2.0/24" }
variable "cidr_private1" { default = "192.168.10.0/24" }
variable "cidr_private2" { default = "192.168.20.0/24" }
variable "cidr_rds2a" { default = "192.168.100.0/24" }
variable "cidr_rds2c" { default = "192.168.200.0/24" }
# Bastion
variable "bastion_instance_type" { default = "t3.medium" }
variable "bastion_key_name" { default = "INSERT YOUR KEYPAIR" }
variable "bastion_volume_size" { default = 10 }
# Private EC2
variable "Private_EC2_instance_type" { default = "t3.medium" }
variable "Private_EC2_key_name" { default = "INSERT YOUR KEYPAIR" }
variable "Private_EC2_volume_size" { default = 10 }
여기서부터는 최상위 폴더에서 작업합니다.
main.tf 에서 source를 최상위 폴더로 지정했기 때문입니다.
# VPC
resource "aws_vpc" "vpc" {
cidr_block = var.cidr_vpc
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "${var.project_name}-${var.enviroment}-vpc"
}
}
# Internet Gateway
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.project_name}-${var.enviroment}-igw"
}
}
# NAT Gateway
resource "aws_nat_gateway" "nat_gateway" {
allocation_id = aws_eip.nat_gateway.id
subnet_id = aws_subnet.public1.id
depends_on = [aws_internet_gateway.igw]
tags = {
Name = "${var.project_name}-${var.enviroment}-natgw1"
}
}
resource "aws_eip" "nat_gateway" {
vpc = true
depends_on = [aws_internet_gateway.igw]
tags = {
Name = "${var.project_name}-${var.enviroment}-natgw1-eip"
}
}
# Default route table
resource "aws_default_route_table" "default" {
default_route_table_id = aws_vpc.vpc.default_route_table_id
tags = {
Name = "${var.project_name}-${var.enviroment}-default-rtb"
}
}
# Default security group
resource "aws_default_security_group" "default" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.project_name}-${var.enviroment}-default-sg"
}
}
# Default network access list
resource "aws_default_network_acl" "default" {
default_network_acl_id = aws_vpc.vpc.default_network_acl_id
tags = {
Name = "${var.project_name}-${var.enviroment}-default-nacl"
}
}
# Subnet
## public1-subnet
resource "aws_subnet" "public1" {
vpc_id = aws_vpc.vpc.id
availability_zone = "ap-northeast-2a"
cidr_block = var.cidr_public1
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-${var.enviroment}-public1-subnet"
}
}
## public2-subnet
resource "aws_subnet" "public2" {
vpc_id = aws_vpc.vpc.id
availability_zone = "ap-northeast-2c"
cidr_block = var.cidr_public2
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-${var.enviroment}-public2-subnet"
}
}
## private1-subnet
resource "aws_subnet" "private2a" {
vpc_id = aws_vpc.vpc.id
availability_zone = "ap-northeast-2a"
cidr_block = var.cidr_private1
map_public_ip_on_launch = false
tags = {
Name = "${var.project_name}-${var.enviroment}-private2a-subnet"
}
}
## private2-subnet
resource "aws_subnet" "private2c" {
vpc_id = aws_vpc.vpc.id
availability_zone = "ap-northeast-2c"
cidr_block = var.cidr_private2
map_public_ip_on_launch = false
tags = {
Name = "${var.project_name}-${var.enviroment}-private2c-subnet"
}
}
## RDS-subnet
resource "aws_subnet" "rds2a" {
vpc_id = aws_vpc.vpc.id
availability_zone = "ap-northeast-2a"
cidr_block = var.cidr_rds2a
map_public_ip_on_launch = false
tags = {
Name = "${var.project_name}-${var.enviroment}-rds2a-subnet"
}
}
resource "aws_subnet" "rds2c" {
vpc_id = aws_vpc.vpc.id
availability_zone = "ap-northeast-2c"
cidr_block = var.cidr_rds2c
map_public_ip_on_launch = false
tags = {
Name = "${var.project_name}-${var.enviroment}-rds2c-subnet"
}
}
# Route table
## public1~2
resource "aws_route_table" "public1" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.project_name}-${var.enviroment}-public1-rtb"
}
}
resource "aws_route_table_association" "public1" {
subnet_id = aws_subnet.public1.id
route_table_id = aws_route_table.public1.id
}
resource "aws_route_table_association" "public2" {
subnet_id = aws_subnet.public2.id
route_table_id = aws_route_table.public1.id
}
resource "aws_route" "public1" {
route_table_id = aws_route_table.public1.id
gateway_id = aws_internet_gateway.igw.id
destination_cidr_block = "0.0.0.0/0"
}
## private1~2
resource "aws_route_table" "private2a" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.project_name}-${var.enviroment}-private2a-rtb"
}
}
resource "aws_route_table_association" "private2a" {
subnet_id = aws_subnet.private2a.id
route_table_id = aws_route_table.private2a.id
}
resource "aws_route_table_association" "private2c" {
subnet_id = aws_subnet.private2c.id
route_table_id = aws_route_table.private2a.id
}
resource "aws_route" "private2a" {
route_table_id = aws_route_table.private2a.id
nat_gateway_id = aws_nat_gateway.nat_gateway.id
destination_cidr_block = "0.0.0.0/0"
}
## RDS 1~2
resource "aws_route_table" "rds2a" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.project_name}-${var.enviroment}-rds-rtb"
}
}
resource "aws_route_table" "rds2c" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.project_name}-${var.enviroment}-rds-rtb"
}
}
resource "aws_route_table_association" "rds2a" {
subnet_id = aws_subnet.rds2a.id
route_table_id = aws_route_table.rds2a.id
}
resource "aws_route_table_association" "rds2c" {
subnet_id = aws_subnet.rds2c.id
route_table_id = aws_route_table.rds2c.id
}
# NACL
## public1~2
resource "aws_network_acl" "public1" {
vpc_id = aws_vpc.vpc.id
subnet_ids = [aws_subnet.public1.id, aws_subnet.public2.id]
egress {
protocol = -1
rule_no = 100
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 0
to_port = 0
}
ingress {
protocol = -1
rule_no = 100
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 0
to_port = 0
}
tags = {
Name = "${var.project_name}-${var.enviroment}-public-nacl"
}
}
## private1~2
resource "aws_network_acl" "private2a" {
vpc_id = aws_vpc.vpc.id
subnet_ids = [aws_subnet.private2a.id, aws_subnet.private2c.id]
egress {
protocol = -1
rule_no = 100
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 0
to_port = 0
}
ingress {
protocol = -1
rule_no = 100
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 0
to_port = 0
}
tags = {
Name = "${var.project_name}-${var.enviroment}-private1-nacl"
}
}
# prj
variable "project_name" {
default = "charon"
type = string
}
variable "enviroment" {
default = "ec2-test"
}
# network
variable "cidr_vpc" {
default = "192.168.0.0/16"
}
variable "cidr_public1" {
default = "192.168.1.0/24"
}
variable "cidr_public2" {
default = "192.168.2.0/24"
}
variable "cidr_private1" {
default = "192.168.10.0/24"
}
variable "cidr_private2" {
default = "192.168.20.0/24"
}
variable "cidr_rds2a" {
default = "192.168.100.0/24"
}
variable "cidr_rds2c" {
default = "192.168.200.0/24"
}
# Bastion AMI를 미리 콘솔에서 생성해 주어야 합니다.
variable "bastion_ami" {
default = "ami-0fe176a332565f0d4"
}
variable "bastion_instance_type" {
default = "t3.medium"
}
variable "bastion_key_name" {
default = "INSERT YOUT KEYPAIR"
}
variable "bastion_volume_size" {
default = "10"
}
variable "bastion_volume_type" {
default = "gp3"
}
# Private EC2
variable "Private_EC2_ami" {
default = "ami-0fe176a332565f0d4"
}
variable "Private_EC2_instance_type" {
default = "t3.medium"
}
variable "Private_EC2_key_name" {
default = "INSERT YOUT KEYPAIR"
}
variable "Private_EC2_volume_size" {
default = "10"
}
variable "Private_EC2_volume_type" {
default = "gp3"
}
#Access Key 아래와 같이 하드코딩 하는 방식은 추천하지 않습니다.
variable "AWS_AccessKey" {
default = "INSERT YOUR ACCESSKEY"
}
variable "AWS_SecretKey" {
default = "INSERT YOUR SECRETKEY"
}
# DB password
variable "db_password" {
description = "RDS root user password"
type = string
sensitive = true
}
# Security Group
# Bastion EC2 SG
resource "aws_security_group" "bastion_ec2" {
name = "${var.project_name}-${var.enviroment}-bastion-sg"
description = "for bastion ec2"
vpc_id = aws_vpc.vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
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.project_name}-${var.enviroment}-bastion-sg"
}
}
# Private EC2 SG
resource "aws_security_group" "private_ec2" {
name = "${var.project_name}-${var.enviroment}-private-sg"
description = "for private ec2"
vpc_id = aws_vpc.vpc.id
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-${var.enviroment}-private-sg"
}
}
resource "aws_security_group_rule" "private_ec2" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
source_security_group_id = aws_security_group.bastion_ec2.id
security_group_id = aws_security_group.private_ec2.id
}
# RDS SG
resource "aws_security_group" "private_rds" {
name = "${var.project_name}-${var.enviroment}-rds-sg"
description = "for private rds"
vpc_id = aws_vpc.vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
security_groups = [aws_security_group.bastion_ec2.id]
}
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
security_groups = [aws_security_group.private_ec2.id]
}
egress {
from_port = 22
to_port = 22
protocol = "tcp"
security_groups = [aws_security_group.bastion_ec2.id]
}
egress {
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-${var.enviroment}-rds-sg"
}
}
data "aws_iam_policy_document" "ec2_assume_role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
data "aws_iam_policy" "systems_manager" {
arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
data "aws_iam_policy" "cloudwatch_agent" {
arn = "arn:aws:iam::aws:policy/CloudWatchAgentAdminPolicy"
}
# IAM Role
## bastion
resource "aws_iam_role" "bastion" {
name = "${var.project_name}-${var.enviroment}-bastion-iamrole"
assume_role_policy = data.aws_iam_policy_document.ec2_assume_role.json
}
resource "aws_iam_role_policy_attachment" "bastion_ssm" {
role = aws_iam_role.bastion.name
policy_arn = data.aws_iam_policy.systems_manager.arn
}
resource "aws_iam_role_policy_attachment" "bastion_cloudwatch" {
role = aws_iam_role.bastion.name
policy_arn = data.aws_iam_policy.cloudwatch_agent.arn
}
resource "aws_iam_instance_profile" "bastion" {
name = "${var.project_name}-${var.enviroment}-bastion-instanceprofile"
role = aws_iam_role.bastion.name
}
## private_ec2
resource "aws_iam_role" "private_ec2" {
name = "${var.project_name}-${var.enviroment}-private_ec2-iamrole"
assume_role_policy = data.aws_iam_policy_document.ec2_assume_role.json
}
resource "aws_iam_role_policy_attachment" "private_ec2_ssm" {
role = aws_iam_role.private_ec2.name
policy_arn = data.aws_iam_policy.systems_manager.arn
}
resource "aws_iam_role_policy_attachment" "private_ec2_cloudwatch" {
role = aws_iam_role.private_ec2.name
policy_arn = data.aws_iam_policy.cloudwatch_agent.arn
}
resource "aws_iam_instance_profile" "private_ec2" {
name = "${var.project_name}-${var.enviroment}-private_ec2-instanceprofile"
role = aws_iam_role.private_ec2.name
}
output "rds_hostname" {
description = "RDS instance hostname"
value = aws_db_instance.charon
sensitive = true
}
output "rds_port" {
description = "RDS instance port"
value = aws_db_instance.charon.port
sensitive = true
}
output "rds_username" {
description = "RDS instance root username"
value = aws_db_instance.charon.username
sensitive = true
}
이제까지 VPC를 구성하는 환경에 대해서 terraform 코드를 통해 설정하였습니다. 다음으로는 bastion ec2, private ec2, rds를 생성하는 작업을 진행해 보겠습니다.
# EC2
resource "aws_eip" "bastion" {
instance = aws_instance.bastion.id
vpc = true
tags = {
Name = "${var.project_name}-${var.enviroment}-bastion-eip"
}
}
resource "aws_instance" "bastion" {
ami = var.bastion_ami
instance_type = var.bastion_instance_type
vpc_security_group_ids = [aws_security_group.bastion_ec2.id]
iam_instance_profile = aws_iam_instance_profile.bastion.name
subnet_id = aws_subnet.public1.id
key_name = var.bastion_key_name
disable_api_termination = true
root_block_device {
volume_size = var.bastion_volume_size
volume_type = "gp3"
delete_on_termination = true
tags = {
Name = "${var.project_name}-${var.enviroment}-bastion-ec2"
}
}
tags = {
Name = "${var.project_name}-${var.enviroment}-bastion-ec2"
}
}
# EC2
resource "aws_instance" "private-ec2" {
ami = var.Private_EC2_ami
instance_type = var.Private_EC2_instance_type
vpc_security_group_ids = [aws_security_group.private_ec2.id]
iam_instance_profile = aws_iam_instance_profile.private_ec2.name
subnet_id = aws_subnet.private2a.id
associate_public_ip_address = false
key_name = var.Private_EC2_key_name
disable_api_termination = true
root_block_device {
volume_size = var.Private_EC2_volume_size
volume_type = "gp3"
delete_on_termination = true
tags = {
Name = "${var.project_name}-${var.enviroment}-private-ec2"
}
}
tags = {
Name = "${var.project_name}-${var.enviroment}-private-ec2"
}
}
resource "aws_db_parameter_group" "charon" {
name = "charon"
family = "mysql5.7"
parameter {
name = "character_set_server"
value = "utf8"
}
parameter {
name = "character_set_client"
value = "utf8"
}
}
#DB subnet group
resource "aws_db_subnet_group" "charon" {
name = "charon"
subnet_ids = [aws_subnet.rds2a.id, aws_subnet.rds2c.id]
}
resource "aws_db_instance" "charon" {
identifier = "charon"
allocated_storage = 10
db_name = "charon_rds"
engine = "mysql"
engine_version = "5.7"
instance_class = "db.t3.medium"
username = "charon"
password = "INSERT YOUR PASSWORD"
parameter_group_name = aws_db_parameter_group.charon.name
skip_final_snapshot = true
publicly_accessible = true
vpc_security_group_ids = [aws_security_group.private_rds.id]
db_subnet_group_name = aws_db_subnet_group.charon.name
}
이로써 드디어 tf 코드 작성이 완료되었습니다.
이제 배포를 시작해 보겠습니다.
필자는 VS code환경에서 코드를 작성하였으므로 참고하여 주시기 바랍니다.
터미널을 열고 해당 폴더로 진입합니다. 이후 terraform init을 하여 terraform의 initializing을 진행해줍니다.
Initializing이 성공하면 위와 같은 메세지가 출력됩니다.
현재는 변경 사항이 없으므로 포멧팅은 생략합니다.
모든 파일에 대해서 배포를 진행할 것이므로 특정 옵션을 사용하지 않고 계획을 진행하겠습니다.
terraform plan을 입력하여 문법과 배포 등에 이상이 없는지 확인합니다.
앞서 작성한 RDS root user의 비밀번호를 입력해 줍니다.
Plan이 성공하면 위와 같은 메세지가 출력되고 앞서 작성한 Outputs 파일의 값들이 표시됩니다.
Output의 정보를 더 출력받기를 원하신다면 독자분들의 입맛에 맞게 코드를 추가해 주면 되겠습니다.
이제 terraform apply를 진행해 보겠습니다.
앞서 plan과 같이 RDS 비밀번호를 물어봅니다.
이후 비밀번호를 입력해 주면 실제로 배포를 진행할 지 다시한번 물어봅니다.
yes를 입력하면 배포가 진행됩니다.
대다수의 리소스들이 1초 이내로 배포 됩니다.
다만, nat gateway와 RDS는 조금 소요되지만 모든 리소스가 생성되는데 5분 가량이면 완료됩니다.
콘솔에서 직접 VPC를 만들고 기타 설정들을 한땀한땀 진행하는 것 보다 수십배나 절약할 수 있습니다.
저는 모든 리소스가 생성되는데 6분정도 소요되었습니다.
그럼 이제 배포된 리소스들을 확인해 보겠습니다.
모든 리소스들이 정상적으로 생성되었습니다.
이로써 Terraform을 이용하여 3tier test 환경을 구축하는 실습이 완료 되었습니다
마지막으로 리소스들을 삭제하는 destroy 명령어를 입력하여 모든 리소스를 삭제해보겠습니다.
앞서와 같이 RDS의 비밀번호를 입력해줍니다.
리소스를 진짜 삭제할지 물어봅니다. yes를 입력해 줍니다.
성공했다면 아래와 같은 메세지가 출력됩니다.
소스코드가 변경되지 않은 이상 destroy가 실패할 경우는 없습니다.
이로써 모든 실습이 완료되었습니다.
감사합니다.
[AWS] 1. AWS(Amazon Web Services)와 클라우드 컴퓨팅(Cloud Computing)이란? (0) | 2022.10.18 |
---|
댓글 영역