HCL (hashicorp configuration language)
- IaC는 수동 프로세스가 아닌 코드를 통해 인프라를 관리하고 프로비저닝 하는 것을 의미
- 테라폼에서 HCL이 코드의 영역을 담당한다. HCL은 쉽게 읽을 수 있고 빠르게 배울 수 있는 언어의 특징을 가짐
- 인프라가 코드로 표현되고, 이 코드는 곧 인프라이기 때문에 선언적 특성을 갖게 되고 Turing-complete 언어적 특성을 갖는다.
- 즉, 일반적인 프로그래밍 언어의 조건문 처리 같은 동작이 가능하다. 자동화와 더불어, 쉽게 버전이해 히스토리를 관리하고 협업이 가능한 기반을 제공한다.
Terraform 블록
테라폼 구성을 명시하는 데 사용
테라폼 버전이나 프로바이더 버전과 같은 값들은 자동 설정되지만, 함께 작업할 대는 버전을 명시적으로 선언하고,
필요한 조건을 입력하여 실행 오류를 최소화 할 것을 권장
terraform {
required_version = "~> 1.3.0" # terraform version
required_providers { # provider version list
random = {
version = ">= 3.0.0, < 3.1.0"
}
aws = {
version = "4.2.0"
}
}
cloud { # cloud/Ent 같은 원격 실행을 위한 정보
organaization = "<MY_ORG_NAME>"
workspaces {
name = "my-first-workspace"
}
}
backend "local" { # state를 보관하는 위치를 지정
path = "relative/path/to/terraform.tfstate"
}
}
테라폼 내에서 버전이 명시되는 terraform, mudule에서 사용 가능하며, 버전에 대한 제약을 둠으로 관련 리소스가 의도한 정의대로 실행되는 것을 목적으로 한다.
버전 체계는 시맨틱 버전 관리 Semantic Versioning 방식을 따른다.
# version = Major.Minor.Patch
version = 1.2.3
테라폼 버전 관리로 비유된 선언 방식의 의미
선언 버전 | 의미 |
1.0.0 | 테라폼 v1.0.0만을 허용한다. |
>= 1.0.0 | 테라폼 v1.0.0 이상의 모든 버전을 허용한다. |
~> 1.0.0 | 테라폼 v1.0.0을 포함한 v1.0.x 버전을 허용하고 1.x는 허용하지 않는다. |
>= 1.0, < 2.0.0 | 테라폼 v1.0.0 이상 v2.0.0 미만인 버전을 허용한다. |
Required_version 실습
case 1)
terraform 1.8.5 가 설치된 환경에서 < 1.0.0 이 선언된 terraform 코드를 배포하자.
terraform {
required_version = "< 1.0.0"
}
resource "local_file" "abc" {
content = "abc!"
filename = "${path.module}/abc.txt"
}
init을 통해 배포를 해보면 아래와 같이 버전에 대한 오류가 발생한다.
코드 상에서 1.0.0 미만의 테라폼을 허용하도록 했으니, 1.8.5 환경에서 실행했을 때 오류가 나는 것이 당연하다.
case 2)
terraform 버전 선언을 >= 1.0.0으로 변경하고 init을 해보자.
terraform {
required_version = ">= 1.0.0"
}
resource "local_file" "abc" {
content = "abc!"
filename = "${path.module}/abc.txt"
}
terraform 1.8.5 환경이기 때문에 조건이 충족하므로 정상적으로 init이 된다.
Terraform 리소스 블럭
리소스 블럭은 선언된 항목을 생성하는 동작을 수행한다.
리소스는 프로바이더에 종속성을 가지고 있다.
# main.tf
resource "local_file" "abc" {
content = "123"
filename = "${path.module}/abc.txt"
}
resource "aws_instance" "web" {
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
}
terraform init 시 자동으로 인식된 프로바이더를 찾으며 진행된다.
리소스 동작 보조 추가 메타인수
- depends_on : 종속성을 선언하며, 선언된 구성요소와의 생성 시점에 대해 정의
- count : 선언된 개수에 따라 여러 리소스를 생성
- for_each : map 또는 set 타입의 데이터 배열의 값을 기준으로 여러 리소스를 생성
- provider : 동일한 프로바이더가 다수 정의되어 있는 경우 지정
- lifecycle : 리소스의 수명주기 관리
- provisioner : 리소스 생성 후 추가 작업 정의
- timeouts : 프로바이더에서 정의한 일부 리소스 유형에서는 create, update, delete에 대한 허용 시간 정의
종속성
- 테라폼 종속성은 resource, module 선언으로 프로비저닝되는 각 요소의 생성 순서를 구분한다.
- 기본적으로 생성 순서에 따라 자동으로 연관 관계가 정의되고,
강제로 리소스 간 명시적 종속성을 부여할 경우에는 메타인수인 depends_on을 활용한다.
(terraform docs)
종속성 실습
case 1) 선후 관계가 없는 2개 리소스 생성
resource "local_file" "abc" {
content = "123!"
filename " "${path.module}/abc.txt"
}
resource "local_file" "def" {
content = "456!"
filename " "${path.module}/def.txt"
}
apply 수행 과정을 보면 abc, def 두개 파일이 동시에 생성되는 것을 확인할 수 있다.
선후관계와 종속성이 없기 때문에 동시에 생성되는 것이다.
case 2) 리소스 참조값을 주어 암시적 종속성 부여
resource "local_file" "abc" {
content = "123!"
filename = "${path.module}/abc.txt"
}
resource "local_file" "def" {
content = local_file.abc.content # 123!
filename = "${path.module}/def.txt"
}
코드에 def가 abc를 참조하도록 설정되어 있기 때문에 동시 생성이 아닌 abc를 생성하고,
그 값을 참조하여 def가 생성되는 것을 확인할 수 있다.
graph로 확인하면 아래와 같이 의존성이 잡혀있는 것도 확인할 수 있다.
case 3)
리소스 속성을 주입하지 않지만, 종속성이 필요한 경우
메타인수 depends_on을 통해 종속성 지정
resource "local_file" "abc" {
content = "123!"
filename = "${path.module}/abc.txt"
}
resource "local_file" "def" {
depends_on = [
local_file.abc
]
content = "456!"
filename = "${path.module}/def.txt"
}
파일이 순차로 생성되었고, 종속성은 지정했지만 콘텐츠는 참조하지 않으므로 각 콘텐츠 파일 내용 표시된다.
depends_on 설정으로 종속성도 지정되어 있는 것을 확인할 수 있다.
리소스 속성 참조
- 리소스 구성에서 참조 가능한 값은 인수와 속성이다.
- 인수 : 리소스 생성 시 사용자가 선언하는 값
- 속성 : 사용자가 설ㅈ어하는 것은 불가능하지만 리소스 생성 이후 획득 하능한 리소스 고유 값
- 리소스 인수의 선언과 참조 가능한 인수 및 속성 패턴
# Terraform Code
resource "<리소스 유형>" "<이름>" {
<인수> = <값>
}
# 리소스 참조
<리소스 유형>.<이름>.<인수>
<리소스 유형>.<이름>.<속성>
ex)
k8s의 namespace와 secret을 생성하는 예제이다.
namespace를 먼저 생성하고, secret은 인수 참조 값에 따라 상단에 선언된 네임스테이스에 secret을 생성하게 된다.
당연하게 namespace의 이름을 변경하고 배포하면, 종속되어 있는 모든 리소스가 업데이트된다.
resource "kubernetes_namespace" "example" {
metadata {
annotations = {
name = "example-annotation"
}
name = "terraform-example-namespace"
}
}
resource "kubernetes_secret" "example" {
metadata {
namespace = kubernetes_namespace.example.metadata.0.name # namespace 리소스 인수 참조
name = "terraform-example"
}
data = {
password = "P4ssw0rd"
}
}
- 리소스가 생성될 때, 사용자가 입력한 ‘인수’를 받아 실제 리소스가 생성되면 일부 리소스는 자동으로 기본값이나 추가되는 ‘속성’이 부여된다.
- 리소스 속성을 참조하는 다른 리소스 또는 구성요소에서는 생성 후의 속성 값들도 인수로 가져올 수 있다.
Lifecycle
Lifecycle은 리소스의 기본 수명주기를 작업자가 의도적으로 변경하는 메타인수다.
메타인수 내에는 아래 선언이 가능하다.
- create_before_destroy (bool) : 리소스 수정 시 신규 리소스를 우선 생성하고 기존 리소스를 삭제
- prevent_destroy (bool) : 해당 리소스를 삭제 Destroy 하려 할 때 명시적으로 거부
- ignore_changes (list) : 리소스 요소에 선언된 인수의 변경 사항을 테라폼 실행 시 무시
- precondition : 리소스 요소에 선언해 인수의 조건을 검증
- postcondition : Plan과 Apply 이후의 결과를 속성 값으로 검증
[각 메타인수 예제]
create_before_destory : 기본적으로 테라폼의 수명주기는 삭제 후 재생성이므로 운영 환경의 리소스 재배포 시
장애를 유발할 수 있으나, create_before_destory 메타인수를 통해 생성 후 삭제로 수정된 리소스를 먼저 생성할 수 있다.
단, 생성되는 리소스가 기존 리소스로 인해 생성이 실패되거나 삭제 시 함께 삭제될 수 있으므로 유의해야 한다.
resource "local_file" "abc" {
content = "lifecycle - step 1"
filename = "${path.module}/abc.txt"
lifecycle {
create_before_destroy = false
}
}
첫 배포 수행 시 정상적으로 파일이 생성되는 것을 확인
컨텐츠 내용 수정 후 재배포
resource "local_file" "abc" {
content = "lifecycle - step 111111"
filename = "${path.module}/abc.txt"
lifecycle {
create_before_destroy = false
}
}
재배포 시 false 옵션으로 인해 기본 수명주기 정책에 따라 삭제 후 재생성으로 파일 생성 진행
옵션 값 및 콘텐츠 수정 후 재배포
resource "local_file" "abc" {
content = "lifecycle - step 2"
filename = "${path.module}/abc.txt"
lifecycle {
create_before_destroy = true
}
}
배포는 오류 없이 정상적으로 되었으나, 실제 확인 시 abc.txt 파일이 없는 것이 확인된다.
이유는 리소스 네임이 같기 때문에 create가 진행되고 destroy 했을 때 삭제가 되버린 것이다.
이 상태에서 다시 apply를 하면 아래와 같이 파일이 재생성되는 것을 확인할 수 있다.
여러 사용 방법이 있겠지만, 일반적으로 ASG 설정 시 사용이 권장된다.
ASG 설정에서 false 인 경우 기존 instance가 삭제되고, 새로운 instance가 생성되기 때문에,
새로운 instance가 ready 상태가 되기 전까지 트래픽이 찾아갈 길이 없기 때문에 장애가 발생한다.
반대로 True 인 경우 새로운 instance가 ready가 될때 까지 기존 instance가 live되기 때문에
서비스에 영향이 발생하지 않는다.
prevent_destroy : 리소스 삭제 시 명시적으로 거부하는 옵션이다.
옵션을 true로 설정하고, apply 수행 시 옵션 값의 영향으로 삭제가 거부된다.
resource "local_file" "abc" {
content = "lifecycle - step 3"
filename = "${path.module}/abc.txt"
lifecycle {
prevent_destroy = true
}
}
정상적으로 삭제하고 싶다면 false로 변경하거나, 메타인수를 제거하면 정상적으로 삭제가 수행된다.
ignore_changes (list) : 리소스 요소에 선언된 인수의 변경 사항을 apply 시 무시
예제 코드 배포 및 파일 생성 확인
resource "local_file" "abc" {
content = "lifecycle - step 4"
filename = "${path.module}/abc.txt"
lifecycle {
ignore_changes = []
}
}
ignore 대상 설정 코드 적용 후 배포 수행
resource "local_file" "abc" {
content = "lifecycle - step 5"
filename = "${path.module}/abc.txt"
lifecycle {
ignore_changes = [
content
]
}
}
content가 변경되지 않도록 설정되었기 때문에 파일 역시 재생성 또는 수정이 되지 않는 것을 확인할 수 있다.
precondition : pre라는 단어가 들어있듯 리소스 생성 전에 검증을 하는 방식으로 조건에 맞지 않는다면,
자원이 생성되지 않는다.
예제 코드에 파일 이름 step0.txt를 변수로 지정하고 precondition에 환경 변수를 step6.txt로 설정하였다.
terraform apply 시 precondition 검증 단계에서 변수의 파일 이름이 다르기 때문에 에러 메시지를 발생 시킨다.
variable "file_name" {
default = "step0.txt"
}
resource "local_file" "abc" {
content = "lifecycle - step 6"
filename = "${path.module}/${var.file_name}"
lifecycle {
precondition {
condition = var.file_name == "step6.txt"
error_message = "file name is not \"step6.txt\""
}
}
}
postcondition : post라는 단어와 같이 생성 후 검증으로 검증에 실패할 경우 다른 리소스에서 참조할 수 없도록 제한한다.
postcondition의 조건은 self.content가 공백일 경우에 에러를 발생 시킨다는 조건을 가지고 있다.
resource 블럭의 content가 공백이기 때문에 terraform apply 시 에러가 발생하는 것을 확인할 수 있다.
resource "local_file" "abc" {
content = ""
filename = "${path.module}/step7.txt"
lifecycle {
postcondition {
condition = self.content != ""
error_message = "content cannot empty"
}
}
}
output "step7_content" {
value = local_file.abc.id
}
아래와 같이 content에 문자열을 입력하고 배포했을 때 조건에 충족되므로 파일이 정상적으로 생성되는 것을 확인할 수 있다.
resource "local_file" "abc" {
content = "step7 file ok"
filename = "${path.module}/step7.txt"
lifecycle {
postcondition {
condition = self.content != ""
error_message = "content cannot empty"
}
}
}
output "step7_content" {
value = local_file.abc.id
}
1주차 회고
이런 스터디가 매우 오랜만이고, 테라폼을 거의 안썼기 때문에 이래저래 이해하는데 애를 먹었다.
그래도 생각보다 재미있고, 도움이 된다는 느낌을 크게 받아 열심히 참여하기 위해 노력하려 한다.
스터디 이후에도 테라폼을 유연하게 사용할 수 있도록 이어나갈 예정이다.
이외 실습들은 개인적으로 1주차 정리와 별개로 부록의 개념으로 추가해야겠다.
'Cloud > Terraform' 카테고리의 다른 글
[T101] Terraform 101 Study 2주차 (3) (0) | 2024.06.22 |
---|---|
[T101] Terraform 101 Study 2주차 (2) (0) | 2024.06.21 |
[T101] Terraform 101 Study 2주차 (1) (0) | 2024.06.18 |
[T101] Terraform 101 Study 1주차 (2) (0) | 2024.06.10 |
[T101] Terraform 101 Study 1주차 (1) (0) | 2024.06.10 |