Terraform 기초 실습 스터디를 진행하고 있으며, 커리큘럼 2주차에 해당하는 내용입니다.
* [테라폼으로 시작하는 IaC] 도서 참조
이전 포스팅에서 1주차 커리큘럼 범위인 리소스에 대한 개념까지 공부하였다.
2주차 학습범위에 대해 개념공부와 실습을 통해 익혀보도록 하자.
데이터 소스
데이터 소스는 테라폼으로 정의되지 않은 외부 리소스 또는 저장된 정보를 테라폼 내에서 참조할 때 사용한다.
(이 설명으로는 개념이 와닿지 않는다. 실습 예시를 통해 상세히 알아보도록 하자.)
데이터 소스 1. 데이터 소스 구성
데이터 소스 블록은 data 로 시작한다. 이후 '데이터 소스 유형'을 정의한다.
Resource 블록 정의와 유사하다.
- 데이터 소스 유형은 _ 를 기준으로 앞은 프로바이더 이름, 뒤는 프로바이더에서 제공하는 리소스 유형을 의미한다.
- 데이터 소스 유형을 선언한 뒤에는 고유한 이름을 붙인다. 리소스의 이름과 마찬가지로 이름은 동일한 유형에 대해 식별자 역할을 하므로 중복될 수 없다.
- 이름 뒤에 데이터 소스 유형에 대한 구성 인수들은 중괄호 {} 안에 선언한다. 인수가 필요하지 않은 유형도 있지만, 중괄호 {} 는 입력한다.
data "local_file" "abc" {
filename = "${path.module}/abc.txt"
}
데이터 소스를 정의할 때 사용 가능한 메타인수는 다음과 같다. (리소스 블록과 유사하다.)
- depends_on
- count
- for_each
- provider
- lifecycle
데이터 소스 2. 데이터 소스 속성 참조
데이터 소스로 읽은 대상을 참조하는 방식은 리소스와 구별되게 data 가 앞에 붙는다.
속성(Attributes) 값은 다음과 같이 접근할 수 있다.
# Terraform Code 로 사용자가 선언
data "<리소스 유형>" "<이름>" {
<인수> = <값>
}
# 데이터 소스 참조를 위해 리소스 생성 이후 획득한 속성(Attributes) 을 사용
data.<리소스 유형>.<이름>.<속성>
예로, 다음은 AWS 프로바이더의 가용영역을 작업자가 코드로 수동 선언하지 않고 프로바이더로 접근한 환경에서 제공되는 데이터 소스를 활용해 subnet 의 가용영역 인수를 정의하는 예이다.
데이터 소스를 활용해 AWS 프로바이더에 구성된 리전 내에서 사용가능한 가용영역 목록을 읽을 수 있다.
# 데이터 소스 선언
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_subnet" "primary" {
availability_zone = data.aws_availability_zones.available.names[0]
# ap-northeast-2a
}
resource "aws_subnet" "secondary" {
availability_zone = data.aws_availability_zones.available.names[1]
# ap-northeast-2b
}
데이터 소스 동작 확인을 위해 main.tf 를 다음과 같이 작성하여 확인해보자.
데이터 소스의 속성을 참조하여 생성된 local_file.def 로 생성된 리소스의 def.txt 파일 내용이, 리소스 블록으로 생성된 abc.txt 의 내용과 동일한지 확인한다.
abc.txt 파일, def.txt 파일의 결과가 동일한 것을 확인할 수 있다.
데이터 소스 data.local_file.abc 는 리소스 local_file.abc. 의 filename 을 참조해 데이터 소스를 생성한다.
데이터 소스 local_file 은 filename 으로 읽어온 파일의 내용을 content 속성으로 참조할 수 있으므로, 리소스 local_file.def 에서는 data.local_file.abc.content 로 읽혀진 데이터(123!)를 참조한다.
입력 변수(variable)
입력 변수는 인프라를 구성하는데 필요한 속성 값을 정의해 코드의 변경 없이 여러 인프라를 생성하는 데 목적이 있다.
테라폼에서는 이것을 입력 변수(Input Variables) 로 정의한다.
여기서 입력이라는 수식어가 붙는 이유는, 일반적인 개발 코드에서의 변수 선언 방식과 달리 테라폼은 plan 수행 시 값을 입력한다는 점이다.
(이 설명으로는 plan 수행 시 변수 값을 입력한다는 말이 와닿지 않는다. 상세히 알아보자.)
입력 변수(variable) 1. 변수 선언 방식
변수는 variable 로 시작되는 블록으로 구성된다. 변수 블록 뒤의 이름 값은 동일 모듈 내 모든 변수 선언에서 고유해야하며, 이 이름으로 다른 코드 내에서 참조된다.
variable "<이름>" {
<인수> = <값>
}
variable "image_id" {
type = string
}
테라폼 코드 구성에 미리 예약되어 있어, 변수 이름으로 사용 불가능한 이름은 다음과 같다.
- source
- version
- providers
- count
- for_each
- lifecycle
- depends_on
- locals
변수 정의 시 사용가능한 메타인수는 다음과 같다.
- default
- type
- description
- validation
- sensitive
- nullable
입력 변수(variable) 2. 변수 유형
지원되는 변수의 유형은 다음과 같다.
기본 유형
- string: 글자 유형
- number: 숫자 유형
- bool: true/false
- any: 명시적으로 모든 유형이 허용됨을 표시
집합 유형
- list(<유형>): 인덱스 기반 집합
- map (<유형>): 값 = 속성 기반 집합이며 키값 기준 정렬
- set (<유형>): 값 기반 집합이며 키값 기준 정렬
- object({<인수 이름> = <유형>, ...})
- tuple([<유형>, ...])
list 와 set 은 선언하는 형태가 비슷하지만 참조방식이 인덱스와 키로 차이가 있고, map 과 set 의 경우 정렬되는 특징이 있다.
각 유형의 예시를 살펴보자.
variable "string" {
type = string
description = "var String"
default = "myString"
}
variable "number" {
type = number
default = 123
}
variable "boolean" {
default = true
}
variable "list" {
default = [
"google",
"vmware",
"amazon",
"microsoft"
]
}
output "list_index_0" {
value = var.list.0
}
output "list_all" {
value = [
for name in var.list :
upper(name)
]
}
variable "map" { #Sorting
default = [
aws = "amazon",
azure = "microsoft",
gcp = "google"
]
}
variable "set" { #Sorting
type = set(string)
default = [
"google",
"vmware",
"amazon",
"microsoft"
]
}
variable "object" {
type = object({name=string, age=number})
default = [
name = "abc",
age = 12
]
}
variable "tuple" {
type = tuple([string, number, bool])
default = ["abc", 123, true]
}
variable "ingress_rule" { # optional ( >= terraform 1.3.0)
type = list(object({
port = number,
description = optional(string),
protocol = optional(string, "tcp"),
}))
default = [
{ port = 80, description = "web" },
{ port = 53, description = "udp" }
]
}
입력 변수(variable) 3. 유효성 검사
입력되는 변수 타입 지정 외에 테라폼 0.13.0 버전부터 사용자 지정 유효성 검사가 가능하다.
변수 블록 내에 validation 블록에서 조건인 condition 에 지정되는 규칙이 true/false 를 반환해야 하며, error_message 는 condition 값의 결과가 false 인 경우 출력되는 메시지이다.
regex 함수는 대상의 문자열에 정규식을 적용하고 일치하는 문자열을 반환하는데, 여기에 can 함수를 함께 사용하면 정규식에 일치하지 않는 경우 오류를 검출한다.
validation 블록은 중복으로 선언 가능하다.
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
validation {
condition = length(var.image_id) > 4
error_message = "The image_id value must exceed 4."
}
validation {
# regex(...) fails if it cannot find a match
condition = can(regex("^ami-", var.image_id))
error_message = "The image_id value must starting with \"ami-\"."
}
}
입력 변수(variable) 4. 변수 참조
variable 은 코드 내에서 var.<이름> 으로 참조된다.
앞서 작성한 main.tf 에 다음과 같이 변수 선언을 추가하고 terraform plan 을 수행한다.
선언된 variable 에 정의된 값이 없으므로 terraform plan/apply 실행 후, 변수 값을 입력하라는 항목을 확인할 수 있다.
실행 시점에 입력을 하면, 다음과 같이 입력된 변수가 적용되는 것을 확인할 수 있다.
해당 변수에 값을 입력하면 입력받은 값으로 실행 계획을 생성하고 수행한다.
local_file 리소스의 content 에 변수로 선언한 값이 참조되어, 파일 내에 password 값이 추가되는 실행 결과를 확인할 수 있다.
입력 변수(variable) 5. 민감한 변수 취급
민감한 인력 변수를 위해 테라폼 0.14.0 버전부터 입력 변수의 민감 여부를 선언할 수 있다.
앞서 작성한 main.tf 에 다음과 같이 변수 선언에 sensitive 를 추가하고 terraform apply 를 해보자.
다음과 같이 테라폼 계획 출력에서 참조되는 변수 값이 (sensitive value) 로 감춰지는 것을 확인할 수 있다.
출력에서는 값이 표현되지 않아도, 실제 생성되는 리소스 결과물에서는 지정한 값이 정상적으로 입력된다.
또한, 민감한 변수(sensitive) 로 지정하더라도 terraform.tfstate 파일에는 결과물이 평문으로 기록되므로, State 파일의 보안에 유의해야 한다.
입력 변수(variable) 6. 변수 입력 방식과 우선순위
variable 의 목적은 코드 내용을 수정하지 않고, 테라폼의 모듈적 특성을 통해 입력되는 변수로 재사용성을 높이는 데 있다.
특히 입력 변수 라는 명칭에 맞게 사용자는 프로비저닝 실행 시에 원하는 값으로 변수에 정의할 수 있다.
선언되는 방식에 따라 변수의 우선순위 가 있으므로, 차례로 확인해보자.
[우선순위 수준] 의 숫자가 작을수록 우선순위도 낮다. 커질수록 점점 높아진다~!
[우선순위 수준 1] 실행 후 입력
Variable 블록에 선언된 기본값이 없는 채로 terraform plan or apply 를 수행
[우선순위 수준 2] variable 블록의 default 값
main.tf 의 variable 블록에 default 값을 추가
[우선순위 수준 3] 환경 변수 (TF_VAR_변수 이름)
시스템 환경 변수의 접두사에 TF_VAR_ 가 포함되면 그 뒤의 문자열을 변수 이름으로 인식
앞서 default 로 추가한 코드의 내용을 그대로 두고, 어떤 방식의 우선순위가 높은지 비교해보자.
[우선순위 수준 4] terraform.tfvars 에 정의된 변수 선언
루트 모듈의 main.tf 파일과 같은 위치에 terraform.tfvars 파일을 생성해 변수에 대한 값을 추가하고, 앞서 선언한 변수와 우선순위 비교
[우선순위 수준 5] *.auto.tfvars 에 정의된 변수 선언
앞서 terraform.tfvars 와 같은 위치에 a.auto.tfvars 파일을 생성한 뒤 변수 값을 추가하고, 앞서 선언한 변수와 우선순위 비교
뒤이어 b.auto.tfvars 파일을 생성하여 변수에 대한 값을 추가하고, 앞서 선언한 변수와 우선순위 비교
파일명의 정렬에 따라 우선순위가 적용된다.
[우선순위 수준 6] *.auto.tfvars.json 에 정의된 변수 선언
뒤이어 c.auto.tfvars.json 파일을 생성하여 변수에 대한 값을 추가하고, 앞서 선언한 변수와 우선순위 비교
*.auto.tfvars 와 같이 파일명의 정렬에 따라 우선순위가 적용된다.
[우선순위 수준 7] CLI 실행 시 -var 인수에 지정 또는 -var-file 로 파일 지정
앞서 생성한 변수 선언 파일을 유지한 상태로, 변수 값을 선언해 우선순위 비교
여러 인수가 선언되는 경우 나중에 선언된 변수의 우선순위가 높다.
*.tfvars 와 같은 형식의 내용이라면 -var-file 로 지정할 수 있다.
var9.txt 파일을 생성하고파일을 변수 값에 대한 인수로 지정해 확인해보자.
다양한 방식으로 입력 변수를 정의하는 예시를 확인해보았다.
테라폼 실행 방식에 따라 동일한 코드로 다양하게 프로비저닝을 수행할 수 있도록 디자인을 하기 위함이다.
.tfvars 확장자로 생성된 파일에 변수를 미리 기입하여, 실행 시 입력해야하는 변수 값을 하나의 파일에서 관리할 수 있다.
local(지역 값)
local(지역 값) 은 코드 내에서 사용자가 지정한 값 또는 속성 값을 가공해 참조 가능하다.
외부에서 입력되지 않고, 코드 내에서만 가공되어 동작하는 값을 선언한다.
local(지역 값) 1. local 선언
로컬이 선언되는 블록은 locals 로 시작한다.
선언되는 인수에 표현되는 값은 상수, 리소스의 속성, 변수의 값들도 조합해 정의할 수 있다.
다만, locals 에 선언한 로컬 변수 이름은 전체 루트 모듈 내에서 유일해야 한다.
local(지역 값) 2. local 참조
선언된 local 값은 local.<이름> 으로 참조할 수 있다.
main.tf 와 sub.tf 파일을 작성하여, terraform plan 으로 로컬 값을 참조하는 동작을 확인해보자.
이 예제는 서로 다른 tf 파일에서도 로컬 값을 참조할 수 있다는 것을 확인할 수 있다.
그러나 관리 측면에서는 서로 참조하는 로컬값을 분리하여 유지 보수가 어려워질 수 있으니 사용에 유의해야 한다.
출력(output)
출력 값은 주로 테라폼 코듸의 프로비저닝 후의 결과 속성 값을 확인하는 용도로 사용된다.
(자바의 getter 와 비슷한 역할이다.)
출력 값의 용도는 다음과 같이 정의할 수 있다.
- 루트 모듈에서 사용자가 확인하고자 하는 특정 속성 출력
- 자식 모듈의 특정 값을 정의하고 루트 모듈에서 결과를 참조
- 서로 다른 루트 모듈의 결과를 원격으로 읽기 위한 접근 요소
출력 값을 작성하면 속성 값을 노출하고 접근할 수 있으며, 이는 협업 시 유용하다.
출력(output) 1. output 선언
모듈 내에서 정의되는 속성 값들은 output 블록에 정의된다.
output 블록 작성의 예시는 다음과 같다.
output "instance_ip_addr" {
value = "http://${aws_instance.server.private_ip}"
}
출력되는 값은 value 값이며, 테라폼이 제공하는 조합 및 프로그래밍적 기능들로 원하는 값을 출력할 수 있다.
주의할 부분은 output 결과에서 리소스 생성 후 결정되는 속성 값은 프로비저닝이 완료되어야 결과를 확인할 수 있다. 따라서, terraform plan 단계에서는 output 값을 출력하지 않는다.
변수 정의 시 사용 가능한 메타인수
- description
- sensitive
- depends_on
- precondition
출력(output) 2. output 활용
main.tf 를 다음과 같이 작성하고 terraform plan 으로 확인해보자.
이미 정해진 속성에 대해서는 출력은 예측하지만, 아직 생성되지 않은 file 의 id 값에 대해서는 결과를 예측할 수 없으므로
terraform apply 이후에 알 수 있다고 출력된다.
terraform apply 완료 후에는 생성된 file_id 값을 output 으로 출력하는 것을 확인할 수 있다.
apply 실행 이후 마지막으로 표시되는 output 만 다시 확인하고 싶은 경우, terraform output 명령으로 확인할 수 있다.
여기까지 화데이터 소스, 입력 변수, locals, output 등 에 대해 짚고 넘어가자.
다음 포스팅에서는 반복문의 활용에 대해 알아보도록 하자.