Ssoon

Chapter (03) 기본 사용법 - HCL - 조건식 / 함수 / 프로비저너 본문

Terraform 101 Study 2기

Chapter (03) 기본 사용법 - HCL - 조건식 / 함수 / 프로비저너

구구달스 2023. 7. 10. 23:39
CloudNet@ 가시다님이 진행하는 Terraform 101 Study 2기
"테라폼으로 시작하는 IaC" (한빛미디어) 도서로 진행!

✅ 조건식

  • 조건식은 3항 연산자 형태
  • 조건은 true 또는 false 로 확인되는 모든 표현식을 사용
<조건 정의> ? <옳은 경우> : <틀린 경우>
var.a != "" ? var.a : "default-a"
  • 조건식 형태 권장사항
var.example ? 12 : "helle"	#비권장
var.example ? "12" : "hellos 	#권장
var.example ? tostring(12) : "hello"	#권장

 main.tf -  조건식과 count 를 조합해 resource 생성 여부 결정

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: ""
}

✅ 함수

  • 값의 유형을 변경, 조합할 수 있는 내장 함수를 지원하지만 별도의 사용자 정의 함수를 지원하지 않습니다.
  • 함수를 적용하면 변수, 리소스 속성, 데이터 소스 속성,  출력 값 표현 시 작업을 동적이고 효과적으로 수행할 수 있습니다.

 main.tf -  upper 함수 사용

resource "local_file" "foo" {
  content = upper("foo!")
  filename = "${path.module}/foo.bar"
}

✔ terraform console

  • > 에 원하는 값을 넣어 함수를 테스트할 수 있습니다.

✅ 프로비저너

  • 프로바이더로 실행되지 않는 커맨드와 파일 복사 같은 역활 수행
  • 프로비저너로 실행된 결과는 테라폼의 상태 파일과 동기화되지 않습니다 -> 프로비저닝의 결과가 항상 같다고 보장할 수 없습니다. -> 프로비저너의 사용을 최소화
  • 프로비저너의 종류에는 file, local-exec, remote-exec 가 있습니다.

🧿 프로비저너 사용 방법

  • 리소스 프로비저닝 이후 동작하도록 구성할 수 있습니다.

 main.tf -  local_file 리소스 내 provisioner 블록 선언

variable "sensitive_content" {
  default = "sevret"
  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}"
  }
}
  • 프로비저너는 선언된 블록의 작업이 종료되고 지정된 작업을 순서대로 수행합니다.
  • self 값에 대한 참조가 가능 -> 리소스 프로비저닝 작업 후 해당 속성 값들을 참조
  • terraform apply 를 통해 프로비저너의 동작을 확인할 수 있습니다.

  • Provisioning with 'local-exec'... : content 를 출력
  • (output suppressed due to sensitive value in config) :  원하는 출력이 보이지 않습니다.  (sensitive = true)
  • Executing: ["cmd" "/C" "abc"] : abc 커맨드를 실행합니다.
  • 'abc' is not recognized as an internal or external command, :  abc라는 커맨드는 없으므로 apply는 실패해야 하지만
  • on_failure = continue 선언으로 실패 시에도 다음 단계로 넘어갑니다.

 2번째 provisioner -  on_failure = continue 를 주석처리

  provisioner "local-exec" {
    command = "abc"
    on_failure = continue
  }

3번째 provisioner - when = destroy

  • terraform destroy 수행할 때에만 정보를 출력합니다.
  provisioner "local-exec" {
    command = destroy
    on_failure = "echo the deleting filename is ${self.filename}"
  }
}

🧿 local-exec 프로비저너

  • local-exec 는 테라폼이 실행되는 환경에서 수행할 커맨드를 정의합니다.
  • 인수 값
    • command(필수) : 실행할 명령줄 입력, << 연산자를 통해 여러 줄의 커맨드 입력 가능
    • working_dir(선택) : command 명령을 실행할 디렉터리 지정, 상대/절대 경로 설정
    • interpreter(선택) : 명령을 실행하는 데 필요한 인터프리터 지정, 첫 번째 인수는 인터프리터 이름이고 두 번째부터는 인터프리터 인수 값
    • environment(선택) : 실행 시 환경 변구는 실행 환경의 값을 상속, 추가 또는 재할당하려는 경우 해당 인수에 key = value 형태로 설정

 main.tf - 작업 한경에 따라 각 인수 값을 활용

  • command = << : 다중 라인의 명령을 수행
  • interpreter = [ : 각 환경에 맞는 인터프리터 지정
  • working_dir = "/tmp" : 명령의 실행 위치를 지정
  • environment = { : 환경 변수
resource "null_resource" "example1" {
  provisioner "local_exec" {
    command = <<EOF
      echo Hello! > file.txt
      echo $ENV >> file.txt
      EOF
    
    interpreter = ["bash", "-c"]

    working_dir = "/tmp"

    environment = {
      ENV = "world!"
    }
  }
}

🧿  원격지 연결

  • remote-execfile 프로비저너를 사용하기 위해서는 원격지 연결할 SSH.WinRM 연결 정의가 필요합니다.

 main.tf - 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 = "/etx/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
    }
  }
}
  • connection 적용 인수 
인수 연결 타입 설명 기본값
type SSH/WinRM 연결 유형 ssh
user SSH/WinRM 연결에 사용되는 사용자 ssh: root
winrm : Administrator
password SSH/WinRM 연결에 사용되는 비밀번호  
host SSH/WinRM (필수) 연결 대상 주소  
port SSH/WinRM 연결 대상의 타입별 사용 포트 ssh : 22
winrm : 5985
timeout SSH/WinRM 연결 시도에 대한 대기 값 5m

🧿 file 프로비저너

  • 테라폼을 실행하는 시스템에서 연결 대상으로 파일 또는 디렉터리를 복사하는 데 사용합니다.
  • source
    • 소스 파일 또는 디렉터리
    • 현재 작업중인 디렉터리에 대한 상대 경로 또는 절대 경로로 지정
    • content와 함께 사용할 수 없음
  • content
    • 연결 대상에 복사할 내용을 정의
    • 대상이 디렉터리인 경우 tf-file-content 파일이 생성, 파일인 경우 해당 파일에 내용이 기록
    • source와 같이 사용할 수 없음
  • destination 
    • 필수 항목으로 항상 절대 경로로 지정
    • 파일 또는 디렉터리
    • ssh 연결  -> 대상 디렉터리가 존재해야 함
    • winrm 연결 -> 자동으로 생성
    • /tmp -> source가 디렉터리로 
      • /foo 처럼 마지막에 /가 없는 경우 -> 대상 디렉터리에 지정한 디렉터리가 업로드 -> 연결 시스템에 /tmp/foo 디렉터리가 업로드
      • /foo/ 처럼 마지막에 /가 포함되는 경우 -> source 디렉터리 내의 파일만 /tmp 디렉터리에 업로드

 main.tf - 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"
  }

  # configs.d 디렉터리가 /etc/configs.d 로 업로드
  provisioner "file" {
    source = "conf/configs.d"
    destination = "/etc"
  }
 
  # apps/app1 디렉터리 내의 파일들만 D:/IIS/webapp1 디렉터리 내에 업로드
  provisioner "file" {
    source = "apps/app1/"
    destination = "D:/IIS/webapp1"
  }

🧿 remote-exec 프로비저너

  • 원격지 환경에서 실행할 커맨드와 스크립트 정의
  • inline
    • 명령에 대한 목록
    • [ ] 블록 내에 " " 로 묶인 다수의 명령을 , 로 구분해 구성
  • script
    • 로컬의 스크립트 경로를 넣고 원격에 복사해 실행
  • scripts
    • 로컬의 스크립트 경로의 목록으로 [ ] 블록 내에 " " 로 묶인 다수의 스크립트 경로를 , 로 구분해 구성

 main.tf - file 프로비저너 구성

resource "aws_instance" "web" {
  ...

  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".
    ]
  }
}

 

Comments