1. IaC와 테라폼
테라폼은 infrastructure as code 를 표방하는 인프라 프로비져닝툴이다.
선언적(declarative)설정으로 인프라의 최종 설정 상태를 대상을 생성한다.
2. 실습 환경 준비
A. 실행 환경 구성
Terraform 설치
WSL 을 사용해서 UBUNTU를 이용해서 테라폼을 설치하면 쉽다.
VSCODE를 WSL에 마운트되어있는 폴더에서 열게되면 LINUX 환경처럼 파일을 사용가능하다.
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform
AWSCLI 설치
aws configure
를 이용해서 aws 크리덴셜을 설정한다.
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
B. EC2 배포 실습
EC2에 대한 네트워크 접근 허용에 대한 테스트
해당 질문에 대한 답변은 어떤 속성(tag들은 Mutable으로 리소스가in-place로 변경이 됩니다.
그와 반대로, ami같은 이미지 아이디들은 immutable로 리소스가 replace가 됩니다.
3. 기본 사용법
3.1 주요 커맨드
terraform init
// 필요한 프로바이더 플러그인을 찾고 설치, 추가로 '프로바이더/모듈/백엔드' 구성
validate으로 테라폼 구성 파일 유효성 확인
해당 커맨드로 작업은 발생하지 않고 코드적 유효성을 확인할 수 있습니다.
terraform plan
//실행 계획을 생성하는 동작으로 테라폼이 적용할 명령을 검토할 수 있게
// plan을 위의 그림과 같이 보여줍니다.
terraform apply
// 다음과 같이 aws instance가 생성되고 실행되는것을 확인할 수 있습니다.
terraform destroy
// 테라폼에서 관리하는 모든 개체를 제거하게 됩니다.
terraform destroy -target RESOURCE_TYPE.NAME -target RESOURCE_TYPE2.NAME
// 다음 코드를 사용하면 subset에 대한 리소스를 제거할 수 있습니다.
3.2 HCL
HCL은 Json과 비슷하게 설정을 나타내는 syntax라고 생각하면 됩니다.
조건문 동작도 가능하고 버저닝해서 히스토리를 쉽게 관리할 수 있습니다.
resource "aws_instance" "example" {
ami = "abc123"
network_interface {
# ...
}
}
// funtion 호출 예
myprojectname = format("%s is myproject name", var.project)
// null 일때 값을 넣어줄 수 있습니다.
credentials = var.somevariable== "" ? file(var.somevariable) : var.somevariable
인프라를 구성하기 위한 선언 블록도 존재합니다: terraform, resource, data, variable, local, output
3.3 테라폼 블록
테라폼 블록
테라폼 구성을 명시하는데 block을 사용합니다.
테라폼 버전과 프로바이더 버전을 명시함으로써 실행 오류를 제거합니다.
3년 후에 실행하던 동일한 결과를 얻을 수 있어야한다!
terraform {
required_version = "~> 1.3.0" # 테라폼 버전
required_providers { # 프로바이더 버전을 나열
random = {
version = ">= 3.0.0, < 3.1.0"
}
aws = {
version = "4.2.0"
}
}
cloud { # Cloud/Enterprise 같은 원격 실행을 위한 정보
organization = "<MY_ORG_NAME>"
workspaces {
name = "my-first-workspace"
}
}
backend "local" { # state를 보관하는 위치를 지정
path = "relative/path/to/terraform.tfstate"
}
}
테라폼 내에서 시맨틱 버전관리도 밑과 같이 가능하다.
# version = Major.Minor.Patch
version = 1.3.4
버전의 값에 따른 실행 여부로 버전의 가드레일을 설치할 수 있다.
terraform {
required_version = "< 1.0.0"
}
에서로 변경했을때 다음과 같이 에러가 표기되게 된다.
terraform {
required_version = ">= 1.0.0"
}
에서로 변경했을때 정상 실행된다.
또, 높은 프로바이더 버전을 갑자기 설정하였을 때에도 다음과 같은 에러를 얻을 수 있다.
백엔드 블록
설명
백엔드 블록은 테라폼 실행시 저장되는 State(tf.tfstate) 파일들의 저장 위치를 선언한다.
해당 state의 데이터를 사용해서 리소스를 탐색하고 추적하게 된다. (작업자간 공유 필요함)
한명만 작업을 진행해야하므로 lock.info 같은 정보들로 lock이 걸리게 됩니다.
외부 노출되면 안되는 정보가 포함되어있어서 접근제어가 필요하다.
state/terraform.tfstate 파일을 강제로 삭제 후, plan 과 apply 실행 시 어떻게 될까요?
기존의 인스턴스는 테라폼에서 관리가 안되고 apply 시 새로 생성됨!
무조건! 백업을 하거나 s3같은 원격 저장소를 사용하고 versioning을 켜둘것!
rm -rf terraform.tfstate*
// state가 모두 삭제될 경우 백업을 확인해보자!
// 없으면 마음이 아파질거다.
// s3 bucket와을 DYNAMODB의 LOCK을사용해라!
3.4 리소스
다음과 같이 리소스 블록은 resource로 시작하고 리소스 블락이 생성한 리소스 유형을 정의한다.
다음과 같은 추가적 종속성이나 메타 인수를 정의가 가능하다.
depends_on : 종속성을 선언하며, 선언된 구성요소와의 생성 시점에 대해 정의
count : 선언된 개수에 따라 여러 리소스를 생성
for_each : map 또는 set 타입의 데이터 배열의 값을 기준으로 여러 리소스를 생성
provider : 동일한 프로바이더가 다수 정의되어 있는 경우 지정
provisioner : 리소스 생성 후 추가 작업 정의
timeouts : 프로바이더에서 정의한 일부 리소스 유형에서는 create, update, delete에 대한 허용 시간 정의 가능
resource "local_file"(리소스 유형)"abc"(ID) {
content = "123"
filename = "${path.module}/abc.txt"
}
resource "aws_instance" "web" {
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
}
resource "local_file" "abc" {
content = "123!"
filename = "${path.module}/abc.txt"
}
resource "local_file" "def" {
content = local_file.abc.content // 리소스참조로종속성! 표기
// depends_on = [
// local_file.abc // 명시적종속성! "123!" 표기
// ]
filename = "${path.module}/def.txt"
}
다음과 같은 종속성으로 GRAPHVIZ에서 다음과 같이 표기됨
리소스 구성에서 참조 가능한 값은 인수
, 속성
이다.
속성은 리소스가 생성되고 획득 가능한 리소스 고유 값이다.
// 리소스 참조
<리소스 유형>.<이름>.<인수>
<리소스 유형>.<이름>.<속성>
content = local_file.abc.content // 리소스 참조로 종속성 표기
라이프 사이클은 리소스의 수명주기를 작업자가 명시하는 메타 인수다.
create_before_destroy (bool): 리소스 수정 시 신규 리소스를 우선 생성하고 기존 리소스를 삭제
prevent_destroy (bool): 해당 리소스를 삭제 Destroy 하려 할 때 명시적으로 거부
ignore_changes (list): 리소스 요소에 선언된 인수의 변경 사항을 테라폼 실행 시 무시
precondition: 리소스 요소에 선언해 인수의 조건을 검증
postcondition: Plan과 Apply 이후의 결과를 속성 값으로 검증
테라폼의 기본 수명 주기는 삭제후 생성인데 create_before_destory를 사용하면 생성을 실행한후 삭제로 동작하게 된다.
조심해야하는 케이스 2개
리소스의 명시적인 이름이 기존 리소스에 할당 되어있으면 create_before_destroy
가 생성에 실패할 수 있다.
생성후 삭제할때, 동일한 리소스에 대한 삭제 명령이 수행되어 리소스가 모두 삭제되는 경우도 있다.
실습
다음 코드에 대해서 terraform init && terraform plan && terraform apply -auto-apply
실행이후 cat abc.txt로 결과값 확인인
// content 수정이후에 terraform init && terraform plan && terraform apply
create_before_destory= false 로 동작하는 것을 확인인
// content 수정이후에 terraform init && terraform plan && terraform apply
create_before_destory= true로 설정하였을때 동작하는 것을 확인인
다음과 같이 생성하고 바로 삭제해버리는 것을 확인할 수 있다.
위와 같이 파일들을 수정해서 진행했을때, prevent_destroy 옵션은 삭제를 하지 못해 terraform이 정상 실행하지 못하는 것도 확인할 수 있다.
ignore_changes 는 해당 대상 리소스는 테라폼 실행시 무시하게된다.
해당 설정은 리소스 요소에 선언해서 인수의 조건을 검증하는데 사용한다.
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
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
}
다음 코드를 실행시키면 실행이후의 값을 검증할 수 있다.