흰 스타렉스에서 내가 내리지

Terraform Functions - 테라폼에서 사용하는 함수 본문

DevOps

Terraform Functions - 테라폼에서 사용하는 함수

주씨. 2024. 9. 20. 14:38
728x90

# 개요

Terraform 은 다양한 함수를 내장하고 있다. 

사용자는 이 함수를 이용하여 리소스를 보다 효율적으로 생성할 수 있고, 간략하게 코드를 만들 수 있다. 

* 현재는 built-in 함수만 지원하고 있다. 사용자가 임의로 함수를 만드는 건 지원하지 않고 있다.

 

 

# Functions

  • Numeric functions
  • String functions - ⭐️
  • Collection functions - ⭐️
  • Encoding functions
  • Filesystem functions
  • Date and Time functions
  • Hash and Crypto functions
  • IP Network functions
  • Type Conversion Functions

https://developer.hashicorp.com/terraform/language/functions

 

 

# 예시 코드

https://github.com/DevopsArtFactory/aws-provisioning

 

현업에서 직접 사용하는 코드를 오픈 소스처럼 공개한 레포지토리이다. 

아래의 vpc.tf 파일은 vpc 를 이루는 구성요소를 생성하는 코드이다. 

 

기본적으로 모든 리소스가 가지고 있는 count 파라미터를 이용하여 반복되는 리소스를 간단하게 생성할 수 있다

count 에 부여한 숫자만큼, 리소스는 반복되어 생성되고 자동으로 테라폼 내에서 resource_name[0] 처럼 리스트화된다. 

 

# VPC
# Whole network cidr will be 10.0.0.0/8 
# A VPC cidr will use the B class with 10.xxx.0.0/16
# You should set cidr advertently because if the number of VPC get larger then the ip range could be in shortage.
resource "aws_vpc" "default" {
  cidr_block           = "10.${var.cidr_numeral}.0.0/16" # Please set this according to your company size
  enable_dns_hostnames = true

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

# Internet Gateway
resource "aws_internet_gateway" "default" {
  vpc_id = aws_vpc.default.id

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


## NAT Gateway 
resource "aws_nat_gateway" "nat" {
  # Count means how many you want to create the same resource
  # This will be generated with array format
  # For example, if the number of availability zone is three, then nat[0], nat[1], nat[2] will be created.
  # If you want to create each resource with independent name, then you have to copy the same code and modify some code
  count = length(var.availability_zones)

  # element is used for select the resource from the array 
  # Usage = element (array, index) => equals array[index]
  allocation_id = element(aws_eip.nat.*.id, count.index)
  
  #Subnet Setting
  # nat[0] will be attached to subnet[0]. Same to all index.
  subnet_id = element(aws_subnet.public.*.id, count.index)

  lifecycle {
    create_before_destroy = true
  }

  tags = {
    Name = "NAT-GW${count.index}-${var.vpc_name}"
  }

}

# Elastic IP for NAT Gateway 
resource "aws_eip" "nat" {
  # Count value should be same with that of aws_nat_gateway because all nat will get elastic ip
  count = length(var.availability_zones)
  vpc   = true

  lifecycle {
    create_before_destroy = true
  }
}



#### PUBLIC SUBNETS
# Subnet will use cidr with /20 -> The number of available IP is 4,096  (Including reserved ip from AWS)
resource "aws_subnet" "public" {
  count  = length(var.availability_zones)
  vpc_id = aws_vpc.default.id

  cidr_block              = "10.${var.cidr_numeral}.${var.cidr_numeral_public[count.index]}.0/20"
  availability_zone       = element(var.availability_zones, count.index)

  # Public IP will be assigned automatically when the instance is launch in the public subnet
  map_public_ip_on_launch = true

  tags = {
    Name = "public${count.index}-${var.vpc_name}"
  }
}

# Route Table for public subnets
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.default.id

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


# Route Table Association for public subnets
resource "aws_route_table_association" "public" {
  count          = length(var.availability_zones)
  subnet_id      = element(aws_subnet.public.*.id, count.index)
  route_table_id = aws_route_table.public.id
}




#### PRIVATE SUBNETS
# Subnet will use cidr with /20 -> The number of available IP is 4,096  (Including reserved ip from AWS)
resource "aws_subnet" "private" {
  count  = length(var.availability_zones)
  vpc_id = aws_vpc.default.id

  cidr_block        = "10.${var.cidr_numeral}.${var.cidr_numeral_private[count.index]}.0/20"
  availability_zone = element(var.availability_zones, count.index)

  tags = {
    Name               = "private${count.index}-${var.vpc_name}"
    Network            = "Private"
  }
}

# Route Table for private subnets
resource "aws_route_table" "private" {
  count  = length(var.availability_zones)
  vpc_id = aws_vpc.default.id

  tags = {
    Name    = "private${count.index}rt-${var.vpc_name}"
    Network = "Private"
  }
}

# Route Table Association for private subnets
resource "aws_route_table_association" "private" {
  count          = length(var.availability_zones)
  subnet_id      = element(aws_subnet.private.*.id, count.index)
  route_table_id = element(aws_route_table.private.*.id, count.index)
}


# DB PRIVATE SUBNETS
# This subnet is only for the database. 
# For security, it is better to assign ip range for database only. This subnet will not use NAT Gateway
# This is also going to use /20 cidr, which might be too many IPs... Please count it carefully and change the cidr.
resource "aws_subnet" "private_db" {
  count  = length(var.availability_zones)
  vpc_id = aws_vpc.default.id

  cidr_block        = "10.${var.cidr_numeral}.${var.cidr_numeral_private_db[count.index]}.0/20"
  availability_zone = element(var.availability_zones, count.index)

  tags = {
    Name               = "db-private${count.index}-${var.vpc_name}"
    Network            = "Private"
  }
}

# Route Table for DB subnets
resource "aws_route_table" "private_db" {
  count  = length(var.availability_zones)
  vpc_id = aws_vpc.default.id

  tags = {
    Name    = "privatedb${count.index}rt-${var.vpc_name}"
    Network = "Private"
  }
}

# Route Table Association for DB subnets
resource "aws_route_table_association" "private_db" {
  count          = length(var.availability_zones)
  subnet_id      = element(aws_subnet.private_db.*.id, count.index)
  route_table_id = element(aws_route_table.private_db.*.id, count.index)
}

 

 

NAT Gateway 부분을 보면 된다. 

count 개수만큼 리소스가 생성이 될 것이다. 

주석을 잘 읽어보자.

 

count 를 사용하지 않았다면 코드가 정말 길어졌을텐데, 함수를 사용함으로써 코드가 더 간략해지고 가독성이 좋아진다. 


# 실습

git clone https://github.com/DevopsArtFactory/aws-provisioning.git

 

cd ./aws-provisioning/terraform/vpc/devartd_apnortheast2

 

먼저, terraform 의 version 이 있는데, 로컬에 깔린 terraform 의 버전과 backend.tf 에 명시된 버전이 일치하는지 확인하고 일치시켜준다. 

 

--미완

outputs.tf 에

output "first_public_subnet" {
  description = "first public subent"
  value = element(aws_subnet.public.*.id, 0)
}

 이렇게 사용할 수 있겠다.