본문 바로가기

♻ Terraform(테라폼)/Module-EC2

Terraform을 활용한 EC2 인스턴스 생성 및 아파치 웹서버 설치

# Terraform을 활용한 EC2 인스턴스 생성 후 아파치 웹서버를 설치하여 확인을 해보자.

1. 목표 아키텍처 확인하기

- 이해를 돕기 위해 주요 리소스에 넘버링을 하였다.

EC2_Public_Numbering.drawio
0.00MB

- EC2 인스턴그 관련 리소스만 설명을 하면 아래와 같다. (파란색 바탕의 넘버링 확인)

① EIP : EC2 인스턴스가 사용할 EIP를 생성한다.

② EC2 인스턴스 : 퍼블릭 망에 존재하는 EC2 인스턴스이다.

②-① : EC2 인스턴스에 구성될 Apache WebServer이다.

③ PrivateKey : RSA 알고리즘으로 구성된 TLS Private Key이다.

④ 보안그룹 : 해당 EC2 인스턴스에서 사용할 보안그룹을 생성한다. (인바운드와 아웃바운드도 설정)

⑤ KeyPair :. pem으로 구성된 Key_Pair 파일을 생성한다.

- 일단 1번에서 14번까지는 아래의 링크를 확인한다.

2023.02.28 - [Terraform(테라폼)/Module-VPC] - Terraform - Module을 활용한 VPC 설계

 

Terraform - Module을 활용한 VPC 설계

# 생성 리소스 설명 -목표 아키텍처는 아래와 같고, Terraform Module을 활용하여 VPC를 설계한다. - 리전 : ap-northeast-2 (서울) - AZ : A영역과 C영역 사용 - 서브넷 : 4개 (퍼블릭 2개, 프라이빗 2개) - 인터넷

may9noy.tistory.com

2. 구성한 Terraform Code 실행하기

- 구조를 보면 아래와 같다.

- Root 폴더 아래에 modules라는 폴더가 보인다. Root 폴더 아래에 변수로 정의된 리소스가 module폴더를 활용하여 리소스를 생성한다고 보면 된다.

    ├─modules
    │  ├─module.ec2
    │  └─module.vpc
    └─Root
        └─.terraform
            ├─modules
            └─providers
                └─registry.terraform.io
                    └─hashicorp
                        ├─aws
                        │  └─4.56.0
                        │      └─windows_386
                        ├─local
                        │  └─2.3.0
                        │      └─windows_386
                        └─tls
                            └─4.0.4
                                └─windows_386

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

Root 폴더아래에 정의된 ec2.tf와 vpc.tf 파일이 modules 폴더의 ec2와 vpc를 참조하여 리소스를 생성한다.

3. Root 폴더의 ec2.tf 파일과 vpc.tf 파일 내용

- ec2.tf 파일 내용

- source 경로는 해당 변수집합이 맵핑될 경로를 말한다.

- 나머지는 default 값으로 세팅하였다.

여기서 중요한 점은 module로 구성되었기 때문에 아래의 변수 값들만 변경하거나 추가하면 새로운 환경의 ec2를 생성할 수 있다는 점이다.

module "ec2" {
  source           = "../modules/module.ec2"
  ami_number       = "ami-0eddbd81024d3fbdd"
  instance_type    = "t2.micro"
  key_name         = "webserver"
  public_subnet    = module.vpc.public_subnet_id
  public_subnet-a  = module.vpc.public_subnet_id-a
  private_subnet   = module.vpc.private_subnet_id
  private_subnet-a = module.vpc.private_subnet_id-a
  vpc_id           = module.vpc.vpc_id
}

- vpc.tf 파일내용은 아래와 같다.

module "vpc" {
  source                      = "../modules/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"
}

4. Root 폴더에서 terraform plan 명령어를 사용하여 생성될 리소스를 확인한다.

- terraform plan을 했을 때 vpc.tf와 ec2.tf 파일을 참조하여 예상 리소스를 화면에 보여준다.

아래 "더 보기" 항목을 클릭하여 전체 리소스 코드를 확인할 수 있다.

더보기
PS \Terraform_New\Terraform_seung\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.ec2.aws_eip.webserver will be created
  + resource "aws_eip" "webserver" {
      + 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.ec2.aws_instance.webserver will be created
  + resource "aws_instance" "webserver" {
      + ami                                  = "ami-0eddbd81024d3fbdd"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = "webserver"
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "webserver"
        }
      + tags_all                             = {
          + "Name" = "webserver"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "27df6bf3f9185d6b06dd3276d82b060b35533ead"
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id                 = (known after apply)
              + capacity_reservation_resource_group_arn = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + maintenance_options {
          + auto_recovery = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
          + instance_metadata_tags      = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_card_index    = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + private_dns_name_options {
          + enable_resource_name_dns_a_record    = (known after apply)
          + enable_resource_name_dns_aaaa_record = (known after apply)
          + hostname_type                        = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # module.ec2.aws_key_pair.kp will be created
  + resource "aws_key_pair" "kp" {
      + arn             = (known after apply)
      + fingerprint     = (known after apply)
      + id              = (known after apply)
      + key_name        = "webserver"
      + key_name_prefix = (known after apply)
      + key_pair_id     = (known after apply)
      + key_type        = (known after apply)
      + public_key      = (known after apply)
      + tags_all        = (known after apply)
    }

  # module.ec2.aws_security_group.webserversg will be created
  + resource "aws_security_group" "webserversg" {
      + arn                    = (known after apply)
      + description            = "allow 22, 80"
      + egress                 = (known after apply)
      + id                     = (known after apply)
      + ingress                = (known after apply)
      + name                   = "webserversg"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags_all               = (known after apply)
      + vpc_id                 = (known after apply)
    }

  # module.ec2.aws_security_group_rule.websg_http will be created
  + resource "aws_security_group_rule" "websg_http" {
      + cidr_blocks              = [
          + "0.0.0.0/0",
        ]
      + description              = "http"
      + from_port                = 80
      + id                       = (known after apply)
      + protocol                 = "tcp"
      + security_group_id        = (known after apply)
      + security_group_rule_id   = (known after apply)
      + self                     = false
      + source_security_group_id = (known after apply)
      + to_port                  = 80
      + type                     = "ingress"
    }

  # module.ec2.aws_security_group_rule.websg_outbound will be created
  + resource "aws_security_group_rule" "websg_outbound" {
      + cidr_blocks              = [
          + "0.0.0.0/0",
        ]
      + description              = "outbound"
      + from_port                = 0
      + id                       = (known after apply)
      + protocol                 = "-1"
      + security_group_id        = (known after apply)
      + security_group_rule_id   = (known after apply)
      + self                     = false
      + source_security_group_id = (known after apply)
      + to_port                  = 0
      + type                     = "egress"
    }

  # module.ec2.aws_security_group_rule.websg_ssh will be created
  + resource "aws_security_group_rule" "websg_ssh" {
      + cidr_blocks              = [
          + "0.0.0.0/0",
        ]
      + description              = "ssh"
      + from_port                = 22
      + id                       = (known after apply)
      + protocol                 = "tcp"
      + security_group_id        = (known after apply)
      + security_group_rule_id   = (known after apply)
      + self                     = false
      + source_security_group_id = (known after apply)
      + to_port                  = 22
      + type                     = "ingress"
    }

  # module.ec2.local_file.ssh_key will be created
  + resource "local_file" "ssh_key" {
      + content              = (sensitive value)
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "webserver.pem"
      + id                   = (known after apply)
    }

  # module.ec2.tls_private_key.pk will be created
  + resource "tls_private_key" "pk" {
      + algorithm                     = "RSA"
      + ecdsa_curve                   = "P224"
      + id                            = (known after apply)
      + private_key_openssh           = (sensitive value)
      + private_key_pem               = (sensitive value)
      + private_key_pem_pkcs8         = (sensitive value)
      + public_key_fingerprint_md5    = (known after apply)
      + public_key_fingerprint_sha256 = (known after apply)
      + public_key_openssh            = (known after apply)
      + public_key_pem                = (known after apply)
      + rsa_bits                      = 4096
    }

  # 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                 = {
          + "Name" = "terraform_vpc_test_eip"
        }
      + tags_all             = {
          + "Name" = "terraform_vpc_test_eip"
        }
      + 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     = {
          + "Name" = "terraform_vpc_test_igw"
        }
      + tags_all = {
          + "Name" = "terraform_vpc_test_igw"
        }
      + 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                 = {
          + "Name" = "terraform_vpc_test_nat"
        }
      + tags_all             = {
          + "Name" = "terraform_vpc_test_nat"
        }
    }

  # 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             = {
          + "Name" = "terraform_vpc_test_private-route-table"
        }
      + tags_all         = {
          + "Name" = "terraform_vpc_test_private-route-table"
        }
      + 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             = {
          + "Name" = "terraform_vpc_test_public-route-table"
        }
      + tags_all         = {
          + "Name" = "terraform_vpc_test_public-route-table"
        }
      + 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: 23 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + private_subnet_id   = (known after apply)
  + private_subnet_id-a = (known after apply)
  + public_subnet_id    = (known after apply)
  + public_subnet_id-a  = (known after apply)

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

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를 활용한 aws 리소스 생성

리소스 생성에는 약 5분 이내 소요된다. 아래는 생성 중인 모습.

- 결과 확인

outputs는 outputs.tf에 정의한 내용을 표출해 준다.

Apply complete! Resources: 23 added, 0 changed, 0 destroyed.

Outputs:

private_subnet_id = "subnet-0"
private_subnet_id-a = "subnet-0"
public_subnet_id = "subnet-0"
public_subnet_id-a = "subnet-0"

5. 생성된 리소스를 AWS Console에서 직접 확인해 보자.

- 일단 아파치 웹서버를 생성하였으므로 웹서버에 정상적으로 접근이 되는지 확인하자.

- EIP를 생성하였으므로, EIP:80으로 접근하면 아래와 같이 내용을 확인할 수 있다.

- 위의 목표 아키텍처의 1~5번까지의 리소스를 확인해 보자.

① EIP : 정상 생성 완료

② ec2 인스턴스 : 정상 생성 완료

②-① 아파치 웹서버 : 정상 생성 완료

③, ⑤ PublicKey와 KeyPair : 정상 생성 완료

④ 보안그룹 : 정상 생성 완료

- 보안그룹의 인바운드와 아웃바운드 확인

: 인바운드

: 아웃바운드

- 이로써 목표 아키텍처의 리소스들은 정상적으로 생성이 된 것을 확인할 수 있다.

- 끝 -

'♻ Terraform(테라폼) > Module-EC2' 카테고리의 다른 글

테라폼 모듈을 2개 사용하는 방법  (0) 2023.02.28