본문 바로가기

♻ Terraform(테라폼)/Module-VPC

Terraform - Module을 활용한 VPC 설계

# 생성 리소스 설명

-목표 아키텍처는 아래와 같고, Terraform Module을 활용하여 VPC를 설계한다.

- 리전 : ap-northeast-2 (서울)

- AZ : A영역과 C영역 사용

- 서브넷 : 4개 (퍼블릭 2개, 프라이빗 2개)

- 인터넷 게이트웨이 : 1개

- NAT 게이트웨이 : 1개

- EIP (NAT에서 사용) : 1개

- 퍼블릭 라우팅 테이블 : 1개

- 프라이빗 라우팅 테이블 : 1개

- 기타 : 라우팅 테이블 연결 작업 → 퍼블릭 서브넷 2개, 프라이빗 서브넷 2개

- EC2 : 2개의 프라이빗 인스턴스 생성

# 목표 아키텍처

- BasicVPC

Bacis_VPC.drawio
0.00MB

0. 기본 폴더 구조 확인

- 기본 폴더 구조는 아래와 같다.

①  리소스를 생성하기 위한 변수들을 입력한다.

② vpc.tf에서 입력된 변수들의 타입과 변수명을 세팅한다.

③ 실제 리소스들을 생성하기 위한 코드들이 존재한다.

1. Terraform을 활용하여 구성

- main.tf 파일을 구성한다.

구성 내용은 아래와 같다. (자세한 설명은 주석으로 달아 놓았으니 참조)

# VPC 생성
resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr_block

  tags = {
    Name = "${var.vpc_name}"
  }
}

# Public 서브넷 생성
resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.public_subnet_cidr_block

  availability_zone = "ap-northeast-2a"

  tags = {
    Name = "${var.public_subnet_name}"
  }
}

# Public-A 서브넷 생성
resource "aws_subnet" "public-a" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.public_subnet_cidr_block-a

  availability_zone = "ap-northeast-2c"

  tags = {
    Name = "${var.public_subnet_name-a}"
  }
}


# Private 서브넷 생성
resource "aws_subnet" "private" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.private_subnet_cidr_block

  availability_zone = "ap-northeast-2a"

  tags = {
    Name = "${var.private_subnet_name}"
  }
}

# Private-A 서브넷 생성
resource "aws_subnet" "private-a" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.private_subnet_cidr_block-a

  availability_zone = "ap-northeast-2c"

  tags = {
    Name = "${var.private_subnet_name-a}"
  }
}

# 인터넷 게이트웨이 생성
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
  tags = {
    Name = "${var.vpc_name}_igw"
  }
}

# EIP 생성 (nat에서 사용)
resource "aws_eip" "nat" {
  vpc = true

  tags = {
    Name = "${var.vpc_name}_eip"
  }
}

# NAT 게이트웨이 생성
resource "aws_nat_gateway" "main" {
  allocation_id = aws_eip.nat.id
  subnet_id     = aws_subnet.public.id
  
  tags = {
    Name = "${var.vpc_name}_nat"
  }
}

# 퍼블릭 라우팅 테이블 생성
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }
  
  tags = {
    Name = "${var.vpc_name}_public-route-table"
  }  
}

# 프라이빗 라우팅 테이블 생성
resource "aws_route_table" "private" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.main.id
  }
  
  tags = {
    Name = "${var.vpc_name}_private-route-table"
  }  
}

# 퍼블릭 서브넷과 프라이빗 서브넷 모두 라우팅 테이블 1개에 연결 (2:1)로 연결함
# 라우팅 테이블 연결 (퍼블릭 서브넷)
resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}

# 라우팅 테이블 연결 (퍼블릭 서브넷-a)
resource "aws_route_table_association" "public-a" {
  subnet_id      = aws_subnet.public-a.id
  route_table_id = aws_route_table.public.id
}

# 라우팅 테이블 연결 (프라이빗 서브넷)
resource "aws_route_table_association" "private" {
  subnet_id      = aws_subnet.private.id
  route_table_id = aws_route_table.private.id
}

# 라우팅 테이블 연결 (프라이빗 서브넷-a)
resource "aws_route_table_association" "private-a" {
  subnet_id      = aws_subnet.private-a.id
  route_table_id = aws_route_table.private.id
}

- variables.tf 파일을 구성한다.

여기서는 따로 outputs.tf 파일의 내용을 생성하지 않았으므로, 바로  variables.tf를 생성하도록 하겠다.

variable "vpc_cidr_block" {
  type = string
}

variable "public_subnet_cidr_block" {
  type = string
}

variable "public_subnet_cidr_block-a" {
  type = string
}

variable "private_subnet_cidr_block" {
  type = string
}

variable "private_subnet_cidr_block-a" {
  type = string
}

variable "vpc_name" {
  type = string
}

variable "public_subnet_name" {
  type = string
}

variable "public_subnet_name-a" {
  type = string
}

variable "private_subnet_name" {
  type = string
}

variable "private_subnet_name-a" {
  type = string
}

- root 폴더안에 vpc.tf 파일을 생성한다.

module "vpc" {
  source                      = "../module.vpc"
  vpc_cidr_block              = "10.0.0.0/16"
  public_subnet_cidr_block    = "10.0.1.0/24"
  public_subnet_cidr_block-a  = "10.0.2.0/24"
  private_subnet_cidr_block   = "10.0.3.0/24"
  private_subnet_cidr_block-a = "10.0.4.0/24"

  vpc_name              = "terraform_vpc_test"
  public_subnet_name    = "terraform_vpc_test_public_subnet-a"
  public_subnet_name-a  = "terraform_vpc_test_public_subnet-b"
  private_subnet_name   = "terraform_vpc_test_private_subnet-a"
  private_subnet_name-a = "terraform_vpc_test_private_subnet-b"
}

2. Terraform plan & apply를 활용한 리소스 생성

- Terraform의 명령어는 매우 간단하다. init, plan, apply 같은 매우 단순한 구조로 되어 있다.

- 일단 신규로 폴더를 생성 하였다면 terraform init명령어를 실행해 줘야 한다. (root폴더로 이동하고, vpc.tf가 존재하는 영역에서 실행해 주면 된다.)

- terraform init

PS C:\terraform\Terraform_New\root> terraform init
Initializing modules...

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v4.56.0

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

- terraform plan

terraform plan을 실행하면 아래와 같이 생성될 리소스들을 전반적으로 확인을 할 수 있다.

PS C:\terraform\Terraform_New\root> terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  + create

Terraform will perform the following actions:

  # module.vpc.aws_eip.nat will be created
  + resource "aws_eip" "nat" {
      + allocation_id        = (known after apply)
      + association_id       = (known after apply)
      + carrier_ip           = (known after apply)
      + customer_owned_ip    = (known after apply)
      + domain               = (known after apply)
      + id                   = (known after apply)
      + instance             = (known after apply)
      + network_border_group = (known after apply)
      + network_interface    = (known after apply)
      + private_dns          = (known after apply)
      + private_ip           = (known after apply)
      + public_dns           = (known after apply)
      + public_ip            = (known after apply)
      + public_ipv4_pool     = (known after apply)
      + tags_all             = (known after apply)
      + vpc                  = true
    }

  # module.vpc.aws_internet_gateway.main will be created
  + resource "aws_internet_gateway" "main" {
      + arn      = (known after apply)
      + id       = (known after apply)
      + owner_id = (known after apply)
      + tags_all = (known after apply)
      + vpc_id   = (known after apply)
    }

  # module.vpc.aws_nat_gateway.main will be created
  + resource "aws_nat_gateway" "main" {
      + allocation_id        = (known after apply)
      + connectivity_type    = "public"
      + id                   = (known after apply)
      + network_interface_id = (known after apply)
      + private_ip           = (known after apply)
      + public_ip            = (known after apply)
      + subnet_id            = (known after apply)
      + tags_all             = (known after apply)
    }

  # module.vpc.aws_route_table.private will be created
  + resource "aws_route_table" "private" {
      + arn              = (known after apply)
      + id               = (known after apply)
      + owner_id         = (known after apply)
      + propagating_vgws = (known after apply)
      + route            = [
          + {
              + carrier_gateway_id         = ""
              + cidr_block                 = "0.0.0.0/0"
              + core_network_arn           = ""
              + destination_prefix_list_id = ""
              + egress_only_gateway_id     = ""
              + gateway_id                 = ""
              + instance_id                = ""
              + ipv6_cidr_block            = ""
              + local_gateway_id           = ""
              + nat_gateway_id             = (known after apply)
              + network_interface_id       = ""
              + transit_gateway_id         = ""
              + vpc_endpoint_id            = ""
              + vpc_peering_connection_id  = ""
            },
        ]
      + tags_all         = (known after apply)
      + vpc_id           = (known after apply)
    }

  # module.vpc.aws_route_table.public will be created
  + resource "aws_route_table" "public" {
      + arn              = (known after apply)
      + id               = (known after apply)
      + owner_id         = (known after apply)
      + propagating_vgws = (known after apply)
      + route            = [
          + {
              + carrier_gateway_id         = ""
              + cidr_block                 = "0.0.0.0/0"
              + core_network_arn           = ""
              + destination_prefix_list_id = ""
              + egress_only_gateway_id     = ""
              + gateway_id                 = (known after apply)
              + instance_id                = ""
              + ipv6_cidr_block            = ""
              + local_gateway_id           = ""
              + nat_gateway_id             = ""
              + network_interface_id       = ""
              + transit_gateway_id         = ""
              + vpc_endpoint_id            = ""
              + vpc_peering_connection_id  = ""
            },
        ]
      + tags_all         = (known after apply)
      + vpc_id           = (known after apply)
    }

  # module.vpc.aws_route_table_association.private will be created
  + resource "aws_route_table_association" "private" {
      + id             = (known after apply)
      + route_table_id = (known after apply)
      + subnet_id      = (known after apply)
    }

  # module.vpc.aws_route_table_association.private-a will be created
  + resource "aws_route_table_association" "private-a" {
      + id             = (known after apply)
      + route_table_id = (known after apply)
      + subnet_id      = (known after apply)
    }

  # module.vpc.aws_route_table_association.public will be created
  + resource "aws_route_table_association" "public" {
      + id             = (known after apply)
      + route_table_id = (known after apply)
      + subnet_id      = (known after apply)
    }

  # module.vpc.aws_route_table_association.public-a will be created
  + resource "aws_route_table_association" "public-a" {
      + id             = (known after apply)
      + route_table_id = (known after apply)
      + subnet_id      = (known after apply)
    }

  # module.vpc.aws_subnet.private will be created
  + resource "aws_subnet" "private" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "ap-northeast-2a"
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "10.0.3.0/24"
      + enable_dns64                                   = false
      + enable_resource_name_dns_a_record_on_launch    = false
      + enable_resource_name_dns_aaaa_record_on_launch = false
      + id                                             = (known after apply)
      + ipv6_cidr_block_association_id                 = (known after apply)
      + ipv6_native                                    = false
      + map_public_ip_on_launch                        = false
      + owner_id                                       = (known after apply)
      + private_dns_hostname_type_on_launch            = (known after apply)
      + tags                                           = {
          + "Name" = "terraform_vpc_test_private_subnet-a"
        }
      + tags_all                                       = {
          + "Name" = "terraform_vpc_test_private_subnet-a"
        }
      + vpc_id                                         = (known after apply)
    }

  # module.vpc.aws_subnet.private-a will be created
  + resource "aws_subnet" "private-a" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "ap-northeast-2c"
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "10.0.4.0/24"
      + enable_dns64                                   = false
      + enable_resource_name_dns_a_record_on_launch    = false
      + enable_resource_name_dns_aaaa_record_on_launch = false
      + id                                             = (known after apply)
      + ipv6_cidr_block_association_id                 = (known after apply)
      + ipv6_native                                    = false
      + map_public_ip_on_launch                        = false
      + owner_id                                       = (known after apply)
      + private_dns_hostname_type_on_launch            = (known after apply)
      + tags                                           = {
          + "Name" = "terraform_vpc_test_private_subnet-b"
        }
      + tags_all                                       = {
          + "Name" = "terraform_vpc_test_private_subnet-b"
        }
      + vpc_id                                         = (known after apply)
    }

  # module.vpc.aws_subnet.public will be created
  + resource "aws_subnet" "public" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "ap-northeast-2a"
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "10.0.1.0/24"
      + enable_dns64                                   = false
      + enable_resource_name_dns_a_record_on_launch    = false
      + enable_resource_name_dns_aaaa_record_on_launch = false
      + id                                             = (known after apply)
      + ipv6_cidr_block_association_id                 = (known after apply)
      + ipv6_native                                    = false
      + map_public_ip_on_launch                        = false
      + owner_id                                       = (known after apply)
      + private_dns_hostname_type_on_launch            = (known after apply)
      + tags                                           = {
          + "Name" = "terraform_vpc_test_public_subnet-a"
        }
      + tags_all                                       = {
          + "Name" = "terraform_vpc_test_public_subnet-a"
        }
      + vpc_id                                         = (known after apply)
    }

  # module.vpc.aws_subnet.public-a will be created
  + resource "aws_subnet" "public-a" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "ap-northeast-2c"
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "10.0.2.0/24"
      + enable_dns64                                   = false
      + enable_resource_name_dns_a_record_on_launch    = false
      + enable_resource_name_dns_aaaa_record_on_launch = false
      + id                                             = (known after apply)
      + ipv6_cidr_block_association_id                 = (known after apply)
      + ipv6_native                                    = false
      + map_public_ip_on_launch                        = false
      + owner_id                                       = (known after apply)
      + private_dns_hostname_type_on_launch            = (known after apply)
      + tags                                           = {
          + "Name" = "terraform_vpc_test_public_subnet-b"
        }
      + tags_all                                       = {
          + "Name" = "terraform_vpc_test_public_subnet-b"
        }
      + vpc_id                                         = (known after apply)
    }

  # module.vpc.aws_vpc.main will be created
  + resource "aws_vpc" "main" {
      + arn                                  = (known after apply)
      + cidr_block                           = "10.0.0.0/16"
      + default_network_acl_id               = (known after apply)
      + default_route_table_id               = (known after apply)
      + default_security_group_id            = (known after apply)
      + dhcp_options_id                      = (known after apply)
      + enable_classiclink                   = (known after apply)
      + enable_classiclink_dns_support       = (known after apply)
      + enable_dns_hostnames                 = (known after apply)
      + enable_dns_support                   = true
      + enable_network_address_usage_metrics = (known after apply)
      + id                                   = (known after apply)
      + instance_tenancy                     = "default"
      + ipv6_association_id                  = (known after apply)
      + ipv6_cidr_block                      = (known after apply)
      + ipv6_cidr_block_network_border_group = (known after apply)
      + main_route_table_id                  = (known after apply)
      + owner_id                             = (known after apply)
      + tags                                 = {
          + "Name" = "terraform_vpc_test"
        }
      + tags_all                             = {
          + "Name" = "terraform_vpc_test"
        }
    }

Plan: 14 to add, 0 to change, 0 to destroy.

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform
apply" now.

- terraform apply를 통한 리소스 생성

terraform apply를 실행하면 아래와 같이 정말 실행을 할거냐는 확인 메시지가 나온다. 여기서 yes를 입력해 주면 된다.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:

- 생성중인 모습 여러 가지 리소스가 차례대로 생성이 되고 있다.

- 생성이 완료되면 아래와 같이 생성이 완료되었다는 메시지가 출력된다.

14개의 리소스가 생성이 되었고, 변경된거나 삭제된 것은 없다.

3. AWS Console로 이동하여 정상적으로 생성이 되었는지 확인

- AWS Console로 이동 후 위에서 Terraform으로 생성한 리소스가 정상적으로 생성이 되었는지 확인한다.

- 리소스 생성 순서 확인

1. eip
2. internet_gateway
3. nat_gateway
4. route_table_private
5. route_table_public
6. route_table_association_private
7. route_table_association_private-a
8. route_table_association_public
9. route_table_association_public-a
10. subnet_private
11. subnet_private-a
12. subnet_public
13. subnet_public-a
14. aws_vpc_main

① eip 확인

- 정상적으로 생성이 된것을 확인할 수 있다.

② internet_gateway 확인

- 정상적으로 생성된것을 확인할 수 있다.

③ nat_gateway 확인

- 정상 생성 확인

④ route_table_private 확인

⑤ route_table_public 확인

⑥, ⑦ 프라이빗 서브넷과 프라이빗 라우팅 테이블과 연결 확인

⑧, ⑨ 퍼블릭 서브넷과 퍼블릭 라우팅 테이블과 연결 확인

⑩, ⑪ subnet_private, subnet_private-a 생성 확인

⑫, ⑬ subnet_public, subnet_public-a 생성 확인

⑭ vpc 생성 확인

이렇게 terraform을 활용하여 간단한 vpc 네트워크를 생성 하였다.

추후에 다른 리소스들도 생성을 해보자~