Terraform 기초 실습 스터디를 진행하고 있으며, 커리큘럼 1주차에 해당하는 내용입니다.
* [테라폼으로 시작하는 IaC] 도서 참조
이전 포스팅에서 테라폼 실행 환경을 세팅하였다. 이제 테라폼을 시작하는 방법을 알아보자.
AWS 리소스 생성하기, 쿠버네티스 구성하기, Active Directory 계정 생성 등의 예제를 구현하기에 앞서, 테라폼이 IaC 를 구현하는 '코드'적인 속성과 환경을 기본기부터 이해하는 방향으로 진행한다.
주요 커맨드
커맨드 사용법을 익히기 위해 03.start 라는 디렉토리를 생성하고, main.tf 파일을 다음과 같이 생성하였다.
- "local_file" 은 테라폼의 local 프로바이더로 파일을 프로비저닝하는 데 사용된다.
- $(path.module) 은 실행되는 테라폼 모듈의 파일 시스템 경로이며, 예제에서는 03.start 디렉토리 경로이다.
주요 커맨드 1. init
terraform init : 테라폼 구성 파일이 있는 작업 디렉토리를 초기화하는데 사용된다. 이 작업을 실행하는 디렉토리를 루트 모듈이라고 칭하며, 테라폼 코드 정의를 위한 파일 집합에 해당된다. (상세 내용 추가)
$ terraform init
해당 커맨드를 실행하면, 필요한 프로바이더 플러그인을 찾고 설치하는 과정이 실행된다.
추가로 프로바이더, 모듈, 백엔드 구성이 설정 및 변경되는 경우에도 이 명령을 수행해야된다.
-upgrade : 0.14 버전 이후부터 init 실행 시, 프로바이더 종속성을 고정시키는 .terraform.lock.hcl 파일이 추가된다. 해당 파일에 프로바이더, 모듈의 버전 정보가 기입되며, 다른 작업자가 해당 프로젝트를 리모트 환경에서 init 수행 시 해당 파일에 명시된 버전으로 수행한다.
의도적으로 버전 변경이 필요할 때, terraform init -upgrade 를 수행해야 한다.
주요 커맨드 2. validate
terraform validate : 단어 의미 그대로 디렉토리에 있는 테라폼 구성 파일의 유효성을 확인한다. 이때 생성된 인프라 리소스에 대한 API 작업은 발생하지 않고, 코드적인 유효성만 검토한다. (코드 구성의 문법, 종속성, 속성 이름이나 연결된 값의 타당성 확인)
$ terraform validate
local_file 리소스 정의에 필수 인수 값인 filename 을 주석처리하여 확인해보자.
필수 인수 값이 정의되어있지 않기 때문에, 에러 메시지가 출력되는 것을 확인할 수 있다.
-no-color, -json 과 같은 옵션을 추가하여, 다음과 같이 확인할 수 있다.
주요 커맨드 3. plan & apply
teraform plan : 테라폼으로 적용할 인프라 리소스의 변경 사항에 관한 실행 계획을 생성하는 동작이다. 또한 출력되는 결과를 확인하여 실제 적용 전 미리 변경 사항에 대해 검토할 수 있다.
terraform apply : plan 을 기반으로 리소스 적용 작업을 실행한다.
$ terraform plan
$ terraform apply
실행 계획을 살펴보면, 코드 구성에서는 local_file 리소스 정의의 필수 요소인 content 와 filename 만 선언했지만, 리소스에 정의 가능한 다른 옵션의 내용이 자동 입력되어 적용되는 것을 확인할 수 있다. (이를 통해 특정 리소스를 생성할 때, 어떤 값이 기본값으로 설정되는지 파악할 수 있다.)
Plan: 1 to add, 0 to change, 0 to destory 를 통해, 하나의 리소스가 추가되고, 변경 및 삭제되는 것은 없는 것을 확인 가능하다.
바로 terraform apply 를 실행할 수 있지만, 실행 계획 파일(tfplan)을 별도로 작성해보자.
$ terraform plan -out=tfplan
tfplan 이라는 이름은 임의로 작성하였고, 다른 이름으로 대체가능하다. 해당 파일은 바이너리 형태이므로 내용 확인은 불가하다.
tfplan 실행계획 확인 후, terraform apply 를 실행하면 적용여부를 묻지 않고, 즉시 적용하는 것을 확인할 수 있다.
테라폼의 멱등성 : 동일한 구성에 대해서는 apply 단계에서 다시 실행 작업이 수행되지 않는다.
(No changes. Your infrastructure matches the configuration.)
terraform apply 명령으로 운영 리소스를 생성하기 전, terraform validate 와 terraform plan 을 먼저 실행해 변경 사항 적용 전에 검증 및 승인하는 단계를 꼭 거치는 것을 권장한다.
-replace : 기 생성된 특정 리소스 재생성 옵션으로 대상 리소스 주소를 지정하여 사용한다. plan 과 apply 커맨드 모두 적용 가능하다.
주요 커맨드 4. destroy
terraform destroy : 테라폼 구성에서 관리하는 모든 개체를 제거하는 명령어.
(테라폼 코드로 구성된 리소스의 일부만 제거하기 위해서는, 삭제하려는 항목을 코드에서 제거하고, 다시 terraform apply 를 실행하는 방법으로 수행한다.)
$ terraform destroy
$ terraform apply -destroy # 둘 다 동일한 명령어
terraform plan -destroy 로 미리 확인하고, terraform apply -destroy 수행 및 terraform destroy 수행이 가능하다.
-auto-approve : 사전 실행 계획(tfplan)이 없을 때, 사용자에게 승인 요청 없이 자동 승인 기능을 부여하는 옵션
주요 커맨드 5. fmt
terraform fmt : format 의 줄임 표시로 테라폼 구성 파일에 작성된 테라폼 코드의 가독성을 높이는 작업에 사용된다. 보통 코드 협업 과정에서 각 작업자별로 코드 작성에 쓰인 정렬, 들여쓰기 등 규칙이 다른 경우에 유용하다.
git 에 업로드 하기 전에, 해당 커맨드를 수행하면 작업자간 스타일의 차이로 생긴 코드 중복 처리가 가능하여, 업데이트를 최소화할 수 있다.
$ terraform fmt
적용된 대상 파일이 목록에 표시된다. (-recursive 옵션: 하위 디렉토리의 구성파일을 모두 포함해 적용)
HCL
HCL(HashiCorp configuration language) 는 하시코프사에서 IaC와 구성 정보를 명시하기 위해 개발되 오픈 소스 도구이다.
테라폼에서는 HCL 이 코드의 영역을 담당하며, 이 코드는 인프라이기 때문에 선언적 특성을 갖는다.
또한, 일반적인 프로그래밍 언어의 조건문 처리 같은 동작이 가능한 것이 특징이다.
HCL 표현식
- 주석 표기
- 변수 정의
- 프로그래밍적 연산
- function 제공
- 테라폼으로 인프라를 구성하기 위한 선언 블록
- terraform 블록
- resource 블록
- data 블록
- variable 블록
- local 블록
- output 블록
테라폼 블록
테라폼 구성을 명시하는데 사용된다.
테라폼 버전이나 프로바이더 버전과 같은 값들은 자동으로 설정되지만, 협업을 위한 관점으로 확장할 경우, 테라폼 구성 정보를 명확하게 정의해야 오류를 방지할 수 있다.
테라폼 버전 관리 방식
테라폼 블록 1. 테라폼 버전
테라폼 버전은 지정된 조건과 일치하지 않는 경우 오류를 출력하고, 이후 동작을 수행하지 않는다.
현재 사용자의 테라폼 버전을 확인해보자.
required_version 으로 제어되는 버전 제한을 확인하기 위해, main.tf 에 terraform 블록을 추가하고
앞서 확인한 버전보다 낮은 조건으로 선언해보자.
terraform init 명령을 수행하면, 버전 조건에 맞지 않아 에러가 발생하는 것을 확인할 수 있다.
실행 환경에 맞는 버전으로 조건을 변경하고, 다시 terraform init 을 수행해보자.
테라폼 버전 조건을 통과하여, 정상 동작되는 것을 확인할 수 있다.
테라폼 블록 2. 프로바이더 버전
terraform 블록의 required_providers 에 정의한다.
각 프로바이더(ex, AWS, Azure..) 의 이름에 소스 경로와 버전을 명시하며, 테라폼 레지스트리 공식 페이지에서 샘플 코드를 확인할 수 있다.
프로바이더 버전 동작을 확인하기 위해, terraform 블록에 required_providers 값을 추가해보자.
의도적으로 현재 실행되는 프로바이더 버전보다 과하게 높게 설정하여 확인해보자.
실제 가용한 버전의 프로바이더가 존재하지 않아 init 은 실패한다.
올바른 버전 제한을 선언하면, 정상적으로 terraform init -upgrade 가 적용되는 것을 확인할 수 있다.
테라폼 블록 3. cloud 블록
Terraform Cloud, Terraform Enterprise 는 CLI, VCS, API 기반의 실행 방식을 지원하고 cloud 블록 으로 선언한다.
(현재 테스트 환경은 테라폼 제공 환경 중 On-premise 환경에서 사용자의 컴퓨팅 환경에 terraform 을 세팅하여 사용하고 있기 때문에, 해당 내용은 넘어가겠다.)
테라폼 블록 4. 백엔드 블록
백엔드 블록의 구성은 테라폼 실행 시 저장되는 State (상태 파일) 의 저장 위치를 선언한다.
주의할 점은 하나의 백엔드만 허용한다는 점이다.
테라폼은 State 의 데이터를 사용해 ㅁ코드로 관리된 리소스를 탐색하고 추적한다. 작업자 간의 협업을 고려한다면 테라폼으로 생성한 리소스의 State 파일을 공유할 수 있는 외부 백엔드 저장소가 필요하다. (ex. S3 bucket..)
State 잠금 동작
기본적으로 활성화되는 백엔드는 local 이다.
공유되는 백엔드에 State 가 관리되면 테라폼이 실행되는 동안 .terraform.tfstate.lock.info 파일이 생성되면서 해당 State 를 동시에 사용하지 못하도록 잠금 처리를 한다.
테라폼 코드(content 내용)를 수정 및 저장하고 다음과 같이 확인해보자.
VSCode 에서 터미널을 2개의 창으로 세팅하고, 첫번째 창에서 terraform apply 를 실행만 하고, 'yes' 를 입력하지 않은 상태에서 대기한다.
그리고 두번째 창에서도 terraform apply 를 실행한다.
동시에 동일한 State 에 접근이 발생하여, 잠금 파일의 내용이 표기되면서 에러가 발생함을 확인할 수 있다.
(-lock=false 옵션을 사용하여 잠금을 무시할 수도 있지만, 다른 작업이 수행 중일 수 있으므로 주의해야한다.)
백엔드 설정 변경
백엔드가 설정되면 다시 init 명령을 수행해 State 의 위치를 재설정해야 한다.
백엔드 블록에 local 을 정의하여 terraform init 을 수행해보자.
백엔드 설정이 init 되면, 백엔드 정보를 테라폼이 내부 메타데이터에 기록한다는 것을 의미한다.
새로운 백엔드로의 전환을 위해 두가지 옵션 조건이 있다.
- 이전 구성 유지: -migrate-state
- 새로 초기화: -reconfigure
백엔드를 전환하는 것은 State 관리가 되는 저장소를 선택하는 것과 같다.
local 백엔드 외에도 다양한 저장공간이 있지만, 현재 업무를 수행하는 프로젝트에서는 Amazon S3 에 저장하여 관리하고 있다.
이러한 설정 구성은 추후에 세팅해보도록 하자.
리소스(resource)
리소스는 테라폼이 프로비저닝 도구라는 측면에서 가장 중요한 요소이다. 리소스 블록은 선언된 항목을 생성하는 동작을 수행한다.
리소스 블록의 설명, 동작 방식, 메타데이터를 확인해보자.
리소스(resource) 1. 리소스 구성
리소스 블록은 resource 로 시작한다. 이후 리소스 블록이 생성할 '리소스 유형' 을 정의한다.
리소스 선언 방식은 다음과 같다.
- 리소스 유형에서 _ 를 기준으로 앞은 프로바이더 이름, 뒤는 프로바이더에서 제공하는 리소스 유형을 의미. 따라서 해당 리소스의 유형이 어떤 프로바이더가 제공하는 것인지 앞의 이름으로 알 수 있다.
- 리소스 유형이 선언되면 뒤에는 고유한 이름을 붙인다. 리소스 유형이 같은 경우에는 동일한 이름을 사용할 수 없다.
- 이름 뒤에는 리소스 유형에 대한 구성 인수들이 중괄호 내에 선언된다. 리소스 유형에 따라 인수가 필요하지 않은 경우도 있지만, 중괄호는 입력한다.
resource "<리소스 유형>" "<이름>" {
<인수> = <값>
}
resource "aws_instance" "web" {
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
}
resource "local_file" "abc" {
content = "123456!"
filename = "${path.module}/abc.txt"
}
리소스 유형은 프로바이더에 종속성을 갖는다.
특정 프로바이더의 유형만 추가해도 terraform init 을 수행하면 해당 프로바이더를 설치한다.
aws_instance 리소스 유형을 추가하고 init 수행 시 AWS 프로바이더 선언 없이도, AWS 프로바이더가 설치되는 것을 확인할 수 있다.
리소스 동작을 보조하기 위한 추가 메타인수. 각 요소는 추후 상세히 살펴보자
(timeouts 을 제외하고 모든 리소스 정의에 추가 가능)
- depends_on
- count
- for_each
- provider
- lifecycle
- provisioner
- timeouts
리소스(resource) 2. 종속성
테라폼의 종속성은 resource, module 선언으로 프로비저닝되는 각 요소의 생성 순서를 구분짓는다.
- 암시적 종속성: 다른 리소스에서 값을 참조해 불러올 경우 생성 선후 관계에 따라 자동으로 연관 관계 정의
- 명시적 종속성: 강제로 리소스 간 명시적 종속성을 부여할 경우에는 메타인수인 depends_on 을 활용
암시적 종속성을 확인해보자. local_file.def 는 local_file.abc 의 값을 참조해야 하므로 순서에 대해 종속이 발생함을 확인할 수 있다.
Graphviz (dot) language support for Visual Studio Code Extensions 을 추가하면 graph 의 결과를 시각화하여 확인할 수 있다.
명시적 종속성을 확인해보자.
인프라를 프로비저닝하다보면 리소스 참조값이 아닌 메타인수 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"
}
리소스(resource) 3. 리소스 속성 참조
리소스 구성에서 참조 가능한 값은 인수와 속성이다.
- 인수(Arguments): 리소스 생성 시 사용자가 선언하는 값
- 속성(Attributes): 사용자가 설정하는 것이 아닌 리소스 생성 이후 획득 가능한 리소스 고유 값
리소스가 생성될 때, 사용자가 선언한 '인수'를 받아 실제 리소스가 생성되면 일부 리소스는 자동으로 기본값이나 '속성'이 부여된다. 인수도 참조 할 수 있고, 리소스 생성 후 속성 값들도 인수로 가져올 수 있다.
해당 내용에 대해서는 인프라 리소스 생성 테스트를 진행하며, 상세히 테스트해보도록 하겠다.
리소스(resource) 4. 수명주기
lifecycle 은 리소스의 기본 수명주기를 작업자가 의도적으로 변경하는 메타인수다. 해당 메타인수 내에는 다음과 같은 선언이 가능하다.
- create_before_destroy(bool): 리소스 수정 시 신규 리소스를 우선 생성하고 기존 리소스를 삭제
- prevent_destroy(bool): 해당 리소스를 삭제(Destroy) 하려고 할 때 명시적으로 거부
- ignore_changes(list): 리소스 요소에 선언된 인수의 변경 사항을 테라폼 실행 시 무시
- precondition: 리소스 요소에 선언된 인수의 조건을 검증
- postcondition: plan 과 apply 이후의 결과를 속성 값으로 검증
create_before_destroy (생성 후 삭제)
기존의 content 에서 내용을 수정하고, 해당 라이프사이클 메타인수를 추가하였다.
동일한 파일이름 abc.txt 를 지정했으므로 > 파일 내용이 수정(생성)되고 > 최종적으로 삭제 시 동일한 파일을 삭제하므로 > 파일이 삭제된다.
prevent_destroy (삭제 방지)
테라폼 수명주기(삭제 > 생성)으로 수행되는 리소스에 prevent_destroy 가 활성화되어, 삭제되지 않고 실패하게 된다.
lifecycle 의 다른 선언 옵션들에 대해서도 추가 테스트를 해보고, 인프라 리소스 구성 시 적용 방안에 대해 고려해보도록 하자.
1주차 스터디 내용 공부 및 정리를 포스팅해보았다.
기본적인 내용이라 개념과 책에 정리된 예시들을 확인해보았다.
진도가 더 나가기 전에, 테스트해볼 인프라를 구상 및 적용하면서 스터디를 진행해보려고 한다.