테라폼 기본 3/3
September 2023 (2305 Words, 13 Minutes)
프로비저너
테라폼의 프로비저너는 리소스 생성, 변경 또는 삭제 작업을 보완하기 위해 사용됩니다. 프로비저너는 특정 리소스를 초기 설정, 설정 변경, 시스템에 소프트웨어 설치 등의 작업을 수행합니다.
일반적인 사용 사례
- 파일 업로드: 서버에 필요한 설정 파일을 업로드
- 소프트웨어 설치: 패키지 매니저를 사용하여 필요한 소프트웨어를 설치
- 스크립트 실행: 특정 작업을 수행하기 위해 쉘 스크립트 또는 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 프로비저닝이 된것을 확인 할 수 있다.