프로비저너
테라폼의 프로비저너는 리소스 생성, 변경 또는 삭제 작업을 보완하기 위해 사용됩니다. 프로비저너는 특정 리소스를 초기 설정, 설정 변경, 시스템에 소프트웨어 설치 등의 작업을 수행합니다.
일반적인 사용 사례
- 파일 업로드: 서버에 필요한 설정 파일을 업로드
- 소프트웨어 설치: 패키지 매니저를 사용하여 필요한 소프트웨어를 설치
- 스크립트 실행: 특정 작업을 수행하기 위해 쉘 스크립트 또는 Ansible 등을 실행
주요 프로비저너 유형
local-exec: 로컬 머신에서 명령을 실행remote-exec: 원격 머신에서 명령을 실행file: 로컬 머신에서 원격 머신으로 파일 또는 디렉터리를 복사
주의사항
프로비저너의 사용은 테라폼 코드의 선언적 특성에 어긋날 수 있습니다. 따라서 가능한 프로비저너를 적게 사용하고, 다른 방법으로 리소스를 설정하는 것이 권장됩니다.
사용 예시
AWS EC2 인스턴스에 파일을 업로드하고 명령을 실행하는 예입니다.
resource "aws_instance" "example" {
ami = "ami-0c9c942bd7bf113a2"
instance_type = "t2.micro"
provisioner "file" {
source = "local/file/path"
destination = "/remote/file/path"
}
provisioner "remote-exec" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y nginx"
]
}
}
유의점
- 순서: 프로비저너는 리소스의 생명주기 중 특정 시점에 실행됩니다. 예를 들어, 리소스 생성 후에 실행되거나 리소스 삭제 전에 실행될 수 있습니다.
- 가변성: 프로비저너는 상태를 명시적으로 관리하지 않습니다. 따라서, 프로비저닝 로직이 변경될 경우 이전 리소스에 적용되지 않을 수 있습니다.
- 에러 핸들링: 프로비저너가 실패하면, 테라폼은 해당 리소스를 “타인트” 상태로 마킹합니다. 이 경우 사용자는 수동으로 상태를 복구해야 할 수 있습니다.
프로비저너는 유용하지만, 가능하면 리소스의 argument 또는 **setting**을 통해 필요한 설정을 하는 것이 더 좋습니다. 프로비저너는 꼭 필요한 경우에만 사용하는 것이 관리 측면에서 좋습니다.
테라폼(Terraform)에서 사용되는 주요 프로비저너(provisioners)와 각각의 특성은 다음과 같습니다.
1. local-exec 프로비저
- 특성: 로컬 시스템에서 명령어를 실행합니다.
- 사용 사례: 리소스 생성 후 로컬에서 특정 스크립트를 실행해야 할 때 유용합니다.
2. remote-exec 프로비저너
- 특성: 원격 서버에서 명령어를 실행합니다.
- 사용 사례: 서버 생성 후 원격으로 초기 설정이나 패키지 설치가 필요한 경우에 사용됩니다.
resource "aws_instance" "web" {
# ...
# Establishes connection to be used by all
# generic remote provisioners (i.e. file/remote-exec)
connection {
type = "ssh"
user = "root"
password = var.root_password
host = self.public_ip
}
provisioner "file" {
source = "script.sh"
destination = "/tmp/script.sh"
}
provisioner "remote-exec" {
inline = [
"chmod +x /tmp/script.sh",
"/tmp/script.sh args",
]
}
}3. file 프로비저너
- 특성: 로컬 파일을 원격 서버로 복사합니다.
- 사용 사례: 설정 파일이나 스크립트를 원격 서버에 전달해야 할 때 사용됩니다.
resource "null_resource" "foo" {
# myapp.conf 파일이 /etc/myapp.conf 로 업로드
provisioner "file" {
source = "conf/myapp.conf"
destination = "/etc/myapp.conf"
}
# content의 내용이 /tmp/file.log 파일로 생성
provisioner "file" {
content = "ami used: ${self.ami}"
destination = "/tmp/file.log"
}null resource와 terraform data
null_resource
특성
- 아무런 작업도 수행하지 않는 리소스.
- 별도의 프로바이더 구성이 필요합니다.
- 주로 프로비저닝 로직이나 의존성 관리를 수행하기 위해 사용됩니다.
사용 시나리오
- 프로비저닝 수행: **
local-exec**나 **remote-exec**과 같은 프로비저너를 활용해 명령어를 실행합니다. - 의존성 관리: 다른 리소스의 생성을 조건부로 관리합니다.
- 데이터 처리: 출력을 위한 데이터를 가공하거나, 로컬 변수와 함께 사용합니다.
terraform_data
특성
- 자체적으로 아무런 작업도 수행하지 않습니다.
- 별도의 프로바이더 구성이 필요 없이 테라폼 자체의 기본 수명주기 관리자가 제공됩니다.
- **
trigger_replace**와input 인수, 그리고 **output 속성**이 제공됩니다.
사용 시나리오
- 기본적으로 **
null_resource**와 동일한 사용 시나리오가 적용됩니다. - 강제 재실행을 위한
trigger_replace사용이 가능합니다. - 상태 저장을 위한 **
input 인수**와 그에 따른 **output 속성**을 활용할 수 있습니다.
추가 기능
- triggers_replace: tuple 형태로 기존 map 형태보다 간단하게 값들을 정의할 수 있습니다.
- input: 상태 저장을 위해 사용됩니다.
- output: **
input**에 저장된 값을 출력합니다.
예제
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 # 출력 결과는 "world"
}
moved 블록
기본 개념
- 테라폼에서 리소스의 주소나 이름이 변경되면 기본적으로 그 리소스는 삭제되고 새로운 리소스가 생성됩니다.
- 테라폼 1.1 버전부터는 리소스 이름이나 주소를 변경하더라도, 기존 리소스 상태를 유지하면서 이를 반영할 수 있는
moved블록이 도입되었습니다.
주요 사용 케이스
- 리소스 이름 변경: 코딩 규칙이나 명명 규칙의 변화로 리소스 이름을 변경해야 할 때.
- 반복문 변경: **
count**을 사용하던 것을 **for_each**로 변경할 때. - 모듈 이동: 리소스가 다른 모듈로 이동하여 참조 주소가 변경될 때.
기존 방식 vs Moved 블록
- 기존 방식: 이전에는
terraform state mv명령어를 사용해서 수동으로 테라폼 상태 파일을 수정해야 했습니다. 이는 State 파일에 직접 접근해야 하므로 권한이나 복잡성 문제가 발생할 수 있습니다. - Moved 블록: State 파일에 직접 접근할 필요가 없습니다. 이전 주소와 새 주소를
moved블록 내에서 선언함으로써 리소스의 이동을 안전하고 간편하게 관리할 수 있습니다.
핵심 기능
- 리소스가 “옮겨졌다(moved)“는 사실과 그에 따른 이전 주소와 새로운 주소를 테라폼 State에 알려주는 역할을 합니다.
이러한 특징을 고려하면, moved 블록은 리소스 구성이 변경되는 다양한 상황에서 유용하게 사용될 수 있습니다. 이를 통해 테라폼 코드의 유연성과 안정성이 향상될 수 있습니다.
다음 예시 코드를 실행해봅다.
cat <<'EOT' > main.tf
resource "local_file" "a" {
content = "foo!"
filename = "${path.module}/foo.bar"
}
output "file_content" {
value = local_file.a.content
}
EOT
이제 다음 main.tf 파일을 변경합니다다.
아래의 local_file의 이름을 a→ b 로 변경합니다
cat <<'EOT' > main.tf
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
}
EOT
위의 결과는 moved 블록을 사용하지않고 plan 했을경우 나오는 경과문이며, moved 블록을 이용해 plan 할경우 이상이 없음을 확인할 수 있습니다.
CLI를 위한 시스템 환경변수
테라폼은 환경변수를 이용해 실행방식, 출력내용에 대한 옵션을 조정이 가능합니다
일반적인 사용
- 테라폼 CLI 환경 변수 설정을 통해 로컬 또는 다른 서버 환경에서 특정 옵션을 지정할 수 있습니다.
- 이 설정은 시스템 환경 변수로, 일반적으로 영구적으로 로컬 환경에 적용됩니다.
설정 방법
Mac/리눅스/유닉스: export <환경 변수 이름>=<값>
Windows CMD: set <환경 변수 이름>=<값>
Windows PowerShell: $Env:<환경 변수 이름>='<값>'주요 환경 변수
- TF_LOG: 테라폼의 로깅 레벨을 설정합니다. (
trace,debug,info,warn,error,off) - TF_LOG_PATH: 로그를 저장할 파일의 위치를 지정합니다.
- TF_LOG_CORE: 테라폼 코어 자체의 로깅 레벨을 설정합니다.
- TF_LOG_PROVIDER: 테라폼의 프로바이더에 대한 로깅 레벨을 설정합니다.
사용 예시
-
**
TF_LOG**를 **info**로 설정하고 **terraform plan**을 실행하면, 관련 로그가 표시됩니다.bashCopy code TF_LOG=info terraform plan
이를 통해 테라폼 작업을 보다 세밀하게 제어하고 디버깅할 수 있습니다.
프로바이더
테라폼의 프로바이더(Provider)는 특정 클라우드 또는 서비스의 리소스를 관리하기 위한 플러그인입니다. 각 프로바이더는 해당 서비스에 특화된 리소스 생성, 수정, 관리 및 삭제 동작을 정의합니다. 예를 들어, AWS 프로바이더를 사용하면 AWS의 EC2 인스턴스, S3 버킷, RDS 데이터베이스 등을 테라폼 코드로 관리할 수 있습니다.
프로바이더는 테라폼 코드에서 provider 블록을 통해 설정됩니다. 이 블록에서는 프로바이더의 버전, 인증 정보, 지역 등을 지정할 수 있습니다.
구성

출처 : Cloudnet 스터디

대표적인 프로바이더 종류입니다.
terraform {
required_providers {
architech-http = {
source = "architect-team/http"
version = "~> 3.0"
}
http = {
source = "hashicorp/http"
}
aws-http = {
source = "terraform-aws-modules/http"
}
}
}
data "http" "example" {
provider = aws-http
url = "https://checkpoint-api.hashicorp.com/v1/check/terraform"
request_headers = {
Accept = "application/json"
}
}다음과 같이 다수의 프로바이더를 선택이 가능합니다.
단일 프로바이더를 다중정의 할 경우
# region 1
provider "aws" {
region = "ap-southeast-1"
}
# region 2
provider "aws" {
alias = "seoul"
region = "ap-northeast-2"
}
resource "aws_instance" "app_server1" {
ami = "ami-06b79cf2aee0d5c92"
instance_type = "t2.micro"
}
resource "aws_instance" "app_server2" {
provider = aws.seoul
ami = "ami-0ea4d4b8dc1e46212"
instance_type = "t2.micro"
}다음과 같은 형식으로 region에 따라 aws provider를 aws_instance에 지정하는 방식입니다.
확인 / 삭제
terraform init && terraform plan
terraform apply -auto-approve
terraform state list
terraform destroy -auto-approve프로바이더 경험해보기
Kubernetes
Kubernetes 실습
Kubernetes 프로바이더를 사용한 Nginx Deployment + Service 배포 - [참고: Docs ]
- 실습을 위해서 4.4 디렉터리를 신규 생성 후 열기
cd ../
mkdir 4.4 && cd 4.4- main.tf 파일 생성 : kubernetes 프로바이더 정의 및 KUBECONFIG 파일경로 정의
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
}
}
}
provider "kubernetes" {
config_path = "~/.kube/config"
}- kubernetes.tf 파일 생성 : Deployment, Service 리소스 정의 - [참고: K8s YAML to HCL ]
resource "kubernetes_deployment" "nginx" {
metadata {
name = "nginx-example"
labels = {
App = "images/T101-nginx"
}
}
spec {
replicas = 2
selector {
match_labels = {
App = "images/T101-nginx"
}
}
template {
metadata {
labels = {
App = "images/T101-nginx"
}
}
spec {
container {
image = "nginx:1.7.8"
name = "example"
port {
container_port = 80
}
}
}
}
}
}
resource "kubernetes_service" "nginx" {
metadata {
name = "nginx-example"
}
spec {
selector = {
App = kubernetes_deployment.nginx.spec.0.template.0.metadata[0].labels.App
}
port {
node_port = 30080
port = 80
target_port = 80
}
type = "NodePort"
}
}- 실행
# [터미널1] terraform init & plan & apply
**terraform init && terraform plan && terraform apply -auto-approve
terraform state list**
# [터미널1] terraform destroy
**terraform destroy -auto-approve**watch 명령어로 생성을 같이 살펴봅니다
watch -n1 -d kubectl get pods,svc기존에 올라가있는 리소스들을 제외하고, 4m 13s 로 생성된 nginx-example 리소스를 조회 할 수 있습니다.

helm 실습
- 실습을 위해서 4.5 디렉터리를 신규 생성 후 열기
# 4.4 디렉토리에서 작업을 진행했다면 상위 디렉토리로 이동
cd ../
mkdir 4.5 && cd 4.5- main.tf
terraform {
required_providers {
helm = {
source = "hashicorp/helm"
version = "2.11.0"
}
}
}
provider "helm" {
kubernetes {
config_path = "~/.kube/config"
}
}- helm.tf
resource "helm_release" "nginx" {
name = "nginx"
repository = "https://charts.bitnami.com/bitnami"
chart = "nginx"
values = [
file("${path.module}/nginx-values.yaml")
]
}- nginx-values.yaml
replicaCount: 1
service:
type: NodePort- 실행
# [터미널1] terraform init & plan & apply
**terraform init && terraform plan && terraform apply -auto-approve**
# [터미널2]helm 배포확인
helm list | grep nginx
# [터미널1] terraform destroy
**terraform destroy -auto-approve**
정상적으로 helm 프로비저닝이 된것을 확인 할 수 있다.