cloudNet@ 팀의 가시다 님이 진행하는 테라폼 102 스터디 3주차 정리입니다.
1. 조건문
- 테라폼에서의 조건식은 3항 연산자 형태를 갖는다. 조건은 true 또는 false로 확인되는 모든 표현식을 사용할 수 있다
- 조건식은 (?) 기호를 기준으로 왼쪽은 조건이며, 오른쪽은 : 기호를 기준으로 왼쪽이 조건에 대해 true가 반환되는 경우이고 오른쪽이 false가 반환되는 경우다.
- 다음의 예에서 var.a가 빈 문자열이 아니라면 var.a를 나타내지만, 비어 있을 때는 “default-a”를 반환한다
# <조건 정의> ? <옳은 경우> : <틀린 경우>
var.a != "" ? var.a : "default-a"
조건식의 각 조건은 비교 대상의 형태가 다르면 테라폼 실행 시 조건 비교를 위해 형태를 추론하여 자동으로 변환하는데, 명시적인 형태 작성을 권장합니다.
# 조건식 형태 권장 사항
#12는숫지 #hello는 문자 물론 테라폼이 비교해서 형태를 추론하지만 비추
var.example ? 12 : "hello" # 비권장
var.example ? "12" : "hello" # 권장
#tostring 함수는 입력값을 문자열로 변환하는데 사용됩니다. 여기서 tostring(12)는 숫자 12를 문자열 "12"로 변환
var.example ? tostring(12) : "hello" # 권장
또다른 예시입니다
- enable_file 값이 true 즉 1 이므로 파일을 생성합니다.
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 : ""
}
2. 함수
- 테라폼은 프로그래밍 언어적인 특성을 가지고 있어서, 값의 유형을 변경하거나 조합할 수 있는 내장 함수를 사용 할 수 있다
- 단, 내장된 함수 외에 사용자가 구현하는 별도의 사용자 정의 함수를 지원하지는 않는다.
- 함수 종류에는 숫자, 문자열, 컬렉션, 인코딩, 파일 시스템, 날짜/시간, 해시/암호화, IP 네트워크, 유형 변환이 있다.
- 테라폼 코드에 함수를 적용하면 변수, 리소스 속성, 데이터 소스 속성, 출력 값 표현 시 작업을 동적이고 효과적으로 수행할 수 있다.
예시 코드입니다.
upper = 소문자를 대문자로 변경
resource "local_file" "foo" {
content = upper("foo! bar!")
filename = "${path.module}/foo.bar"
}
3. 프로비저너
프로비저너는 프로바이더와 비슷하게 ‘제공자’로 해석되나, 프로바이더로 실행되지 않는 커맨드와 파일 복사 같은 역할을 수행
- 예를 들어 AWS EC2 생성 후 특정 패키지를 설치해야 하거나 파일을 생성해야 하는 경우, 이것들은 테라폼의 구성과 별개로 동작해야 한다.
- 프로비저너로 실행된 결과는 테라폼의 상태 파일과 동기화되지 않으므로 프로비저닝에 대한 결과가 항상 같다고 보장할 수 없다 ⇒ 선언적 보장 안됨
- 따라서 프로비저너 사용을 최소화하는 것이 좋다. 프로비저너의 종류에는 파일 복사와 명령어 실행을 위한 file, local-exec, remote-exec가 있다.( 멱등성 )
- 프로비저너의 경우 리소스 프로비저닝 이후 동작하도록 구성할 수 있다. 예를 들어 AWS EC2 생성 후 CLI를 통해 별도 작업 수행 상황을 가정
예제 코드입니다.
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
...
Plan: 1 to add, 0 to change, 0 to destroy.
local_file.foo: Creating...
local_file.foo: Provisioning with 'local-exec'...
local_file.foo (local-exec): Executing: ["/bin/sh" "-c" "echo The content is SECRET"]
local_file.foo (local-exec): The content is SECRET
local_file.foo: Provisioning with 'local-exec'...
local_file.foo (local-exec): Executing: ["/bin/sh" "-c" "abc"]
#abc라는 명령어가 없어서 원래는 실패해야하지만 on_failure 계속진행됨
local_file.foo (local-exec): /bin/sh: abc: command not found
local_file.foo: Creation complete after 0s [id=3c3b274d119ff5a5ec6c1e215c1cb794d9973ac1]
# 테라폼 상태에 프로비저너 정보(실행 및 결과)가 없다
terraform state list
terraform state show local_file.foo
=
# local_file.foo:
resource "local_file" "foo" {
content = "SECRET"
content_base64sha256 = "CRexOpCRkV1UtjNvRZCVOczkUrNmGyHzhkGKJXiDswo="
content_base64sha512 = "/rZUHUkqHVA5TMRI6cTQisOBxckKZWsZIBus/flGK4eopVeaR4EGCcIwfeyS9SyI8hj9MHWv4CYpvF/QHOc0/Q=="
content_md5 = "44c7be48226ebad5dca8216674cad62b"
content_sha1 = "3c3b274d119ff5a5ec6c1e215c1cb794d9973ac1"
content_sha256 = "0917b13a9091915d54b6336f45909539cce452b3661b21f386418a257883b30a"
content_sha512 = "feb6541d492a1d50394cc448e9c4d08ac381c5c90a656b19201bacfdf9462b87a8a5579a47810609c2307dec92f52c88f218fd3075afe02629bc5fd01ce734fd"
directory_permission = "0777"
file_permission = "0777"
filename = "./foo.bar"
id = "3c3b274d119ff5a5ec6c1e215c1cb794d9973ac1"
}
# 삭제
terraform destroy -auto-approve
...
Plan: 0 to add, 0 to change, 1 to destroy.
local_file.foo: Destroying... [id=3c3b274d119ff5a5ec6c1e215c1cb794d9973ac1]
local_file.foo: Provisioning with 'local-exec'..
local_file.foo (local-exec): Executing: ["/bin/sh" "-c" "echo The deleting filename is ./foo.bar"]
#출력문구 확인
local_file.foo (local-exec): The deleting filename is ./foo.bar
local_file.foo: Destruction complete after 0s
on_failure = continue 추석처리 하고 보자
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 apply -auto-approve
...
Plan: 1 to add, 0 to change, 0 to destroy.
local_file.foo: Creating...
local_file.foo: Provisioning with 'local-exec'...
#감춰진 이유는 sensitive_content 참조하고 있어서이다.
local_file.foo (local-exec): (output suppressed due to sensitive value in config)
local_file.foo (local-exec): (output suppressed due to sensitive value in config)
local_file.foo: Provisioning with 'local-exec'...
local_file.foo (local-exec): Executing: ["/bin/sh" "-c" "abc"]
local_file.foo (local-exec): /bin/sh: abc: command not found
╷
# 에러가 발생한 이유는 on_failure 주석처리 하여서 입니다.
│ Error: local-exec provisioner error
│
│ with local_file.foo,
│ on main.tf line 14, in resource "local_file" "foo":
│ 14: provisioner "local-exec" {
│
│ Error running command 'abc': exit status 127. Output: /bin/sh: abc: command not found
local-exec
- 리눅스나 윈도우등 테라폼을 실행하는 환경에 맞게 커맨드를 정의, 아래 사용하는 인수 값
- **command(**필수) : 실행할 명령줄을 입력하며 << 연산자를 통해 여러 줄의 커맨드 입력 가능
- working_dir(선택) : command의 명령을 실행할 디렉터리를 지정해야 하고 상대/절대 경로로 설정
- interpreter(선택) : 명령을 실행하는 데 필요한 인터프리터를 지정하며, 첫 번째 인수로 인터프리터 이름이고 두 번째부터는 인터프리터 인수 값
- environment(선택) : 실행 시 환경 변수 는 실행 환경의 값을 상속받으면, 추가 또는 재할당하려는 경우 해당 인수에 key = value 형태로 설정
예제 코드입니다.
resource "null_resource" "example1" {
#리소스 배치와 관련된 로컬 명령 실행에 사용되는 프로비저너입니다. 후속 블록에서 지정한 명령어가 로컬 시스템에서 실행됩니다.
provisioner "local-exec" {
command = <<EOF
echo Hello!! > file.txt
echo $ENV >> file.txt
EOF
# 이 스크립트를 실행할 때 사용할 인터프리터를 지정합니다. 여기서는 bash와 -c 옵션을 사용합니다.
# Bash 명령을 텍스트로 직접 입력하여 실행할 수 있습니다. -c 옵션 뒤에 따옴표로 둘러싼 명령어를 입력
#추가 팁으로는 해당 부분을 주석을 처리해도 =..
#..=>테라폼은 기본 셸을 사용하여 프로비전 명령을 실행합니다. Linux 및 macOS에서 기본 셸은 일반적으로 "bash"이므로 명령이 계속 실행됩니다. 따라서 이 경우 interpreter = ["bash", "-c"] 부분이 주석 처리되어도 명령이 정상적으로 실행되는 것입니다. 그러나 기본 셸이 "bash"가 아닌 다른 환경에서는 실행이 제대로 되지 않을 수도 있으므로, 명시적으로 interpreter를 지정하는 것이 좋습니다.
interpreter = [ "bash" , "-c" ]
# 스크립트를 실행할 작업 디렉토리를 지정합니다. 여기서는 /tmp를 작업 디렉토리로 설정합니다.
working_dir = "/tmp"
environment = {
ENV = "world!!"
}
}
}
remote -exec
- remote-exec와 file 프로비저너를 사용하기 위해 원격지에 연결할 SSH, WinRM 연결 정의가 필요하다
- connection 블록 리소스 선언 시, 해당 리소스 내에 구성된 프로비저너에 대해 공통으로 선언되고, 프로비저너 내에 선언되는 경우, 해당 프로비저너에서만 적용된다.
# connection 블록으로 원격지 연결 정의
resource "null_resource" "example1" {
connection {
type = "ssh"
user = "root"
password = var.root_password
host = var.host
}
provisioner "file" {
source = "conf/myapp.conf"
destination = "/etc/myapp.conf"
}
provisioner "file" {
source = "conf/myapp.conf"
destination = "C:/App/myapp.conf"
connection {
type = "winrm"
user = "Administrator"
password = var.admin_password
host = var.host
}
}
}
원격지 환경에서 실행할 커맨드와 스크립트를 정의
- 아래의 코드는 AWS의 EC2 인스턴스를 생성하고 해당 VM에 접속하여 명령어를 실행하고 패키지를 설치하는 등의 동작 입니다.
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",
]
}
}
사용하는 인수는 다음과 같고 각 인수는 서로 배타적입니다.[같이 쓸수 없음]
– inline
– script
– scripts
4. null resource와 terraform_data
null_resource
- 이런 리소스가 필요한 이유는 테라폼 프로비저닝 동작을 설계하면서 사용자가 의도적으로 프로비저닝하는 동작을 조율해야 하는 상황이 발생하여, 프로바이더가 제공하는 리소스 수명주기 관리만으로는 이를 해결하기 어렵기 때문이다.
- 주로 사용되는 시나리오
- 프로비저닝 수행 과정에서 명령어 실행
- 프로비저너와 함께 사용
- 모듈, 반복문, 데이터 소스, 로컬 변수와 함께 사용
- 출력을 위한 데이터 가공
- 예를 들어 다음의 상황을 가정
- AWS EC2 인스턴스를 프로비저닝하면서 웹서비스를 실행시키고 싶다
- 웹서비스 설정에는 노출되어야 하는 고정된 외부 IP가 포함된 구성이 필요하다. 따라서 aws_eip 리소스를 생성해야 한다.
예를 들어 다음과 같은 상황을 든다고 하면..
- AWS EC2 인스턴스를 프로비저닝하면서 웹서비스를 실행시키고 싶다
- 웹서비스 설정에는 노출되어야 하는 고정된 외부 IP가 포함된 구성이 필요하다. 따라서 aws_eip 리소스를 생성해야 한다.
먼저 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.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}"
]
}
}
#생성된 인스턴스에 탄력적 IP를 할당합니다.
#탄력적 IP를 "172.31.1.100" 프라이빗 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"
}
# 두 리소스의 종속성이 상호 참조되어 발생하는 에러
terraform init
terraform plan
Error: Cycle: aws_eip.myeip, aws_instance.example
Error가 발생하는 이유는 두가지 입니다.
- aws_eip가 생성되는 고정된 IP를 할당하기 위해서는 대상인 aws_instance의 id값이 필요하다
- aws_instance의 프로비저너 동작에서는 aws_eip가 생성하는 속성 값인 public_ip가 필요하다
이 문제를 해결하기 위하여 코드를 수정 합니다. (null_resource사용)
# AWS 프로바이더 설정 및 ap-northeast-2(서울) 리전 사용
provider "aws" {
region = "ap-northeast-2"
}
# 보안 그룹 생성(t101sg라는 이름으로)
resource "aws_security_group" "instance" {
name = "t101sg"
# 인바운드 규칙 설정(one)
# HTTP 접속을 위한 인바운드 규칙 (포트 80 개방)
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# 인바운드 규칙 설정(two)
# SSH 접속을 위한 인바운드 규칙 (포트 22 개방)
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
# AWS EC2 인스턴스 생성
resource "aws_instance" "example" {
ami = "ami-0c9c942bd7bf113a2" # 사용할 인스턴스 이미지 ID 설정
instance_type = "t2.micro" # 인스턴스 유형 설정
subnet_id = "subnet-07fa4fc702e8b566b" # 사용할 서브넷 ID 설정
private_ip = "172.31.0.100" # 인스턴스의 사설 IP 설정
key_name = "kp-min" # Key Pair 설정 , 각자 자신껄로 설정!
vpc_security_group_ids = [aws_security_group.instance.id] # 생성한 보안 그룹 연결 설정
# 사용자 정의 정보 실행
# 시작 시 스크립트를 실행하여 문자열을 index.html 파일에 작성하고, HTTP 서버 구동
user_data = <<-EOF
#!/bin/bash
echo "Hello, T101 Study" > index.html
nohup busybox httpd -f -p 80 &
EOF
# 인스턴스에 태그(Name = Single-WebSrv) 추가
tags = {
Name = "Single-WebSrv"
}
}
# 고정 IP(Elastic IP) 생성 및 인스턴스에 연결
resource "aws_eip" "myeip" {
instance = aws_instance.example.id # 인스턴스 연결 설정 / aws_instance라는 Terraform 리소스를 생성하면, 해당 인스턴스의 ID는 .id를 통해 도출할 수 있습니다.
associate_with_private_ip = "172.31.0.100" # 사설 IP와 연관 설정
}
# 생성된 인스턴스의 고정 IP 출력
resource "null_resource" "echomyeip" {
provisioner "remote-exec" {
#연결
connection {
#고정 퍼블릭 ip로 연결
host = aws_eip.myeip.public_ip
type = "ssh"
user = "ubuntu"
private_key = file("/Users/gasida/.ssh/kp-min.pem") # 사설 키에 대한 경로 설정 , 각자 자신들의 경로
#password = "qwe123" 만약 패스워드로 로그인할시
}
#원격 서버에서 실행할 명령을 정의
inline = [
#EIP(Elastic IP)의 public IP 주소를 출력하는 작업을 수행
"echo ${aws_eip.myeip.public_ip}"
]
}
}
# 인스턴스의 공인 IP 출력
output "public_ip" {
value = aws_instance.example.public_ip
description = "The public IP of the Instance"
}
# 인스턴스의 고정 IP 출력
output "eip" {
value = aws_eip.myeip.public_ip
description = "The EIP of the Instance"
}
# 프로비저너 필요로 설치
terraform plan
===
The following dependency selections recorded in the lock file are inconsistent with the
│ current configuration:
│ - provider registry.terraform.io/hashicorp/null: required by this configuration but no version is selected
│
│ To update the locked dependency selections to match a changed configuration, run:
│ terraform init -upgrade
===
terraform init -upgrade
# 실행 : EIP 할당 전 (임시) 유동 공인 IP 출력
terraform plan
terraform apply -auto-approve
...
null_resource.echomyeip (remote-exec): Connected!
null_resource.echomyeip (remote-exec): 13.125.25.238
...
Outputs:
eip = "3.36.80.43"
public_ip = "43.202.65.66"
#
terraform state list
terraform state show aws_eip.myeip
terraform state show aws_instance.example
terraform state show null_resource.echomyeip
# graph 확인 > graph.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph > graph.dot
# 데이터소스 값 확인
echo "aws_instance.example.public_ip" | terraform console #고정 ip 받기전 유동 ip이다
echo "aws_eip.myeip.public_ip" | terraform console
# 출력된 EC2 퍼블릭IP로 curl 접속 확인
MYIP=$(terraform output -raw eip)
while true; do curl --connect-timeout 1 http://$MYIP/ ; echo "------------------------------"; date; sleep 1; done
==
Tue Jul 18 23:55:50 KST 2023
Hello, T101 Study
------------------------------
Tue Jul 18 23:55:52 KST 2023
Hello, T101 Study
------------------------------
Tue Jul 18 23:55:53 KST 2023
Hello, T101 Study
==
확인 완료되면 terraform destroy -auto-approve 삭제합니다.
terraform_data
- 이 리소스 또한 자체적으로 아무것도 수행하지 않지만 null_resource는 별도의 프로바이더 구성이 필요하다는 점과 비교하여 추가 프로바이더 없이 테라폼 자체에 포함된 기본 수명주기 관리자가 제공된다는 것이 장점이다.
- 사용 시나리오는 기본 null_resourcr와 동일하며 강제 재실행을 위한 trigger_replace와 상태 저장을 위한 input 인수와 input에 저장된 값을 출력하는 output 속성이 제공된다.
- triggers_replace에 정의되는 값이 기존 map 형태에서 tuple로 변경되어 쓰임이 더 간단해졌다
예제
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"
}
5. moved 블록
moved 블록
- 테라폼의 State에 기록되는 리소스 주소의 이름이 변경되면 기존 리소스는 삭제되고 새로운 리소스가 생성됨을 앞서 설명에서 확인했다.
- 하지만 테라폼 리소스를 선언하다 보면 이름을 변경해야 하는 상황이 발생하기도 하는데, 예를 들면 다음과 같다.
- 리소스 이름을 변경
- count로 처리하던 반복문을 for_each로 변경
- 리소스가 모듈로 이동하여 참조되는 주소가 변경
- 리소스의 이름은 변경되지만 이미 테라폼으로 프로비저닝된 환경을 그대로 유지하고자 하는 경우 테라폼 1.1 버전부터 moved 블록을 사용할 수 있다.
- ‘moved’라는 단어가 의미하는 것처럼 테라폼 State에서 옮겨진 대상의 이전 주소와 새 주소를 알리는 역할을 수행한다.
- moved 블록 이전에는 State를 직접 편집하는 terraform state mv 명령을 사용하여 State를 건드려야 하는 부담이 있었다면, moved 블록은 State에 접근 권한이 없는 사용자라도 변경되는 주소를 리소스 영향 없이 반영할 수 있다.
예제 코드입니다
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 will perform the following actions:
# local_file.a has moved to local_file.b
resource "local_file" "b" {
id = "4bf3e335199107182c6f7638efaad377acc7f452"
# (10 unchanged attributes hidden)
}
Plan: 0 to add, 0 to change, 0 to destroy.
#
terraform apply -auto-approve
terraform state list
echo "local_file.b" | terraform console
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
}
6. 시스템 환경 변수
테라폼은 환경 변수를 통해 실행 방식과 출력 내용에 대한 옵션을 조절할 수 있습니다.
- 시스템 환경 변수를 설정하면, 영구적으로 로컬 환경에 적용되는 옵션이나 별도 서버 환경에서 실행하기 위한 옵션을 부여할 수 있다.
- 이를 통해 로컬 작업 환경과 다른 환경 구성에서만 사용될 특정 옵션을 적용한다.
Mac/리눅스/유닉스: export <환경 변수 이름>=<값>
Windows CMD: set <환경 변수 이름>=<값>
Windows PowerShell: $Env:<환경 변수 이름>='<값>'
TF_LOG : 테라폼의 stderr 로그에 대한 레벨을 정의
- trace, debug, info, warn, error, off를 설정할 수 있고 관련 환경 변수가 없는 경우 off와 동일하다
- 디버깅을 위한 로그 관련 환경 변수 설명은 다음과 같다
- TF_LOG: 로깅 레벨 지정 또는 해제
- TF_LOG_PATH: 로그 출력 파일 위치 지정
- TF_LOG_CORE: TF_LOG와 별도로 테라폼 자체 코어에 대한 로깅 레벨 지정 또는 해제
- TF_LOG_PROVIDER: TF_LOG와 별도로 테라폼에서 사용하는 프로바이더에 대한 로깅 레벨 지정 또는 해제
TF_INPUT : 값을 false 또는 0으로 설정하면 테라폼 실행 시 인수에 -input=false 를 추가한 것과 동일한 수행 결과를 확인
- 환경에 맞게 TF_INPUT을 0으로 설정하고 terraform plan 동작 실행하면 입력받는 동작을 수행하지 않으므로 입력 변수를 입력해야 하는 경우 에러가 출력된다
TF_INPUT=0 terraform plan
Error : No value for required variable
TF_VAR_name : TF_VAR_<변수 이름>을 사용하면 입력 시 또는 default로 선언된 변수 값을 대체한다
TF_CLI_ARGS / TF_CLI_ARGS_subcommand : 테라폼 실행 시 추가할 인수를 정의
# TF_CLI_ARGS="-input=false" terraform apply -auto-approve 는 terraform apply -input=false -auto-approve 와 같다
TF_CLI_ARGS="-input=false" terraform apply -auto-approve
Error: No value for required variable
# TF_CLI_ARGS_apply로 인수를 정의하면 terraform apply 커맨드 수행 시에만 동작한다
export TF_CLI_ARGS_apply="-input=false"
terraform apply -auto-approve
<에러>
terraform plan
<정상 계획 예측 출력>
TF_DATA_DIR : State 저장 백엔드 설정과 같은 작업 디렉터리별 데이터를 보관하는 위치를 지정
- 이 데이터는 .terraform 디렉터리 위치에 기록되지만 TF_DATA_DIR에 경로가 정의되면 기본 경로를 대체하여 사용된다.
- 일관된 테라폼 사용을 위해서 해당 변수는 실행 시마다 일관되게 적용될 수 있도록 설정하는 것이 중요하다.
- 설정 값이 이전 실행 시에만 적용되는 경우 init 명령으로 수행된 모듈, 아티팩트 등의 파일을 찾지 못한다.
- 이미 terraform init이 수행된 상태에서 TF_DATA_DIR로 경로를 재지정하고 실행하는 경우 플러그인 설치가 필요하다는 메시지 출력을 확인할 수 있다.
TF_DATA_DIR=./.terraform_tmp terraform plan
Error: Required plugins anr not installed
7. 프로바이더
https://malwareanalysis.tistory.com/619
- 테라폼은 terraform 바이너리 파일을 시작으로 로컬 환경에나 배포 서버와 같은 원격 환경에서 원하는 대상을 호출하는 방식으로 실행된다. 이때 ‘원하는 대상’은 호출하는 방식이 서로 다르지만 대상의 공급자, 즉 프로바이더가 제공하는 API를 호출해 상호작용을 한다. 여기서 테라폼이 대상과의 상호작용을 할 수 있도록 하는 것이 ‘프로바이더’다.
- 각 프로바이더의 API구현은 서로 다르지만 테라폼의 고유 문법으로 동일한 동작을 수행하도록 구현되어 있다. 프로바이더는 플러그인 형태로 테라폼에 결합되어 대상이 되는 클라우드, SaaS, 기타 서비스 API를 사용해 동작을 수행한다. 각 프로바이더는 테라폼이 관리하는 리소스 유형과 데이터 소스를 사용할 수 있도록 연결한다.
- 즉, 테라폼은 프로바이더 없이는 어떤 종류의 인프라와 서비스도 관리할 수 없다는 의미다. 대부분의 프로바이더는 대상 인프라 환경이나 서비스 환경에 대한 리소스를 관리하므로, 프로바이더를 구성할 때는 대상과의 연결과 인증에 필요한 정보가 제공되어야 한다.
- 각 프로바이더는 테라폼 실행 파일과는 별도로 자체 관리되고 게시된다. 테라폼 레지스트리 사이트에서 주요 프로바이더와 관련 문서를 확인 가능 합니다.
- https://registry.terraform.io/browse/providers <-프로바이더와 관련 링크 입니다.