T101-3주차 [Terraform 101 Study]

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 리소스를 생성해야 한다.

예를 들어 다음과 같은 상황을 든다고 하면..

  1. AWS EC2 인스턴스를 프로비저닝하면서 웹서비스를 실행시키고 싶다
  2. 웹서비스 설정에는 노출되어야 하는 고정된 외부 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 <-프로바이더와 관련 링크 입니다.

위로 스크롤