본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 29. · 0 Views
HCL 문법과 기본 구조 완벽 가이드
Terraform의 핵심 언어인 HCL을 처음 배우는 초급 개발자를 위한 가이드입니다. 기본 문법부터 블록 구조, 데이터 타입, 주석, 포맷팅까지 실무에 필요한 모든 것을 다룹니다. 점프 투 자바 스타일로 쉽고 재미있게 배워보세요.
목차
1. HCL 기본 문법
신입 인프라 엔지니어 김클라우드 씨는 오늘 처음으로 Terraform 코드를 보게 되었습니다. "이게 뭐죠?
JSON 같기도 하고, 일반 프로그래밍 언어 같기도 하고..." 선배 이테라폼 씨가 웃으며 말했습니다. "HCL이라고, Terraform의 전용 언어예요."
**HCL(HashiCorp Configuration Language)**은 Terraform에서 인프라를 코드로 정의하는 선언적 언어입니다. JSON처럼 구조화되어 있지만 훨씬 읽기 쉽고, 일반 프로그래밍 언어처럼 표현력이 풍부합니다.
선언적이라는 것은 "어떻게"가 아닌 "무엇"을 만들지 설명한다는 뜻입니다.
다음 코드를 살펴봅시다.
# 가장 기본적인 HCL 문법
resource "aws_instance" "web_server" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "MyWebServer"
}
}
# 변수 선언
variable "region" {
default = "us-west-2"
}
김클라우드 씨는 입사 1주일 차 신입 인프라 엔지니어입니다. 지금까지 AWS 콘솔에서 클릭으로 서버를 만들어왔는데, 오늘 처음으로 Terraform 코드를 접하게 되었습니다.
화면에 보이는 코드는 낯설었습니다. JSON처럼 생겼지만 중괄호와 따옴표가 조금 다릅니다.
Python처럼 보이기도 하지만 함수 호출은 아닌 것 같습니다. 선배 이테라폼 씨가 옆자리에 앉으며 말했습니다.
"처음 보면 어려워 보이지만, 사실 아주 직관적이에요. 천천히 배워봅시다." HCL이란 무엇일까요? HCL은 마치 건축 설계도와 같습니다.
건축가가 설계도에 "방 3개, 욕실 2개, 주방 1개"라고 적으면, 실제로 어떻게 지을지는 시공사가 알아서 합니다. 마찬가지로 HCL에서는 "t2.micro 인스턴스 1개"라고 선언하면, Terraform이 알아서 AWS API를 호출해서 만들어줍니다.
우리는 무엇을 원하는지만 명확히 적으면 됩니다. 왜 HCL이 필요할까요? 예전에는 인프라를 만들려면 AWS 콘솔에 들어가서 클릭클릭클릭을 반복해야 했습니다.
서버 10대를 만든다면? 같은 작업을 10번 반복해야 했습니다.
실수라도 하면 다시 처음부터 시작해야 했습니다. 더 큰 문제는 재현성이었습니다.
3개월 전에 만든 서버를 똑같이 다시 만들어야 한다면? 어떤 설정을 선택했는지 기억이 나지 않습니다.
문서를 작성해둬도 설정은 계속 바뀌고, 문서는 금방 낡아버립니다. HCL이 모든 것을 바꿔놓았습니다 HCL로 인프라를 정의하면 코드가 곧 문서가 됩니다.
필요한 모든 설정이 코드에 명확히 적혀 있습니다. Git으로 버전 관리도 할 수 있고, 코드 리뷰도 할 수 있습니다.
무엇보다 반복 작업이 사라집니다. 코드 한 번 작성해두면, 같은 환경을 몇 번이든 똑같이 재현할 수 있습니다.
개발 환경, 스테이징 환경, 프로덕션 환경을 완전히 동일하게 만들 수 있습니다. 코드를 하나씩 뜯어봅시다 위 코드의 첫 줄을 보겠습니다.
resource "aws_instance" "web_server"라고 되어 있습니다. 여기서 resource는 무언가를 만들겠다는 선언입니다.
aws_instance는 AWS EC2 인스턴스를 의미합니다. web_server는 이 리소스에 붙일 이름입니다.
중괄호 안을 보면 구체적인 설정이 나옵니다. ami는 어떤 운영체제 이미지를 쓸지, instance_type은 서버 사양을 지정합니다.
tags는 리소스에 붙일 태그입니다. 마지막 부분의 variable은 변수 선언입니다.
코드에서 반복되는 값을 변수로 빼내면 관리가 훨씬 쉬워집니다. 실무에서는 어떻게 쓸까요? 실제 회사에서는 이런 식으로 사용합니다.
새로운 마이크로서비스를 배포해야 한다면, 기존 HCL 파일을 복사해서 서버 이름과 몇 가지 설정만 바꿉니다. 그리고 terraform apply 명령어 한 번이면 모든 인프라가 자동으로 만들어집니다.
대형 스타트업들은 수백 개의 HCL 파일로 전체 인프라를 관리합니다. 신입 엔지니어도 코드를 읽으면 현재 인프라 구조를 정확히 파악할 수 있습니다.
주의할 점이 있습니다 초보자들이 흔히 하는 실수는 모든 것을 하나의 파일에 몰아넣는 것입니다. HCL 파일도 프로그래밍 코드처럼 적절히 분리해야 합니다.
main.tf, variables.tf, outputs.tf처럼 역할별로 나누는 것이 좋습니다. 또 다른 실수는 하드코딩입니다.
환경마다 바뀌는 값은 반드시 변수로 빼내야 합니다. 그래야 개발/스테이징/프로덕션 환경을 같은 코드로 관리할 수 있습니다.
김클라우드 씨의 첫 코드 이테라폼 씨의 설명을 듣고 김클라우드 씨는 직접 HCL 코드를 작성해봤습니다. 처음에는 오타도 많이 나고 문법 오류도 났지만, 몇 번 고쳐보니 점점 익숙해졌습니다.
"생각보다 어렵지 않네요!" 김클라우드 씨가 말했습니다. "JSON보다 훨씬 읽기 쉬워요." HCL의 기본 문법만 익혀도 Terraform의 80%는 사용할 수 있습니다.
나머지는 실전에서 부딪히며 배우면 됩니다.
실전 팁
💡 - 파일 확장자는 .tf를 사용합니다. Terraform이 자동으로 인식합니다.
- 들여쓰기는 2칸 스페이스가 표준입니다. 일관성 있게 유지하세요.
- terraform fmt 명령어를 쓰면 자동으로 코드를 정렬해줍니다.
2. 블록과 인자 구조
김클라우드 씨가 HCL 코드를 작성하다가 막혔습니다. "이건 블록 안에 써야 하나요, 밖에 써야 하나요?" 이테라폼 씨가 코드를 보더니 말했습니다.
"HCL의 구조를 이해하면 자연스럽게 알 수 있어요."
HCL의 핵심은 블록(Block) 구조입니다. 블록은 중괄호로 둘러싸인 설정 묶음이고, 그 안에 **인자(Argument)**를 작성합니다.
마치 집(블록)을 짓고 그 안에 가구(인자)를 배치하는 것과 같습니다. 블록 안에 또 다른 블록을 넣을 수도 있습니다.
다음 코드를 살펴봅시다.
# 기본 블록 구조
resource "aws_security_group" "web_sg" {
name = "web-security-group"
description = "Security group for web servers"
# 중첩된 블록
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# 여러 개의 중첩 블록 가능
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
김클라우드 씨는 보안 그룹을 만들려고 코드를 작성하고 있었습니다. 그런데 어디에 뭘 써야 할지 헷갈렸습니다.
name은 블록 안에 쓰는 게 맞는 것 같은데, ingress는 뭔가 다른 것 같습니다. 중괄호가 또 나오는데, 이건 블록 안의 블록인가요?
이테라폼 씨가 화이트보드에 그림을 그리며 설명하기 시작했습니다. 블록이란 무엇일까요? 블록은 마치 서랍장과 같습니다.
큰 서랍장이 있고, 그 안에 여러 개의 작은 서랍이 들어있습니다. HCL에서 resource 블록은 큰 서랍장입니다.
그 안에 name, description 같은 인자들이 들어있습니다. 그리고 ingress, egress 같은 작은 서랍(중첩 블록)도 들어있습니다.
블록의 기본 구조 모든 블록은 블록 타입 + 레이블 + 중괄호 형태를 갖습니다. resource "aws_security_group" "web_sg"를 보면, resource가 블록 타입입니다.
뒤에 따라오는 "aws_security_group"과 "web_sg"는 레이블입니다. 레이블은 블록을 식별하는 이름표입니다.
블록 타입마다 필요한 레이블 개수가 다릅니다. resource는 2개, variable은 1개, locals는 0개입니다.
인자는 블록 안의 설정값입니다 블록 안에 들어가는 name = "web-security-group" 같은 것을 인자라고 부릅니다. 인자는 항상 키 = 값 형태입니다.
왼쪽의 name이 **키(key)**이고, 오른쪽의 "web-security-group"이 **값(value)**입니다. 등호 양쪽에 공백을 넣으면 가독성이 좋습니다.
인자는 각 블록마다 정해진 것들이 있습니다. AWS 공식 문서를 보면 어떤 인자를 쓸 수 있는지 나와 있습니다.
중첩 블록의 비밀 위 코드에서 ingress와 egress는 **중첩 블록(Nested Block)**입니다. 블록 안에 들어있는 또 다른 블록입니다.
보안 그룹에는 여러 개의 인바운드 규칙이 필요할 수 있습니다. 그래서 ingress 블록을 여러 번 쓸 수 있습니다.
이것이 바로 중첩 블록의 장점입니다. 중첩 블록은 레이블이 없습니다.
그냥 ingress { ... } 형태로 씁니다.
반복이 필요하면 같은 블록을 여러 번 작성하면 됩니다. 실무에서 자주 쓰는 블록들 실제 프로젝트에서는 여러 종류의 블록을 사용합니다.
resource 블록은 실제 인프라 리소스를 만듭니다. EC2, RDS, S3 등 모든 AWS 리소스가 여기 해당합니다.
variable 블록은 입력 변수를 정의합니다. 환경마다 바뀌는 값을 여기에 선언합니다.
output 블록은 출력 값을 정의합니다. 생성된 리소스의 정보를 다른 곳에서 참조할 때 씁니다.
data 블록은 기존 리소스 정보를 조회할 때 씁니다. 이미 만들어진 VPC 정보를 가져올 때 유용합니다.
블록 순서는 중요하지 않습니다 HCL은 선언적 언어이기 때문에 블록의 순서는 상관없습니다. resource를 먼저 쓰든 variable을 먼저 쓰든 결과는 같습니다.
Terraform이 알아서 의존성을 분석해서 올바른 순서로 실행합니다. 다만 가독성을 위해 보통 변수를 위쪽에, 리소스를 아래쪽에 배치합니다.
흔한 실수들 초보자들이 자주 하는 실수는 블록 타입을 잘못 쓰는 것입니다. resources처럼 복수형으로 쓰면 오류가 납니다.
정확히 resource여야 합니다. 또 다른 실수는 중괄호를 빼먹는 것입니다.
블록은 반드시 중괄호로 열고 닫아야 합니다. 하나라도 빠지면 문법 오류가 발생합니다.
김클라우드 씨의 깨달음 이테라폼 씨의 설명을 듣고 김클라우드 씨는 이해했습니다. "아, 큰 블록 안에 작은 블록이 들어가는 구조군요!" 이제 HCL 코드를 보면 구조가 한눈에 들어왔습니다.
어디가 블록이고 어디가 인자인지 명확해졌습니다. 블록과 인자의 차이만 제대로 알아도 HCL 코드를 훨씬 쉽게 읽고 쓸 수 있습니다.
실전 팁
💡 - 블록은 중괄호, 인자는 등호로 구분됩니다.
- 중첩 블록은 반복 가능합니다. 같은 블록을 여러 번 써도 됩니다.
- terraform validate 명령어로 문법 오류를 미리 체크할 수 있습니다.
3. 문자열과 숫자 타입
"왜 어떤 값은 따옴표로 감싸고, 어떤 값은 안 감싸나요?" 김클라우드 씨가 물었습니다. 코드를 보다 보니 "t2.micro"는 따옴표가 있는데 80은 따옴표가 없었습니다.
이테라폼 씨가 답했습니다. "데이터 타입이 다르기 때문이에요."
HCL에서 가장 기본이 되는 데이터 타입은 **문자열(String)**과 **숫자(Number)**입니다. 문자열은 따옴표로 감싸고, 숫자는 따옴표 없이 씁니다.
문자열 안에서 변수를 삽입하는 보간(Interpolation) 기능도 자주 사용합니다.
다음 코드를 살펴봅시다.
# 문자열과 숫자 타입 예제
variable "instance_count" {
type = number
default = 3
}
variable "project_name" {
type = string
default = "my-project"
}
resource "aws_instance" "app" {
count = var.instance_count
instance_type = "t2.micro"
# 문자열 보간 사용
tags = {
Name = "${var.project_name}-server-${count.index + 1}"
Port = "${80}" # 숫자를 문자열로 변환
}
}
김클라우드 씨는 보안 그룹 규칙을 작성하다가 혼란스러웠습니다. 포트 번호 80은 따옴표가 없는데, 프로토콜 "tcp"는 따옴표가 있었습니다.
"뭔가 규칙이 있을 것 같은데..." 김클라우드 씨가 중얼거렸습니다. 이테라폼 씨가 웃으며 화면을 가리켰습니다.
"맞아요. 데이터 타입이라는 규칙이 있어요." 데이터 타입이란 무엇일까요? 데이터 타입은 마치 물건을 담는 상자의 종류와 같습니다.
우유는 우유팩에, 쌀은 쌀포대에 담듯이, 데이터도 종류에 맞는 타입으로 표현해야 합니다. 문자열 타입은 글자를 담는 상자입니다.
"hello", "t2.micro", "us-west-2" 같은 값들이 여기 해당합니다. 반드시 큰따옴표로 감싸야 합니다.
숫자 타입은 숫자를 담는 상자입니다. 80, 443, 3 같은 값들입니다.
따옴표를 쓰지 않습니다. 문자열의 기본 문자열은 HCL에서 가장 많이 쓰는 타입입니다.
AWS 리전 이름, 인스턴스 타입, 태그 이름 등 대부분이 문자열입니다. 문자열은 항상 큰따옴표로 감싸야 합니다.
작은따옴표는 사용할 수 없습니다. 'hello'는 오류가 나고, "hello"가 정답입니다.
빈 문자열도 가능합니다. "" 이렇게 쓰면 됩니다.
가끔 기본값을 비워두고 싶을 때 유용합니다. 숫자의 기본 숫자 타입은 계산이나 카운트에 사용됩니다.
서버 개수, 포트 번호, 디스크 용량 등이 숫자로 표현됩니다. 정수도 되고 소수도 됩니다.
3도 되고 3.14도 됩니다. 음수도 가능합니다.
-1처럼 쓰면 됩니다. 숫자에 따옴표를 붙이면 안 됩니다.
"80"이라고 쓰면 숫자가 아니라 문자열이 됩니다. 계산에 사용할 수 없게 됩니다.
문자열 보간의 마법 HCL의 강력한 기능 중 하나가 **문자열 보간(String Interpolation)**입니다. 문자열 안에 변수나 표현식을 집어넣을 수 있습니다.
${var.project_name}처럼 쓰면, 실행 시점에 변수 값으로 바뀝니다. my-project라는 변수 값이 그 자리에 들어갑니다.
여러 개를 조합할 수도 있습니다. "${var.project_name}-server-${count.index + 1}"처럼 쓰면 "my-project-server-1" 같은 문자열이 만들어집니다.
타입 변환도 가능합니다 숫자를 문자열로 바꿔야 할 때가 있습니다. 태그는 모두 문자열이어야 하는데, 포트 번호는 숫자거든요.
이럴 때는 "${80}" 이렇게 쓰면 됩니다. 숫자 80이 문자열 "80"으로 자동 변환됩니다.
HCL이 알아서 처리해줍니다. 반대로 문자열을 숫자로 바꾸는 것도 가능합니다.
하지만 실무에서는 그런 경우가 드뭅니다. 실무에서 주의할 점 포트 번호는 보통 숫자로 씁니다.
from_port = 80 이렇게요. 하지만 가끔 문자열을 요구하는 속성도 있습니다.
API 문서를 잘 확인해야 합니다. 환경 변수에서 값을 가져올 때는 항상 문자열입니다.
숫자가 필요하면 명시적으로 변환해야 합니다. 많이 하는 실수들 초보자들이 자주 하는 실수는 숫자에 따옴표를 붙이는 것입니다.
count = "3" 이렇게 쓰면 오류가 납니다. count = 3이 맞습니다.
또 다른 실수는 문자열 보간을 잘못 쓰는 것입니다. {var.name} 이렇게 쓰면 안 되고, ${var.name} 처럼 달러 기호가 필요합니다.
간단한 것부터 시작하세요 김클라우드 씨는 실습을 해봤습니다. 문자열 변수를 만들고, 숫자 변수를 만들고, 보간을 써보고...
처음에는 따옴표를 빼먹기도 하고 달러 기호를 잊어버리기도 했습니다. 하지만 몇 번 반복하니 손에 익었습니다.
"생각보다 단순하네요!" 김클라우드 씨가 말했습니다. 맞습니다.
문자열과 숫자만 제대로 이해해도 HCL 코드의 70%는 읽을 수 있습니다.
실전 팁
💡 - 문자열은 큰따옴표, 숫자는 따옴표 없이 작성합니다.
- 변수 삽입은 ${} 문법을 사용합니다.
- 타입이 헷갈리면 공식 문서를 확인하세요. 각 속성마다 요구하는 타입이 나와 있습니다.
4. 리스트와 맵 사용법
김클라우드 씨가 여러 개의 서버를 만들려다가 막혔습니다. "서버마다 설정을 일일이 써야 하나요?" 이테라폼 씨가 답했습니다.
"리스트와 맵을 쓰면 훨씬 간단해져요."
**리스트(List)**는 순서가 있는 값들의 모음이고, **맵(Map)**은 키-값 쌍의 모음입니다. 리스트는 대괄호 []로, 맵은 중괄호 {}로 표현합니다.
여러 개의 비슷한 설정을 다룰 때 필수적입니다.
다음 코드를 살펴봅시다.
# 리스트 사용 예제
variable "availability_zones" {
type = list(string)
default = ["us-west-2a", "us-west-2b", "us-west-2c"]
}
# 맵 사용 예제
variable "instance_tags" {
type = map(string)
default = {
Environment = "production"
Team = "backend"
Project = "api-server"
}
}
resource "aws_subnet" "public" {
count = length(var.availability_zones)
availability_zone = var.availability_zones[count.index]
tags = merge(
var.instance_tags,
{
Name = "public-subnet-${count.index + 1}"
}
)
}
김클라우드 씨는 3개의 가용영역에 서브넷을 만들어야 했습니다. us-west-2a, us-west-2b, us-west-2c에 각각 하나씩요.
"이걸 어떻게 깔끔하게 표현하지?" 김클라우드 씨가 고민했습니다. 같은 코드를 3번 복사 붙여넣기 하는 건 너무 지저분해 보였습니다.
이테라폼 씨가 리스트와 맵을 소개했습니다. 리스트란 무엇일까요? 리스트는 마치 쇼핑 목록과 같습니다.
"사과, 바나나, 오렌지" 이렇게 순서대로 나열된 목록입니다. HCL에서는 대괄호로 표현합니다.
["apple", "banana", "orange"] 이런 식으로요. 쉼표로 각 항목을 구분합니다.
리스트 안의 모든 값은 같은 타입이어야 합니다. 문자열 리스트면 모두 문자열, 숫자 리스트면 모두 숫자여야 합니다.
리스트 인덱스 사용하기 리스트의 각 항목은 인덱스로 접근할 수 있습니다. 첫 번째 항목은 0번, 두 번째는 1번, 세 번째는 2번입니다.
var.availability_zones[0]이라고 쓰면 첫 번째 가용영역인 "us-west-2a"를 가져옵니다. var.availability_zones[1]은 두 번째인 "us-west-2b"입니다.
length() 함수를 쓰면 리스트의 길이를 알 수 있습니다. length(var.availability_zones)는 3을 반환합니다.
맵이란 무엇일까요? 맵은 마치 전화번호부와 같습니다. 이름(키)으로 전화번호(값)를 찾듯이, 키로 값을 찾습니다.
HCL에서는 중괄호로 표현합니다. { Environment = "production", Team = "backend" } 이런 식입니다.
키는 항상 문자열이지만, 값은 어떤 타입이든 가능합니다. 문자열, 숫자, 심지어 리스트나 다른 맵도 됩니다.
맵 키로 값 꺼내기 맵에서 값을 가져올 때는 점 표기법이나 대괄호 표기법을 씁니다. var.instance_tags.Environment라고 쓰면 "production"을 가져옵니다.
var.instance_tags["Team"]이라고 써도 됩니다. 키에 특수문자나 공백이 있으면 대괄호 표기법만 사용할 수 있습니다.
var.tags["Project Name"] 이런 식으로요. 실무에서 리스트와 맵 활용하기 리스트는 반복 작업에 강력합니다.
count 또는 for_each와 함께 쓰면 같은 리소스를 여러 개 만들 수 있습니다. 위 코드에서 count = length(var.availability_zones)는 가용영역 개수만큼 서브넷을 만듭니다.
3개의 서브넷이 자동으로 생성됩니다. 맵은 공통 설정을 관리할 때 유용합니다.
모든 리소스에 붙일 태그를 맵으로 정의해두면, tags = var.instance_tags 한 줄로 적용할 수 있습니다. 맵 병합하기 merge() 함수를 쓰면 여러 맵을 합칠 수 있습니다.
공통 태그에 리소스별 태그를 추가할 때 유용합니다. merge(var.instance_tags, { Name = "subnet-1" })처럼 쓰면, 기존 태그들과 Name 태그가 합쳐진 새로운 맵이 만들어집니다.
빈 리스트와 빈 맵 빈 리스트는 []로, 빈 맵은 {}로 표현합니다. 기본값을 비워두고 싶을 때 사용합니다.
하지만 타입은 명시해야 합니다. type = list(string) 또는 type = map(string) 처럼요.
흔한 실수들 초보자들이 자주 하는 실수는 리스트 인덱스를 1부터 시작하는 것입니다. 프로그래밍에서는 0부터 시작한다는 것을 잊지 마세요.
또 다른 실수는 쉼표를 빼먹는 것입니다. 리스트나 맵에서 각 항목은 반드시 쉼표로 구분해야 합니다.
마지막 항목 뒤에는 쉼표가 있어도 되고 없어도 됩니다. 김클라우드 씨의 성공 이테라폼 씨의 도움으로 김클라우드 씨는 3줄짜리 변수 선언으로 3개의 서브넷을 만들었습니다.
"와, 이거 정말 강력한데요!" 김클라우드 씨가 감탄했습니다. "10개를 만들어도 코드는 똑같겠어요." 맞습니다.
리스트와 맵을 제대로 활용하면 코드 중복을 크게 줄일 수 있습니다.
실전 팁
💡 - 리스트 인덱스는 0부터 시작합니다.
- 맵의 키는 반드시 문자열이어야 합니다.
- length(), merge(), keys(), values() 같은 내장 함수를 활용하세요.
5. 주석 작성하기
김클라우드 씨가 3개월 전에 작성한 코드를 다시 봤습니다. "이게 뭐였더라?" 코드의 의도가 기억나지 않았습니다.
이테라폼 씨가 말했습니다. "주석을 달아뒀으면 이런 일이 없었을 텐데요."
**주석(Comment)**은 코드에 설명을 추가하는 방법입니다. HCL에서는 한 줄 주석 //와 #, 그리고 여러 줄 주석 /* */을 지원합니다.
주석은 실행되지 않고 사람이 읽기 위한 용도입니다.
다음 코드를 살펴봅시다.
# 이것은 한 줄 주석입니다
// 이것도 한 줄 주석입니다 (둘 다 사용 가능)
/*
이것은 여러 줄 주석입니다.
여러 줄에 걸쳐 설명을 작성할 수 있습니다.
코드 블록을 임시로 비활성화할 때도 유용합니다.
*/
variable "region" {
type = string
default = "us-west-2"
# 회사 정책: 모든 리소스는 us-west-2에 생성
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0" # Ubuntu 20.04 LTS
instance_type = "t2.micro"
// TODO: 프로덕션 배포 전에 t3.medium으로 변경 필요
tags = {
Name = "WebServer"
}
}
김클라우드 씨는 급하게 코드를 작성했습니다. 마감이 코앞이었거든요.
주석 같은 건 나중에 달면 되지, 지금은 일단 동작만 하면 된다고 생각했습니다. 3개월이 지났습니다.
같은 코드를 수정해야 하는 상황이 왔습니다. 그런데 코드를 보니 아무것도 기억나지 않았습니다.
"왜 여기에 이 설정을 넣었지? 이 값은 무슨 의미지?" 김클라우드 씨는 예전의 자신을 원망했습니다.
주석이란 무엇일까요? 주석은 마치 요리 레시피의 메모와 같습니다. "이 단계에서 불을 약하게 줄여야 타지 않아요" 같은 팁을 적어두는 것이죠.
코드에서도 마찬가지입니다. "왜 이렇게 작성했는지", "나중에 뭘 해야 하는지" 같은 정보를 주석으로 남겨둡니다.
Terraform은 주석을 완전히 무시합니다. 실행에 아무 영향을 주지 않습니다.
오직 사람이 읽기 위한 것입니다. 한 줄 주석 두 가지 HCL에서는 한 줄 주석을 두 가지 방식으로 쓸 수 있습니다.
#으로 시작하는 방식이 있습니다. Unix/Linux 셸 스크립트와 같은 스타일입니다.
# 이것은 주석입니다 이렇게 씁니다. //로 시작하는 방식도 있습니다.
C언어나 JavaScript와 같은 스타일입니다. // 이것도 주석입니다 이렇게 씁니다.
둘 다 똑같이 동작합니다. 팀에서 하나를 정해서 일관되게 쓰는 게 좋습니다.
많은 팀들이 #을 선호합니다. 여러 줄 주석 긴 설명이 필요할 때는 여러 줄 주석을 씁니다.
/*로 시작해서 */로 끝냅니다. 그 사이에 있는 모든 내용이 주석으로 처리됩니다.
줄 바꿈도 자유롭게 할 수 있습니다. 코드 블록을 임시로 비활성화할 때도 유용합니다.
삭제하기는 아까운데 일단 실행은 하고 싶지 않을 때, 여러 줄 주석으로 감싸면 됩니다. 좋은 주석 작성법 좋은 주석은 **왜(Why)**를 설명합니다.
무엇을(What) 하는지는 코드를 보면 알 수 있지만, 왜 그렇게 했는지는 주석이 없으면 모릅니다. # Ubuntu 20.04 LTS 같은 주석은 유용합니다.
AMI ID만 봐서는 어떤 OS인지 알 수 없거든요. # 회사 정책: 모든 리소스는 us-west-2에 생성 같은 주석도 좋습니다.
정책적인 이유를 명확히 알 수 있습니다. TODO 주석의 힘 // TODO: 주석은 나중에 할 일을 표시합니다.
지금은 시간이 없지만 나중에 꼭 해야 할 작업을 적어둡니다. 많은 IDE가 TODO 주석을 특별히 표시해줍니다.
목록으로 모아서 보여주기도 합니다. 놓치지 않고 처리할 수 있습니다.
// FIXME:, // HACK:, // NOTE: 같은 변형도 있습니다. 팀마다 규칙을 정해서 씁니다.
실무에서 주석 활용하기 복잡한 계산이나 특이한 설정에는 주석을 달아두는 게 좋습니다. 6개월 뒤의 나도, 새로 합류한 동료도 이해할 수 있게 만듭니다.
하지만 모든 줄에 주석을 달 필요는 없습니다. 자명한 코드에는 주석이 불필요합니다.
instance_type = "t2.micro" 같은 건 설명이 필요 없습니다. 피해야 할 주석 잘못된 주석은 없는 것보다 나쁩니다.
코드는 바뀌었는데 주석을 업데이트하지 않으면, 주석이 거짓말을 하게 됩니다. 명백한 내용을 반복하는 주석도 불필요합니다.
# 이름을 설정합니다 같은 주석은 의미가 없습니다. 김클라우드 씨의 다짐 이제 김클라우드 씨는 코드를 작성할 때마다 주석을 답니다.
특히 복잡한 부분이나 나중에 수정해야 할 부분에는 꼭 주석을 남깁니다. 3개월 뒤에 코드를 다시 봤을 때, 주석 덕분에 금방 이해할 수 있었습니다.
"역시 주석을 달아둬서 다행이야!" 좋은 주석은 미래의 자신과 팀원들에게 주는 선물입니다.
실전 팁
💡 - #과 //는 같은 기능입니다. 팀 컨벤션에 맞춰 하나를 선택하세요.
- "왜"를 설명하는 주석이 좋은 주석입니다.
- 코드가 바뀌면 주석도 업데이트하세요. 거짓말하는 주석은 독입니다.
6. 코드 포맷팅 규칙
김클라우드 씨와 동료 박인프라 씨가 같은 프로젝트에서 작업했습니다. 둘의 코드를 합쳤더니 들여쓰기가 엉망이었습니다.
어떤 줄은 스페이스 2칸, 어떤 줄은 4칸, 어떤 줄은 탭이었습니다. 이테라폼 씨가 한숨을 쉬며 말했습니다.
"포맷팅 규칙을 지켰어야죠."
코드 포맷팅은 코드의 시각적 구조를 일관되게 만드는 규칙입니다. HCL의 표준은 2칸 스페이스 들여쓰기, 등호 정렬, 줄 끝 공백 제거 등입니다.
terraform fmt 명령어가 자동으로 포맷팅해줍니다.
다음 코드를 살펴봅시다.
# 잘못된 포맷팅
resource "aws_instance" "bad" {
ami="ami-123456"
instance_type = "t2.micro"
tags={
Name="BadFormat"
}
}
# 올바른 포맷팅 (terraform fmt 적용 후)
resource "aws_instance" "good" {
ami = "ami-123456"
instance_type = "t2.micro"
tags = {
Name = "GoodFormat"
}
}
# 복잡한 중첩 블록도 깔끔하게
resource "aws_security_group" "example" {
name = "example-sg"
description = "Example security group"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
김클라우드 씨는 빠르게 코드를 작성했습니다. 들여쓰기?
신경 쓸 겨를이 없었습니다. 일단 동작만 하면 됐으니까요.
박인프라 씨도 마찬가지였습니다. 자기 스타일대로 코드를 작성했습니다.
자신의 편집기 설정에 맞춰서요. 둘의 코드를 Git에 합쳤더니 끔찍한 일이 벌어졌습니다.
diff가 엉망이었습니다. 실제로 바뀐 게 뭔지 알 수가 없었습니다.
포맷팅이란 무엇일까요? 포맷팅은 마치 책의 편집과 같습니다. 내용은 같지만, 문단 나누기, 줄 간격, 여백 등을 일관되게 만들어 가독성을 높입니다.
코드도 마찬가지입니다. 로직은 같지만, 들여쓰기와 정렬을 일관되게 만들면 훨씬 읽기 쉬워집니다.
특히 여러 사람이 협업할 때는 포맷팅 규칙이 필수입니다. 모두가 같은 규칙을 따라야 코드 리뷰가 수월해집니다.
HCL의 표준 포맷팅 HCL의 공식 스타일 가이드는 명확합니다. 들여쓰기는 2칸 스페이스를 씁니다.
탭이 아니라 스페이스입니다. 4칸도 아니고 정확히 2칸입니다.
블록이 중첩될 때마다 2칸씩 더 들여씁니다. resource 블록 안의 내용은 2칸, 그 안의 tags 블록 내용은 4칸 들여씁니다.
등호 정렬의 마법 같은 블록 안에서 여러 인자를 작성할 때는 등호를 정렬합니다. ami = "..." 와 instance_type = "..."를 보세요.
등호의 위치가 세로로 일직선입니다. 가장 긴 키에 맞춰 정렬되어 있습니다.
이렇게 하면 값들이 세로로 정렬되어 한눈에 쏙 들어옵니다. 차이점을 빠르게 찾을 수 있습니다.
빈 줄 활용하기 논리적으로 구분되는 부분 사이에는 빈 줄을 넣습니다. 리소스와 리소스 사이, 블록과 블록 사이에 빈 줄을 넣으면 코드가 숨을 쉽니다.
뭉쳐있으면 답답하지만, 적절한 공백은 가독성을 높입니다. 하지만 너무 많은 빈 줄은 오히려 방해가 됩니다.
보통 한 줄 정도가 적당합니다. 줄 끝 공백 제거 줄의 끝에 불필요한 공백이 있으면 안 됩니다.
눈에는 보이지 않지만 Git diff에서는 변경으로 표시됩니다. 많은 편집기가 저장할 때 자동으로 줄 끝 공백을 제거하는 옵션을 제공합니다.
켜두는 게 좋습니다. terraform fmt의 마법 다행히도 모든 걸 수동으로 할 필요는 없습니다.
terraform fmt 명령어가 자동으로 포맷팅해줍니다. 프로젝트 디렉토리에서 terraform fmt를 실행하면, 모든 .tf 파일을 HCL 표준에 맞춰 자동으로 정리합니다.
들여쓰기, 등호 정렬, 빈 줄, 모든 것을 완벽하게 처리합니다. 논쟁의 여지가 없습니다.
Terraform이 정한 표준을 그대로 따릅니다. 실무 워크플로우 많은 팀들이 Git commit 전에 terraform fmt를 실행하는 규칙을 갖고 있습니다.
pre-commit hook으로 자동화하기도 합니다. CI/CD 파이프라인에서 terraform fmt -check를 돌려서, 포맷팅이 안 된 코드는 아예 머지를 막기도 합니다.
이렇게 하면 코드베이스의 일관성이 자동으로 유지됩니다. 사람이 신경 쓸 필요가 없습니다.
편집기 설정 팁 VSCode, IntelliJ 같은 편집기는 파일 저장 시 자동 포맷팅 기능을 제공합니다. Terraform 플러그인을 설치하고, "Format on Save" 옵션을 켜두면 됩니다.
저장할 때마다 자동으로 terraform fmt가 실행됩니다. 한 번 설정해두면 영원히 신경 쓸 일이 없어집니다.
팀 컨벤션 포맷팅은 팀 전체가 같은 규칙을 따라야 의미가 있습니다. .editorconfig 파일을 프로젝트에 추가해서 들여쓰기 규칙을 명시할 수 있습니다.
팀원 모두가 같은 설정을 자동으로 따르게 됩니다. README에 "커밋 전에 terraform fmt를 실행하세요"라고 적어두는 것도 좋습니다.
김클라우드 씨의 깨달음 이테라폼 씨가 terraform fmt를 실행했습니다. 엉망이던 코드가 순식간에 깔끔하게 정리되었습니다.
"와, 이거 정말 편하네요!" 김클라우드 씨가 감탄했습니다. "이제부터 커밋 전에 꼭 실행할게요." 박인프라 씨도 고개를 끄덕였습니다.
"저도요. 이렇게 간단한 걸 왜 진작 안 했을까요?" 포맷팅은 코드 품질의 기본입니다.
어렵지 않으니 꼭 습관화하세요.
실전 팁
💡 - terraform fmt를 습관화하세요. 커밋 전에 꼭 실행하세요.
- 편집기의 자동 포맷팅 기능을 활용하세요. 저장 시 자동 정리가 최고입니다.
- CI/CD에 포맷 체크를 추가하면 강제할 수 있습니다.
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Terraform 프로바이더와 리소스 완벽 가이드
Terraform의 핵심인 프로바이더와 리소스 개념을 실무 중심으로 설명합니다. AWS 프로바이더 설정부터 리소스 정의, 의존성 관리, 멀티 프로바이더 구성까지 초급 개발자도 쉽게 이해할 수 있도록 스토리텔링 방식으로 풀어냈습니다.
Ansible 인벤토리 관리 완벽 가이드
서버 수백 대를 관리하는 당신, 매번 IP 주소 외우고 계신가요? Ansible 인벤토리로 서버 관리를 체계화하는 방법을 알아봅니다. 정적 인벤토리부터 동적 인벤토리까지, 실무에서 바로 활용할 수 있는 베스트 프랙티스를 담았습니다.
Terraform 소개 및 설치 완벽 가이드
인프라를 코드로 관리하는 IaC의 개념부터 Terraform의 특징, 설치 방법, 그리고 첫 번째 리소스 생성까지 초급 개발자를 위한 친절한 입문 가이드입니다. 실무에서 바로 활용할 수 있는 예제와 팁을 담았습니다.
Ansible 소개 및 설치 완벽 가이드
서버 수십 대를 손쉽게 관리하는 자동화 도구 Ansible의 기초부터 설치, 첫 명령어 실행까지 배웁니다. 초급 개발자를 위한 실무 중심 입문 가이드입니다.
GitHub와 Vercel로 시작하는 배포 완벽 가이드
코드를 작성했다면 이제 세상에 공개할 차례입니다. GitHub에 코드를 올리고 Vercel로 배포하는 전체 과정을 실무 상황 스토리로 풀어냅니다. 초급 개발자도 따라하면서 자연스럽게 배포 프로세스를 이해할 수 있습니다.