cloudwithbass

[Terraform] 모듈화 연습하기1: VPC와 Subnet, 모듈화 본문

Terraform

[Terraform] 모듈화 연습하기1: VPC와 Subnet, 모듈화

여영클 2024. 8. 25. 14:22

목차

    이번 포스팅에선 모듈화 연습을 위해 간단한 데모를 만들어볼 것입니다.

    vpcsubnet을 이용합니다. 클릭 시 관련 테라폼 문서로 이동할 수 있습니다.

    혹시 포스팅에 잘못된 점이나 개선점이 있을 경우, 댓글로 알려주시면 정말 감사드리겠습니다.

    전체 코드는 다음 주소에서 확인 가능합니다.

    https://github.com/Dminus251/practice-terraform/tree/main/demo01-vpc_subnet


    resource 블록을 제외한 블록들입니다.

     

     

    1. vpc와 subnet 생성

    모듈화를 하기 전에, main.tf의 초기 코드를 보겠습니다.

    테라폼의 vpc, subnet 문서를 참조해서 main.tf에 다음 코드를 작성합니다.

    이 코드는 cidr이 10.0.0.0/16인 VPC와, 그 안에서 public subnet과 private subnet을 각각 하나씩 프로비저닝합니다.

    main.tf

    # main.tf
    resource "aws_vpc" "main" {
      cidr_block       = "10.0.0.0/16"
      instance_tenancy = "default"
    
      tags = {
        Name = "practice"
      }
    }
    
    resource "aws_subnet" "subnet-public-1" {
      vpc_id     = aws_vpc.main.id
      cidr_block = "10.0.1.0/24"
      availability_zone = "ap-northeast-2a"
      map_public_ip_on_launch = "true" #퍼블릭 ip 자동 할당 기능 활성화
      #이 subnet에서 생성되는 instance에는 자동으로 publci ip가 할당된다.
    
      tags = {
        Name = "practice-public-1"
      }
    }
    
    resource "aws_subnet" "subnet-private-1" {
      vpc_id     = aws_vpc.main.id
      cidr_block = "10.0.3.0/24"
      availability_zone = "ap-northeast-2a"
    
      tags = {
        Name = "practice-priavte-1"
      }
    }

     

     

    2. 모듈로 만들기

    다음 디렉터리 구조를 참고해서 modules 디렉터리와 그 하위 요소들을 생성합니다.

     

    이제 1번에서 main.tf에 작성한 vpc와 subnet 코드를 각각 modules/t-aws-vpc/main.tfmodules/t-aws-subnet/main.tf로 옮길 건데, 코드가 조금 바뀔 것입니다.

     

    먼저 t-aws-vpc/ 디렉터리입니다.

    modules/t-aws-vpc/main.tf

    # modules/t-aws-vpc/main.tf
    resource "aws_vpc" "main" {
      cidr_block       = "10.0.0.0/16"
      instance_tenancy = "default"
    
      tags = {
        Name = "practice"
      }
    }

     

    modules/t-aws-vpc/outputs.tf

    # modules/t-aws-vpc/outputs.tf
    output "vpc-id" {
      value = aws_vpc.main.id
    }

     

    • modules/t-aws-vpc/에는 outputs.tf 파일이 추가됐습니다.
    • output 블록을 이용하면 해당 내용을 사용자에게 보여주거나, 다른 모듈로 값을 전달할 수 있습니다.
    • 추후에 subnet은 vpc의 id가 필요하므로 이 값을 subnet 모듈에 전달할 것입니다.

     

    다음으로 t-aws-subnet 디렉터리를 확인해보겠습니다.

    modules/t-aws-subnet/main.tf

    # modules/t-aws-subnet/main.tf
    resource "aws_subnet" "subnet-public-1" {
      vpc_id     = var.vpc-id
      cidr_block = "10.0.1.0/24"
      availability_zone = "ap-northeast-2a"
      map_public_ip_on_launch = "true" #퍼블릭 ip 자동 할당 기능 활성화
      #이 subnet에서 생성되는 instance에는 자동으로 publci ip가 할당된다.
    
      tags = {
        Name = "practice-public-1"
      }
    }
    
    resource "aws_subnet" "subnet-private-1" {
      vpc_id     = var.vpc-id
      cidr_block = "10.0.3.0/24"
      availability_zone = "ap-northeast-2a"
    
      tags = {
        Name = "practice-priavte-1"
      }
    }

     

    modules/t-aws-subnet/vars.tf

    # modules/t-aws-subnet/vars.tf
    variable "vpc-id" {
      type = string
    }
    • 서브넷은 vpc 내에 생성되므로 aws_subnet 리소스는 vpc_id를 요구합니다.
    • 하지만 subnet 모듈 내에는 vpc 리소스가 없으므로 이곳에선 vpc의 id도 알 수가 없습니다.
    • 따라서 일단 변수를 사용한다고 정의만 해놓고(vpc_id = var.vpc-id), t-aws-vpc/ 디렉터리에서 작성한 output을 루트 모듈에서 사용할 것입니다.

     

    마지막으로 루트 디렉터리의 main.tf 내용입니다.

    main.tf

    module "vpc" {
      source = "./modules/t-aws-vpc"
    }
    
    module "subnet" {
      source = "./modules/t-aws-subnet"
      vpc-id = module.vpc.vpc-id
    }
    • source는 모듈의 위치를 나타냅니다.
    • subnet 모듈의 vpc-id는, subnet 모듈 내의 variable입니다.
    • 서브넷의 vpc_id에 vpc-id라는 변수를 할당했으니 이곳에서 그 값을 정의해야 합니다.
    • 이 때 그 값은 vpc 모듈의 output인 vpc-id를 사용합니다.

     

    3. variable 이용하기

    모듈화의 목적 중 하나는 코드 재사용성을 향상시키는 것입니다.

    현재는 cidr, az 등이 하드코딩되어 있으므로 코드를 재사용하기 힘듭니다.

     

    vpc 모듈부터 수정하겠습니다.

    modules/t-aws-vpc/main.tf

    #modules/t-aws-vpc/main.tf
    resource "aws_vpc" "main" {
      cidr_block       = var.vpc-cidr
      instance_tenancy = "default"
    
      tags = {
        Name = var.vpc-name
      }
    }

    다음과 같이 변수를 사용해 수정했습니다.

    • cidr_block: "10.0.0.0/16" → var.vpc-cidr
    • tags.Name: "practice" → var.vpc-name

     

    변수는 아래 처럼 vars.tf 파일에 정의합니다.

    modules/t-aws-vpc/vars.tf

    #modules/t-aws-vpc/vars.tf
    variable "vpc-cidr" {
      type = string
      default = "10.0.0.0/16"
    }
    
    variable "vpc-name" {
      type = string
      default = "practice"
    }

    이렇게 하면, 변경 사항이 있을 때 vars.tf만 변경하면 되므로 코드의 재사용성이 향상됐습니다.

     

    다음으로 subnet 모듈을 보겠습니다.

    modules/t-aws-subnet/vars.tf

    variable "subnets" {
      type = map(object({
        cidr_block            = string
        availability_zone     = string
        map_public_ip_on_launch = bool
      }))
      default = {
        "practice-public-1" = {
          cidr_block            = "10.0.1.0/24"
          availability_zone     = "ap-northeast-2a"
          map_public_ip_on_launch = true
        },
        "practice-private-1" = {
          cidr_block            = "10.0.3.0/24"
          availability_zone     = "ap-northeast-2a"
          map_public_ip_on_launch = false
        }
      }
    }

    subnets을 변수로 선언했습니다.

    subnets는 map(object) 타입이며, default 값으론 기존 main.tf의 값들이 들어가 있습니다.

     

    (참고) Object

    • object도 map처럼 '{'와  '}'를 사용합니다.
    • map은 map(string)이나 map(list)와 같이 key-value 쌍에서 value의 타입이 강제됩니다.
    • 하지만 object는 string, bool 등 여러 타입을 사용할 수 있습니다.
    • object는 주로 리소스의 attribute( cidr_block, availability_zone과 같은)를 나타내기 위한 데이터 구조이기 때문입니다.

    이제 이 map(object) 타입의 변수인 subnets를 사용하면 다음과 같이 main.tf를 간소화할 수 있습니다.

    modules/t-aws-subnet/main.tf

    #modules/t-aws-subnet/main.tf
    resource "aws_subnet" "subnets" {
      for_each = var.subnets
    
      vpc_id     = var.vpc-id
      cidr_block = each.value.cidr_block
      availability_zone = each.value.availability_zone
      map_public_ip_on_launch = each.value.map_public_ip_on_launch
    
      tags = {
        Name = each.key
      }
    }

     

    for_each는 반복문입니다.

    for_each = var.subnets이므로 var.subnets의 각 요소에 대해 반복합니다.

    ar.subnets은 길이가 2인 리스트이므로 두 번 반복해서 aws_subnet 리소스를 생성할 것입니다.


     

    참고 문서

    Terraform Map Variable - What it is & How to Use