Terraform module

kimchigood·2022년 11월 12일
0

Terraform Study

목록 보기
4/6
post-thumbnail

Module?

A Terraform module is a set of Terraform configuration files in a single directory. Even a simple configuration consisting of a single directory with one or more .tf files is a module.

.
├── LICENSE
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf

Terraform에서는 module을 terraform configuration 파일들의 집합이라고 정의한다. 위와 같이 tf 파일들로 구성되어 있는 구조를 module이라고 하는데, 지금까지 실습해오던 디렉토리도 다 module로 분류가 된다.

왜 쓰는건가?


참조: https://www.oreilly.com/library/view/terraform-up-and/9781491977071/ch04.html

file layout 구조를 사용하는 terraform 디렉토리를 예로 들어보자. stage와 prod 환경에서 공통된 리소스들이 있을 수 있다. 매번 중복된 코드를 작성하는 것 보다, 이렇게 module로 따로 빼내서 관리한다면, 코드재사용이 가능하다.

실습

실습은 terraform에서 제공하는 예제로 해보자. Use Registry Modules in Configuration

terraform에서는 registry를 통해 AWS,Azure 등과 같이 자주 쓰이는 module을 정의해 두었다. Terraform Registry page for the VPC module.
이번 실습에서는 registry의 module을 다운받아서 사용할 것이다.

$ git clone https://github.com/hashicorp/learn-terraform-modules-use.git

$ cd learn-terraform-modules-use
$ ls -al
➜  learn-terraform-modules-use git:(main) ls -al

total 64
drwxr-xr-x  11 nowjean  staff   352 Nov 12 09:38 .
drwxr-xr-x  11 nowjean  staff   352 Nov 12 09:38 ..
drwxr-xr-x  12 nowjean  staff   384 Nov 12 09:38 .git
-rw-r--r--   1 nowjean  staff   716 Nov 12 09:38 .gitignore
-rw-r--r--   1 nowjean  staff  1107 Nov 12 09:38 .terraform.lock.hcl
-rw-r--r--   1 nowjean  staff    47 Nov 12 09:38 LICENSE
-rw-r--r--   1 nowjean  staff   372 Nov 12 09:38 README.md
-rw-r--r--   1 nowjean  staff   861 Nov 12 09:38 main.tf
-rw-r--r--   1 nowjean  staff   267 Nov 12 09:38 outputs.tf
-rw-r--r--   1 nowjean  staff   341 Nov 12 09:38 terraform.tf
-rw-r--r--   1 nowjean  staff  1002 Nov 12 09:38 variables.tf

main.tf

provider "aws" {
  region = "us-west-2"

  default_tags {
    tags = {
      hashicorp-learn = "module-use"
    }
  }
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "3.14.0"

  name = var.vpc_name
  cidr = var.vpc_cidr

  azs             = var.vpc_azs
  private_subnets = var.vpc_private_subnets
  public_subnets  = var.vpc_public_subnets

  enable_nat_gateway = var.vpc_enable_nat_gateway

  tags = var.vpc_tags
}

module "ec2_instances" {
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = "3.5.0"
  count   = 2

  name = "my-ec2-cluster"

  ami                    = "ami-0c5204531f799e0c6"
  instance_type          = "t2.micro"
  vpc_security_group_ids = [module.vpc.default_security_group_id]
  subnet_id              = module.vpc.public_subnets[0]

  tags = {
    Terraform   = "true"
    Environment = "dev"
  }
}

main.tf 파을을 보면 module이 추가된 것을 볼 수 있다. source 위치를 로컬에 있는 경로로 지정할 수 도 있고, 예제처럼 terraform registry 경로를 지정하여 다운받을 수 도 있다.

soruce 경로 지정방법 참고: Module Sources

module 적용하기

moduled을 수정, 적용하거나,source 경로를 변경한 경우 terraform init 명령을 통해 초기화를 시켜줘야한다.

$ terraform init
Initializing modules...
Downloading registry.terraform.io/terraform-aws-modules/ec2-instance/aws 3.5.0 for ec2_instances...
- ec2_instances in .terraform/modules/ec2_instances
Downloading registry.terraform.io/terraform-aws-modules/vpc/aws 3.14.0 for vpc...
- vpc in .terraform/modules/vpc

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Installing hashicorp/aws v4.4.0...
- Installed hashicorp/aws v4.4.0 (signed by HashiCorp)

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.

➜  learn-terraform-modules-use git:(main) ls -al
total 64
drwxr-xr-x  12 nowjean  staff   384 Nov 12 09:44 .
drwxr-xr-x  11 nowjean  staff   352 Nov 12 09:38 ..
drwxr-xr-x  12 nowjean  staff   384 Nov 12 09:44 .git
-rw-r--r--   1 nowjean  staff   716 Nov 12 09:38 .gitignore
drwxr-xr-x   4 nowjean  staff   128 Nov 12 09:44 .terraform
-rw-r--r--   1 nowjean  staff  1107 Nov 12 09:38 .terraform.lock.hcl
-rw-r--r--   1 nowjean  staff    47 Nov 12 09:38 LICENSE
-rw-r--r--   1 nowjean  staff   372 Nov 12 09:38 README.md
-rw-r--r--   1 nowjean  staff   861 Nov 12 09:38 main.tf
-rw-r--r--   1 nowjean  staff   267 Nov 12 09:38 outputs.tf
-rw-r--r--   1 nowjean  staff   341 Nov 12 09:38 terraform.tf
-rw-r--r--   1 nowjean  staff  1002 Nov 12 09:38 variables.tf

➜  learn-terraform-modules-use git:(main) cd .terraform
➜  .terraform git:(main) ls
modules   providers
➜  .terraform git:(main) cd modules
➜  modules git:(main) ls
ec2_instances modules.json  vpc

terraform init을 하면, registry에서 module을 다운받고, .terrafrom 디렉토리 밑에 module들이 생성된다.

terraform plan

다운받은 module과 main.tf, variable.tf가 매핑되어 ec2, vpc를 생성하게 된다.

$ 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_instances[0].aws_instance.this[0] will be created
  + resource "aws_instance" "this" {
      + ami                                  = "ami-0c5204531f799e0c6"
      + 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_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (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                             = (known after apply)
      + monitoring                           = false
      + 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                                 = {
          + "Environment" = "dev"
          + "Name"        = "my-ec2-cluster"
          + "Terraform"   = "true"
        }
      + tags_all                             = {
          + "Environment"     = "dev"
          + "Name"            = "my-ec2-cluster"
          + "Terraform"       = "true"
          + "hashicorp-learn" = "module-use"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + volume_tags                          = {
          + "Name" = "my-ec2-cluster"
        }
      + 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)
            }
        }

      + credit_specification {}

      + 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)
        }

      + metadata_options {
          + http_endpoint               = "enabled"
          + http_put_response_hop_limit = 1
          + http_tokens                 = "optional"
          + instance_metadata_tags      = "disabled"
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (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)
        }

      + timeouts {}
    }

  # module.ec2_instances[1].aws_instance.this[0] will be created
  + resource "aws_instance" "this" {
      + ami                                  = "ami-0c5204531f799e0c6"
      + 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_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (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                             = (known after apply)
      + monitoring                           = false
      + 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                                 = {
          + "Environment" = "dev"
          + "Name"        = "my-ec2-cluster"
          + "Terraform"   = "true"
        }
      + tags_all                             = {
          + "Environment"     = "dev"
          + "Name"            = "my-ec2-cluster"
          + "Terraform"       = "true"
          + "hashicorp-learn" = "module-use"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + volume_tags                          = {
          + "Name" = "my-ec2-cluster"
        }
      + 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)
            }
        }

      + credit_specification {}

      + 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)
        }

      + metadata_options {
          + http_endpoint               = "enabled"
          + http_put_response_hop_limit = 1
          + http_tokens                 = "optional"
          + instance_metadata_tags      = "disabled"
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (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)
        }

      + timeouts {}
    }

  # module.vpc.aws_internet_gateway.this[0] will be created
  + resource "aws_internet_gateway" "this" {
      + arn      = (known after apply)
      + id       = (known after apply)
      + owner_id = (known after apply)
      + tags     = {
          + "Environment" = "dev"
          + "Name"        = "example-vpc"
          + "Terraform"   = "true"
        }
      + tags_all = {
          + "Environment"     = "dev"
          + "Name"            = "example-vpc"
          + "Terraform"       = "true"
          + "hashicorp-learn" = "module-use"
        }
      + vpc_id   = (known after apply)
    }

  # module.vpc.aws_route.public_internet_gateway[0] will be created
  + resource "aws_route" "public_internet_gateway" {
      + destination_cidr_block = "0.0.0.0/0"
      + gateway_id             = (known after apply)
      + id                     = (known after apply)
      + instance_id            = (known after apply)
      + instance_owner_id      = (known after apply)
      + network_interface_id   = (known after apply)
      + origin                 = (known after apply)
      + route_table_id         = (known after apply)
      + state                  = (known after apply)

      + timeouts {
          + create = "5m"
        }
    }

  # module.vpc.aws_route_table.private[0] 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            = (known after apply)
      + tags             = {
          + "Environment" = "dev"
          + "Name"        = "example-vpc-private-us-west-2a"
          + "Terraform"   = "true"
        }
      + tags_all         = {
          + "Environment"     = "dev"
          + "Name"            = "example-vpc-private-us-west-2a"
          + "Terraform"       = "true"
          + "hashicorp-learn" = "module-use"
        }
      + vpc_id           = (known after apply)
    }

  # module.vpc.aws_route_table.private[1] 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            = (known after apply)
      + tags             = {
          + "Environment" = "dev"
          + "Name"        = "example-vpc-private-us-west-2b"
          + "Terraform"   = "true"
        }
      + tags_all         = {
          + "Environment"     = "dev"
          + "Name"            = "example-vpc-private-us-west-2b"
          + "Terraform"       = "true"
          + "hashicorp-learn" = "module-use"
        }
      + vpc_id           = (known after apply)
    }

  # module.vpc.aws_route_table.public[0] 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            = (known after apply)
      + tags             = {
          + "Environment" = "dev"
          + "Name"        = "example-vpc-public"
          + "Terraform"   = "true"
        }
      + tags_all         = {
          + "Environment"     = "dev"
          + "Name"            = "example-vpc-public"
          + "Terraform"       = "true"
          + "hashicorp-learn" = "module-use"
        }
      + vpc_id           = (known after apply)
    }

  # module.vpc.aws_route_table_association.private[0] 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[1] 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.public[0] 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[1] 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_subnet.private[0] will be created
  + resource "aws_subnet" "private" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "us-west-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                                           = {
          + "Environment" = "dev"
          + "Name"        = "example-vpc-private-us-west-2a"
          + "Terraform"   = "true"
        }
      + tags_all                                       = {
          + "Environment"     = "dev"
          + "Name"            = "example-vpc-private-us-west-2a"
          + "Terraform"       = "true"
          + "hashicorp-learn" = "module-use"
        }
      + vpc_id                                         = (known after apply)
    }

  # module.vpc.aws_subnet.private[1] will be created
  + resource "aws_subnet" "private" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "us-west-2b"
      + 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                                           = {
          + "Environment" = "dev"
          + "Name"        = "example-vpc-private-us-west-2b"
          + "Terraform"   = "true"
        }
      + tags_all                                       = {
          + "Environment"     = "dev"
          + "Name"            = "example-vpc-private-us-west-2b"
          + "Terraform"       = "true"
          + "hashicorp-learn" = "module-use"
        }
      + vpc_id                                         = (known after apply)
    }

  # module.vpc.aws_subnet.public[0] will be created
  + resource "aws_subnet" "public" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "us-west-2a"
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "10.0.101.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                        = true
      + owner_id                                       = (known after apply)
      + private_dns_hostname_type_on_launch            = (known after apply)
      + tags                                           = {
          + "Environment" = "dev"
          + "Name"        = "example-vpc-public-us-west-2a"
          + "Terraform"   = "true"
        }
      + tags_all                                       = {
          + "Environment"     = "dev"
          + "Name"            = "example-vpc-public-us-west-2a"
          + "Terraform"       = "true"
          + "hashicorp-learn" = "module-use"
        }
      + vpc_id                                         = (known after apply)
    }

  # module.vpc.aws_subnet.public[1] will be created
  + resource "aws_subnet" "public" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "us-west-2b"
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "10.0.102.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                        = true
      + owner_id                                       = (known after apply)
      + private_dns_hostname_type_on_launch            = (known after apply)
      + tags                                           = {
          + "Environment" = "dev"
          + "Name"        = "example-vpc-public-us-west-2b"
          + "Terraform"   = "true"
        }
      + tags_all                                       = {
          + "Environment"     = "dev"
          + "Name"            = "example-vpc-public-us-west-2b"
          + "Terraform"       = "true"
          + "hashicorp-learn" = "module-use"
        }
      + vpc_id                                         = (known after apply)
    }

  # module.vpc.aws_vpc.this[0] will be created
  + resource "aws_vpc" "this" {
      + arn                                  = (known after apply)
      + assign_generated_ipv6_cidr_block     = false
      + 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                 = false
      + enable_dns_support                   = true
      + 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                                 = {
          + "Environment" = "dev"
          + "Name"        = "example-vpc"
          + "Terraform"   = "true"
        }
      + tags_all                             = {
          + "Environment"     = "dev"
          + "Name"            = "example-vpc"
          + "Terraform"       = "true"
          + "hashicorp-learn" = "module-use"
        }
    }

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

Changes to Outputs:
  + ec2_instance_public_ips = [
      + (known after apply),
      + (known after apply),
    ]
  + vpc_public_subnets      = [
      + (known after apply),
      + (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.

Wrap up

실습에서는 terraform registry의 module을 다운받아서 테스트를 해보았는데, 직접 moduled을 작성해서 stage, prod 환경에 따라 varible 값을 변경하여 적용할 수 도 있고, 팀원들과 공유하여 사용할 때는 module을 github과 같은 곳에 올려 공유할 수 도 있다.

profile
Shout out to Kubernetes⎈

0개의 댓글