들어가며
* 본 스터디의 자료는 아래의 책을 기반으로 합니다.
테라폼으로 시작하는 IaC | 김민수, 김재준, 이규석, 이유종 | 링크
이번 주차에서는 테라폼 기본 사용법 3번째 스터디에서 다룬 반복문, 조건문, 함수, 프로비저너, null_resource와 terraform_data에 대해 배운 내용을 정리합니다.
반복문 for_each
반복문 for_each는 선언된 key값 개수만큼 리소스를 생성하는 것으로 count와 비슷하지만, key-value 포맷의 map, set타입으로 리소스를 생성할 수 있습니다.
만약 list나 object를 이용하여 for_each문을 돌릴려면 toset() 또는 tomap() 함수를 이용하여 형변환을 통해 사용할 수 있습니다.
실습 - 반복문(for each)
for_each 문을 사용하여 리소스를 생성하는 예제입니다.
resource "local_file" "abc" {
for_each = {
a = "content a"
b = "content b"
}
content = each.value
filename = "${path.module}/${each.key}.txt"
}
terraform init && terraform plan && terraform apply -auto-approve
terraform state list
ls *.txt
cat a.txt ;echo
cat b.txt ;echo
for_each는 다음과 같이 variable로 선언된 map을 이용하여 사용할 수도 있습니다.
이때 index_key는 map의 key값을 이용하여 생성할 수 있습니다.
variable "names" {
default = {
a = "content a"
b = "content b"
c = "content c"
}
}
resource "local_file" "abc" {
for_each = var.names
content = each.value
filename = "${path.module}/abc-${each.key}.txt"
}
resource "local_file" "def" {
for_each = local_file.abc
content = each.value.content
filename = "${path.module}/def-${each.key}.txt"
}
cat terraform.tfstate | grep -e key -e name -e "content:"
반복문 count와 달리 중간의 값이 삭제되어도 index_key값이 유지되는 모습을 예제를 통해 확인할 수 있습니다.
variable "names" {
default = {
a = "content a"
# b = "content b" 삭제
c = "content c"
}
}
resource "local_file" "abc" {
for_each = var.names
content = each.value
filename = "${path.module}/abc-${each.key}.txt"
}
resource "local_file" "def" {
for_each = local_file.abc
content = each.value.content
filename = "${path.module}/def-${each.key}.txt"
}
cat terraform.tfstate | grep -e key -e name -e "content:"
실습 - for each 포맷
리스트를 사용하여 테라폼 for_each 반복문을 사용하면 아래와 같이 for_each argument가 맞지 않아 에러가 발생합니다.
resource "aws_iam_user" "the-accounts" {
for_each = ["Todd", "James", "Alice", "Dottie"]
name = each.key
}
이럴 경우 앞서 언급했던 것처럼 toset 함수를 이용하면 리소스를 생성할 수 있습니다.
resource "aws_iam_user" "the-accounts" {
for_each = toset(["Todd", "James", "Alice", "Dottie"])
name = each.key
}
List 와 Map의 차이는 list는 key-value 구조가 아니기 때문에, 데이터 접근 시 배열과 같은 index값을 사용합니다. 하지만 map은 선언된 key-value 중 key를 이용하여 데이터에 접근할 수 있습니다.
#sample[0], sample[1], sample[2]
variable "sample" {
type = list(string)
default = ["aaa", "bbb", "ccc"]
}
#sample["aaa"], sample["bbb"], sample["ccc"]
variable "sample" {
type = map(string)
default = {
"aaa" : "aaa",
"bbb" : "bbb",
"ccc" : "ccc"
}
}
실습 - 다양한 변수
타입을 선언하지 않을 경우 테라폼은 어떻게 변수를 이해해는지에 대해 실습했습니다. 아래와 같이 type() 함수를 사용하여 테라폼 콘솔에서 값의 타입을 확인할 수 있습니다.
주의해야 할 경우 문자열은 ""로 감싸야 에러가 발생하지 않는다는 것입니다.
만약 ""로 숫자를 감쌀경우에는 아래처럼 string으로 인식하게 됩니다.
또한 boolean 타입의 변수도 사용할 수 있습니다.
테라폼의 변수들을 다양하게 생성시켜 보며 list, set, tuple에 대해 이해했습니다.
tuple은 map 또는 set으로 인식하지않기 때문에 foreach 문을 사용할 수 없습니다.
foreach에서는 map과 set 만 허용되기 때문에 set이나오는 c 유형을 이용해야 합니다.
map과 object는 각각 대괄호와 중괄호로 묶인다는 차이가 있습니다.
key-value 구성값을 생성시 type을 따로 정해주지 않으면 기본적으로 object 형태로 생성됩니다. 만약 map으로 명시적으로 지정하여 생성 선언하면 map이 된다. type = map(string)과 같이 사용할 수 있습니다.
해당 내용을 숙지한다면 필요한 상황에서 set이나 map으로 변환하여 사용할 수 있습니다. 요약하자면,
[] 기본 타입 tuple 를 list or set으로 변경하려면 tolist(), toset()을 사용하고
{} 기본 타입 object 를 map으로 변경하려면 tomap() 사용하여
for_each문을 사용할 수 있습니다.
실습 - foreach와 count 비교
for_each와 count를 비교하는 실습을 진행했습니다. 먼저 아래와 같이 count를 기반으로 텍스트 파일들을 생성합니다.
resource "local_file" "abc" {
count = 3
content = "This is filename abc${count.index}.txt"
filename = "${path.module}/abc${count.index}.txt"
}
terraform apply -auto-approve
cat terraform.tfstate | grep -e key -e name -e "content:"
중간에 요소를 편집하게 되면 편집시 인덱스가 변경되어 이전의 상태 저장값과 충돌이 발생하여 이상이 발생하게 됩니다.
다음은 for_each문을 이용하여 리소스를 생성하는 모습입니다. 선언된 user_names list를 toset을 이용하여 set 포맷으로 맞춰주면
아래와 같이 리소스가 잘 생성되는 것을 확인할 수 있습니다.
provider "aws" {
region = "ap-northeast-2"
}
variable "user_names" {
description = "Create IAM users with these names"
type = list(string)
default = ["gasida", "akbun", "ssoon"]
}
resource "aws_iam_user" "myiam" {
for_each = toset(var.user_names) #username 리스트를 set으로 변경하여 사용
name = each.value
}
output "all_users" {
value = aws_iam_user.myiam
}
terraform init -upgrade
terraform plan && terraform apply -auto-approve
cat terraform.tfstate | grep -e key -e name -e "content:"
for Expressions
for Expression은 복잡한 형태의 값을 반환할 때 사용합니다. jsonencode를 이용하면 list 형태의 값을 json 포맷으로 출력할 수 있습니다.
실습 - for Expressions #1
먼저 list에 담긴 정보를 컨텐츠에 기록하는 테라폼코드를 작성합니다.
variable "names" {
default = ["a", "b", "c"]
}
resource "local_file" "abc" {
content = jsonencode(var.names) # 결과 : ["a", "b", "c"]
filename = "${path.module}/abc.txt"
}
output "file_content" {
value = local_file.abc.content
}
terraform apply -auto-approve
terraform state list
terraform output --raw file_content | jq
ls *.txt
cat abc.txt ;echo
실습 - for Expressions #2
for expressions를 사용하여 반복문 안에서 uppers()를 이용하여 다음과 같이 소문자를 대문자로 출력할 수 있습니다.
variable "names" {
default = ["a", "b", "c"]
}
resource "local_file" "abc" {
content = jsonencode([for s in var.names : upper(s)]) # 결과 : ["A", "B", "C"]
filename = "${path.module}/abc.txt"
}
output "file_content" {
value = local_file.abc.content
}
실습 - for Expressions #3
다양한 for 구문을 실행해 보며 출력결과를 확인해 봅니다.
variable "names" {
type = list(string)
default = ["a", "b"]
}
output "A_upper_value" {
value = [for v in var.names : upper(v)]
}
output "B_index_and_value" {
value = [for i, v in var.names : "${i} is ${v}"]
}
output "C_make_object" {
value = { for v in var.names : v => upper(v) }
}
output "D_with_filter" {
value = [for v in var.names : upper(v) if v != "a"]
}
#테라폼 콘솔에서 결과값을 확인해 보면서 아웃풋 확인
terraform apply -auto-approve
terraform state list
#
terraform output
terraform output A_upper_value
terraform output D_with_filter
#
terraform console
-----------------
var.names
type(var.names)
# 리턴 타입 tuple : 값 v
[for v in var.names : upper(v)]
type([for v in var.names : upper(v)])
# 리턴 타입 tuple : 인덱스 i, 값 v
[for i, v in var.names : "${i} is ${v}"]
type([for i, v in var.names : "${i} is ${v}"])
# 리턴 타입 object : object 형태의 경우 키와 값에 대한 쌍은 ⇒ 기호로 구분
{ for v in var.names : v => upper(v) }
type({ for v in var.names : v => upper(v) })
# 조건문 활용 : f 구문을 추가해 조건 부여 가능
[for v in var.names : upper(v) if v != "a"]
type([for v in var.names : upper(v) if v != "a"])
D_with_filter output 처럼 리소스를 생성할 때 조건문 기반으로 데이터를 필터링할 수도 있습니다.
실습 - for Expressions #4
선언된 타입이 map과 object,각각의 default 값이 적용되어 있음
variable "members" {
type = map(object({
role = string
}))
default = {
ab = { role = "member", group = "dev" }
cd = { role = "admin", group = "dev" }
ef = { role = "member", group = "ops" }
}
}
output "A_to_tupple" {
value = [for k, v in var.members : "${k} is ${v.role}"]
}
output "B_get_only_role" {
value = {
for name, user in var.members : name => user.role
if user.role == "admin"
}
}
output "C_group" {
value = {
for name, user in var.members : user.role => name...
}
}
#
terraform apply -auto-approve
terraform state list
#
terraform output
terraform output A_to_tupple
terraform output B_get_only_role
terraform output C_group
terraform console
-----------------
var.members
type(var.members)
[for k, v in var.members : "${k} is ${v.role}"]
type([for k, v in var.members : "${k} is ${v.role}"])
{for name, user in var.members : name => user.role}
type({for name, user in var.members : name => user.role})
{for name, user in var.members : name => user.role if user.role == "admin"}
# { } 형식을 사용해 object 형태로 결과를 반환하는 경우 키 값은 고유해야 하므로 값 뒤에 그룹화 모드 심볼(…)를 붙여서 키의 중복을 방지
{for name, user in var.members : user.role => name...}
실습 - for Expressions #5 (악분님 실습)
악분님의 실습 예제를 통해 for Expressions를 활용 시 주의해야 할 사항에 대해 실습해 보았습니다. 아래와 같이 리스트 구문을 통해 for문을 실행시킬 때는 반드시 []로 for 문을 감싸주어야 에러 없이 사용 가능합니다.
또한 for 문을 이용하여 list나 map 또는 object 형태로 리소스를 구성할 수도 있습니다.
variable "fruits_set" {
type = set(string)
default = ["apple", "banana"]
description = "fruit example"
}
variable "fruits_list" {
type = list(string)
default = ["apple", "banana"]
description = "fruit example"
}
variable "fruits_map" {
type = map(string)
default = {"first": "apple", "second": "banana"}
description = "fruit example"
}
terraform console
-----------------
var.fruits_set
var.fruits_list
var.fruits_map
type(var.fruits_set)
type(var.fruits_list)
type(var.fruits_map)
#
for item in var.fruits_set: item
[for item in var.fruits_set: item]
type([for item in var.fruits_set: item])
{for item in var.fruits_set: item}
{for key,value in var.fruits_set: key => value}
type({for key,value in var.fruits_set: key => value})
#
for item in var.fruits_list: item
[for item in var.fruits_list: item]
type([for item in var.fruits_list: item])
{for item in var.fruits_list: item}
{for key,value in var.fruits_list: key => value}
{for i, v in var.fruits_list: i => v}
type({for i, v in var.fruits_list: i => v})
#
for item in var.fruits_map: item
[for item in var.fruits_map: item]
type([for item in var.fruits_map: item])
{for item in var.fruits_map: item}
{for key,value in var.fruits_map: key => value}
{for k, v in var.fruits_map: k => v}
type({for k, v in var.fruits_map: k => v})
실습 - dynamic block
dynamic 블록은 리소스 내부 속성 블록을 동적인 블록으로 생성할 수 있습니다. 아래와 같이 for_each 구문이나 count를 활용하여 블록 자체를 반복적인 템플릿 형태로 활용할 수 있습니다.
예제를 통해 archive_file 리소스를 동적으로 선언해서 생성해 보았습니다.
variable "names" {
default = {
a = "hello a"
b = "hello b"
c = "hello c"
}
}
data "archive_file" "dotfiles" {
type = "zip"
output_path = "${path.module}/dotfiles.zip"
dynamic "source" {
for_each = var.names
content {
content = source.value
filename = "${path.module}/${source.key}.txt"
}
}
}
#
terraform apply -auto-approve
terraform state list
terraform state show data.archive_file.dotfiles
ls *.zip
조건문
조건문은 3항 연산자 형태를 따릅니다.
<조건> : <옳은 경우> : <틀린 경우>
var.a != "" ? var.a : "default-a"
? 의 왼쪽이 조건, 오른쪽이 옳을 때, 마지막은 틀릴때를 표현합니다.
조건식 역시 앞선 예제와 같이 비교대상의 형태가 다를 경우 형태를 추론하여 자동으로 변환하여 비교작업을 수행합니다. 그렇기 때문에 예기치 못한 오류 없이 잘 동작시키려면 다음과 같이 명시적인 형태로 작성하는 것을 권장합니다.
var.example ? 12 : "hello" # 비권장
var.example ? "12" : "hello" # 권장
var.example ? tostring(12) : "hello" # 권장
조건문을 활용하여 리소스의 생성 여부를 관장 할 수 있습니다.
환경변수가 설정되어 있어서 파일이 생기지 않고, 다시 환경변수를 삭제하게 되면 정상적으로 리소스가 생기게 됩니다.
variable "enable_file" {
default = true
}
resource "local_file" "foo" {
count = var.enable_file ? 1 : 0
content = "foo!"
filename = "${path.module}/foo.bar"
}
output "content" {
value = var.enable_file ? local_file.foo[0].content : ""
}
# 변수 우선순위3 : 환경 변수 (TF_VAR 변수 이름)
export TF_VAR_enable_file=false
export | grep TF_VAR_enable_file
#
terraform init && terraform plan && terraform apply -auto-approve
terraform state list
echo "var.enable_file ? 1 : 0" | terraform console
# 환경 변수 삭제
unset TF_VAR_enable_file
export | grep TF_VAR_enable_file
# 재실행
terraform plan && terraform apply -auto-approve
terraform state list
#
echo "local_file.foo[0]" | terraform console
echo "local_file.foo[0].content" | terraform console
echo "var.enable_file ? 1 : 0" | terraform console
도전과제 - 조건문을 활용하여 AWS 리소스 만들기!
조건문을 활용하여 AWS리소스를 생성하는 코드를 작성해 보았습니다.
add_time이라는 변수를 생성하여 default로 true 조건값을 주고, vpc 및 서브넷을 생성합니다.
서브넷 생성시에는 조건문 삼항연산자를 통해 생성되는 태그에 테라폼 함수인 plantimestamp()를 이용하여,
현재 시간값을 추가할 수 있도록 했습니다.
variable "add_time" {
default = true
}
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_vpc" "myvpc" {
cidr_block = "10.10.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "t101-study"
}
}
resource "aws_subnet" "mysubnet1" {
vpc_id = aws_vpc.myvpc.id
cidr_block = "10.10.1.0/24"
availability_zone = "ap-northeast-2a"
tags = {
Name = var.add_time ? "t101-subnet1-${plantimestamp()}" : "t101-subnet1"
}
}
resource "aws_subnet" "mysubnet2" {
vpc_id = aws_vpc.myvpc.id
cidr_block = "10.10.2.0/24"
availability_zone = "ap-northeast-2c"
tags = {
Name = var.add_time ? "t101-subnet2" : "t101-subnet2-${plantimestamp()}"
}
}
output "aws_vpc_id" {
value = aws_vpc.myvpc.id
}
output "aws_subnet1_id" {
value = aws_subnet.mysubnet1.tags.Name
}
output "aws_subnet2_id" {
value = aws_subnet.mysubnet2.tags.Name
}
terraform init && terraform plan && terraform apply -auto-approve
함수
앞서 사용한 함수외에도 테라폼은 다양한 내장함수를 제공합니다. 해당 링크를 통해 다양한 내장함수들의 종류와 활용 예시를 확인할 수 있습니다.
resource "local_file" "foo" {
content = upper("foo! bar!")
filename = "${path.module}/foo.bar"
}
terraform init && terraform plan && terraform apply -auto-approve
cat foo.bar ; echo
# 내장 함수 간단 사용
terraform console
-----------------
upper("foo!")
max(5, 12, 9)
lower(local_file.foo.content)
upper(local_file.foo.content)
cidrnetmask("172.16.0.0/12")
cidrsubnet("1.1.1.0/24", 1, 0)
cidrsubnet("1.1.1.0/24", 1, 1)
cidrsubnet("1.1.1.0/24", 2, 2)
cidrsubnet("1.1.1.0/24", 2, 0)
cidrsubnet("1.1.1.0/24", 2, 1)
cidrsubnet("1.1.1.0/24", 2, 2)
cidrsubnet("1.1.1.0/24", 2, 3)
cidrsubnets("10.1.0.0/16", 4, 4, 8, 4)
exit
-----------------
프로비저너 (최후의 수단)
프로비저너 실행결과는 테라폼 상태파일과 동기화가 되지 않으므로, 결과가 선언적인 보장이 되지 않습니다. 그렇기 때문에 프로비저너 사용을 최소화하는 것이 좋다고 합니다.
variable "sensitive_content" {
default = "secret"
#sensitive = true
}
resource "local_file" "foo" {
content = upper(var.sensitive_content)
filename = "${path.module}/foo.bar"
provisioner "local-exec" {
command = "echo The content is ${self.content}"
}
provisioner "local-exec" {
command = "abc"
on_failure = continue
}
provisioner "local-exec" {
when = destroy
command = "echo The deleting filename is ${self.filename}"
}
}
terraform init && terraform plan
#
terraform apply -auto-approve
terraform state list
terraform state show local_file.foo
cat foo.bar ; echo
cat terraform.tfstate | jq
# graph 확인 : 프로비저너 정보가 없음
terraform graph > graph.dot
# 삭제
terraform destroy -auto-approve
리소스를 만들고나서 프로비저닝을 통해 로컬에서 커맨드가 실행됩니다.
로컬에서 abc 명령어가 실행될 때 오류가 발생합니다. 하지만 continue를 통해 계속 명령을 수행합니다. state 파일을 확인해 보면 에러에 대한 내용을 확인할 수 없습니다. 이것은 상태를 관리하지 않는 프로비저너의 특성 때문입니다.
그렇기 때문에 최후의 수단! 외에는 사용하는 것을 권고하지는 않는다고 합니다.
그래프를 확인해 보면 로컬에서 수행된 명령들의 의존성을 확인할 수 없습니다.
프로비저너는 다음과 같은 종류가 있습니다.
- local-exec 프로비저너 : 로컬 환경에서 테라폼이 수행할 커맨드를 정의
- 원격지 연결 프로비저너 : 원격지로 연결해서 사용하는 프로비저너
- file 프로비저너 : 테라폼을 실행하는 시스템에서 연결 대상으로 파일 또는 디렉토리를 복사하는데 사용
- remote-exec 프로비저너 : 원격지 환경에서 실행할 커맨드와 스크립트를 정의
null_resource와 terraform_data
EC2 인스턴스 생성 후 Elastic IP를 붙이는 상황이 있다고 했을 때, 상호참조가 발생하여 에러가 발생하게 된다. 이때 아무것도 하지 않는 null_resource를 활용하여 리소스가 있는 것처럼 동작하여 라이프 사이클을 맞추는 방법이라고 합니다.
null_resource
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_security_group" "instance" {
name = "t101sg"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "example" {
ami = "ami-0c9c942bd7bf113a2"
instance_type = "t2.micro"
subnet_id = "subnet-0a7e8a95e85cdd3d2" # 각자 default VPC에 subnet ID 아무거나
private_ip = "172.31.1.100"
vpc_security_group_ids = [aws_security_group.instance.id]
user_data = <<-EOF
#!/bin/bash
echo "Hello, T101 Study" > index.html
nohup busybox httpd -f -p 80 &
EOF
tags = {
Name = "Single-WebSrv"
}
provisioner "remote-exec" {
inline = [
"echo ${aws_eip.myeip.public_ip}"
]
}
}
resource "aws_eip" "myeip" {
#vpc = true
instance = aws_instance.example.id
associate_with_private_ip = "172.31.1.100"
}
output "public_ip" {
value = aws_instance.example.public_ip
description = "The public IP of the Instance"
}
해당 코드를 실행하게 되면 테라폼 코드 내에서 상호참조가 발생하게 되어 에러가 발생하게 됩니다.
이를 해결하기 위해 두 리소스 중 하나의 실행 시점을 미루어 문제를 해결할 수 있습니다. 실행에 간격을 추가하여 실행 시점의 문제가 발생하지 않기 위해 아래와 같이 null_resource를 활용합니다.
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_security_group" "instance" {
name = "t101sg"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "example" {
ami = "ami-0c9c942bd7bf113a2"
instance_type = "t2.micro"
subnet_id = "subnet-dbc571b0"
private_ip = "172.31.0.100"
key_name = "jhpark" # 각자 자신의 EC2 SSH Keypair 이름 지정
vpc_security_group_ids = [aws_security_group.instance.id]
user_data = <<-EOF
#!/bin/bash
echo "Hello, T101 Study" > index.html
nohup busybox httpd -f -p 80 &
EOF
tags = {
Name = "Single-WebSrv"
}
}
resource "aws_eip" "myeip" {
#vpc = true
instance = aws_instance.example.id
associate_with_private_ip = "172.31.0.100"
}
resource "null_resource" "echomyeip" {
provisioner "remote-exec" {
connection {
host = aws_eip.myeip.public_ip
type = "ssh"
user = "ubuntu"
private_key = file("/Users/devlos/.ssh/jhpark.pem") # 각자 자신의 EC2 SSH Keypair 파일 위치 지정
#password = "qwe123"
}
inline = [
"echo ${aws_eip.myeip.public_ip}"
]
}
}
output "public_ip" {
value = aws_instance.example.public_ip
description = "The public IP of the Instance"
}
output "eip" {
value = aws_eip.myeip.public_ip
description = "The EIP of the Instance"
}
terraform init -upgrade
# 실행 : EIP 할당 전 (임시) 유동 공인 IP 출력
terraform plan
terraform apply -auto-approve
terraform graph > graph.dot
MYIP=$(terraform output -raw eip)
while true; do curl --connect-timeout 1 http://$MYIP/ ; echo "------------------------------"; date; sleep 1; done
terraform_data
앞서 언급한 실행시점 문제를 해결하기 위해 테라폼 자체에서 추가 프로바이더 없이 수명을 관리하기 위해 나온 리소스입니다.
사용 예시는 다음과 같습니다.
resource "aws_instance" "web" {
# ...
}
resource "aws_instance" "database" {
# ...
}
# A use-case for terraform_data is as a do-nothing container
# for arbitrary actions taken by a provisioner.
resource "terraform_data" "bootstrap" {
triggers_replace = [
aws_instance.web.id,
aws_instance.database.id
]
provisioner "local-exec" {
command = "bootstrap-hosts.sh"
}
}
###
resource "terraform_data" "foo" {
triggers_replace = [
aws_instance.foo.id,
aws_instance.bar.id
]
input = "world"
}
output "terraform_data_output" {
value = terraform_data.foo.output
}
triggers_replace와 input 인수로 상태를 저장하고 다른 곳에서 리소스 정보를 사용할 수 있도록 구성했습니다.
moved 블록
리소스의 이름이 바뀔 때 안전하게 마이그레이션 하는 방법입니다. 테라폼은 기본적으로 리소스의 이름이 변경되면 기존 리소스를 삭제하고 새로운 리소스 형태로 만들어냅니다. 비효율적인 상황을 막기 위해 moved 블록을 사용하여 from, to를 지정하게 되면 리소스가 재생성되는 것을 막을 수 있습니다.
resource "local_file" "a" {
content = "foo!"
filename = "${path.module}/foo.bar"
}
output "file_content" {
value = local_file.a.content
}
terraform init && terraform plan && terraform apply -auto-approve
---
# moved 블록 사용
resource "local_file" "b" {
content = "foo!"
filename = "${path.module}/foo.bar"
}
moved {
from = local_file.a
to = local_file.b
}
output "file_content" {
value = local_file.b.content
}
terraform plan
terraform apply -auto-approve
---
# moved 블록 삭제
resource "local_file" "b" {
content = "foo!"
filename = "${path.module}/foo.bar"
}
#moved {
# from = local_file.a
# to = local_file.b
#}
output "file_content" {
value = local_file.b.content
}
moved 블록 없이 실행하게 되면 콘텐츠가 삭제된다는 설명을 확인할 수 있습니다.
하지만, moved 블록을 사용하면 삭제 없이 이름만 변경이 가능합니다.
실행결과를 살펴보면, 리소스의 이름과 시리얼 번호만 변경되고 나머지 정보는 기존과 동일한 것을 확인할 수 있습니다.
마치며
3주 차에 걸쳐 테라폼 기본 문법을 계속 배우고 있습니다. 개인적으로 이번 주 실습분량은 상당했지만, 스터디 그룹과 악분님께서 준비해 주신 실습 시나리오가 디테일하고, 반복적으로 작성해 보기가 편해서 문법에 익숙해지기 쉬웠습니다.
다음 스터디 후 포스팅에서 뵙겠습니다.
긴 글 읽어주셔서 감사합니다 :)
'클라우드 컴퓨팅 & NoSQL > [T101] 테라폼 4기 스터디' 카테고리의 다른 글
[6주차 - Well-Architected 방식으로 워크로드를 안전하게 마이그레이션 및 현대화하기 Workshop ] T101 4기 스터디 (24.07.14) (0) | 2024.07.17 |
---|---|
[5주차 - 모듈 & Runner] T101 4기 스터디 (24.07.07) (1) | 2024.07.13 |
[4주차 - Provider & State] T101 4기 스터디 (24.06.30) (0) | 2024.07.04 |
[2주차 - 기본사용#2] T101 4기 스터디 (24.06.16) (0) | 2024.06.22 |
[1주차 - 기본사용] T101 4기 스터디 (24.06.09) (1) | 2024.06.15 |