Skip to Content
Archive테라폼 stage, module

State

State 목적과 의미

탄경

  1. 공유 스토리지 필요성: 여러 팀원이 동일한 테라폼 상태 파일을 사용하기 위해 공유 스토리지가 필요 race condition 을 통한 state 관리
  2. 파일 잠금: 여러 팀원이 동시에 테라폼을 실행할 경우, 상태 파일의 동시 수정으로 인한 충돌이 발생 가능
  3. 환경 격리 isolate state : 개발, 스테이징, 프로덕션과 같은 다양한 환경에서 상태 파일을 격리할 필요

버전 관리 시스템의 한계

  1. 수동 오류: 팀원이 상태 파일을 최신 상태로 유지하지 않으면 문제가 발생할 수 있습니다.
  2. 잠금 미지원: 대부분의 VCS는 상태 파일의 잠금을 지원하지 않습니다.
  3. 시크릿 노출 위험: 상태 파일에는 민감한 정보가 평문으로 저장될 수 있어, 보안 위험이 있습니다.

장점점

테라폼은 이러한 문제를 해결하기 위해 원격 백엔드(AWS S3, Azure Blob Storage 등)를 지원합니다.

  1. 자동 동기화: 테라폼 작업을 실행할 때마다 원격 백엔드에서 자동으로 상태 파일을 불러오고 저장합니다.
  2. 잠금 지원 lock : 원격 백엔드를 사용하면 자동으로 상태 파일의 잠금을 관리할 수 있습니다.
  3. 암호화 지원: 대부분의 원격 백엔드는 데이터 전송 및 저장 시 암호화를 지원합니다.

Untitled

state 동기화 구조는 다음과 같습니다.

  • 테라폼 구성과 State 흐름 : Plan 과 Apply 중 각 리소스에 발생할 수 있는 네 가지 사항, 아래 실행 계획 출력 기호와 의미
기호의미
+Create
-Destroy
-/+Replace
~Updated in-place

워크스페이스

Terraform의 workspace는 Terraform 설정의 상태를 분리할 수 있는 환경입니다. 여러 workspace를 사용하면 같은 구성을 가진 별도의 환경을 만들 수 있습니다.

예를 들어, 개발(dev), 스테이징(staging), 그리고 프로덕션(production) 환경을 관리해야 하는 경우, 각 환경에 대한 서로 다른 workspace를 생성할 수 있습니다. 이렇게 하면 Terraform 설정은 동일하지만, 각 workspace의 상태는 각각 관리됩니다.

Untitled

주요 기능 및 장점

  • 상태 분리: 각 workspace는 자체 상태 파일을 가지므로 여러 환경에서 동일한 구성을 안전하게 재사용할 수 있습니다.
  • 변수 재사용: 동일한 Terraform 코드를 다른 매개변수와 함께 여러 환경에서 실행할 수 있습니다. 예를 들어, 스테이징 환경에서는 작은 VM 인스턴스를, 프로덕션에서는 큰 VM 인스턴스를 사용할 수 있습니다.
  • 효율적인 리소스 관리: Workspace를 사용하면, 각 환경에 필요한 클라우드 리소스를 따로 관리할 수 있으므로, 리소스를 더 효율적으로 활용할 수 있습니다.

사용법

기본적인 명령어는 다음과 같습니다:

  • 새 workspace 생성: terraform workspace new [workspace_name]
  • workspace 목록 보기: terraform workspace list
  • workspace 전환: terraform workspace select [workspace_name]

여러 workspace를 사용하면, 환경마다 다른 terraform.tfstate 파일이 생성되므로 각각의 환경을 독립적으로 관리할 수 있습니다.

장단점 총정리

  • 장점: 동일한 테라폼 구성으로 다양한 환경의 리소스를 프로비저닝하고 관리할 수 있습니다.
  • 단점: 완벽한 격리가 어렵고, 상태 파일에 대한 접근 권한 관리가 복잡해질 수 있습니다.
  • 유형1 : 신규 리소스 정의 → Apply ⇒ 리소스 생성(처음부터 Terraform 코드로 작업)
    • 실습을 위해서 5.2 디렉터리를 신규 생성 후 열기 → main.tf 파일 생성

      mkdir 5.2 && cd 5.2
      locals { name = "mytest" } resource "aws_iam_user" "myiamuser1" { name = "${local.name}1" } resource "aws_iam_user" "myiamuser2" { name = "${local.name}2" }
    • 실행

      # **terraform init && terraform apply -auto-approve** terraform state list terraform state show aws_iam_user.myiamuser1 # **ls *.tfstate cat terraform.tfstate | jq # terraform apply -auto-approve ls *.tfstate** # iam 사용자 리스트 확인 aws iam list-users | jq
  • 유형2 : 실제 리소스 수동 제거 → Apply ⇒ 리소스 생성
    • 실행

      # 실제 리소스 수동 제거 **aws iam delete-user --user-name mytest1 aws iam delete-user --user-name mytest2** aws iam list-users | jq # 아래 명령어 실행 결과 차이는? (refresh 유무) # 실제 리소스는 제거되었으나 -refrest=false로 인해 변경사항 없으므로 인식 **terraform plan** **terraform plan -refresh=false cat terraform.tfstate | jq .serial # terraform apply -auto-approve** terraform state list **cat terraform.tfstate | jq .serial** # iam 사용자 리스트 확인 aws iam list-users | jq
  • 유형3 : Apply → Apply - 코드, State, 형상 모두 일치한 경우 ⇒ 변경사항 없음
    • 실행

      **# Serial 값일 동일! terraform apply -auto-approve cat terraform.tfstate | jq .serial terraform apply -auto-approve cat terraform.tfstate | jq .serial terraform apply -auto-approve cat terraform.tfstate | jq .serial**
  • 유형4 : 코드에서 일부 리소스 삭제 → Apply ⇒ 리소스 삭제
    • main.tf 파일 수정

      locals { name = "mytest" } resource "aws_iam_user" "myiamuser1" { name = "${local.name}1" }
    • 실행

      # 코드 변경으로 인해 user2 삭제 **terraform apply -auto-approve** terraform state list terraform state show aws_iam_user.myiamuser1 # **ls *.tfstate cat terraform.tfstate | jq** # iam 사용자 리스트 확인 aws iam list-users | jq

유형5 : 리소스만 있으며 코드, State는 없는 경우 → Import 또는 신규코드 작성

  • 유형6 : 실수로 tfstate 파일 삭제 → plan/apply
    • 실행

      # 실수로 tfstate 파일 삭제 rm -rf terraform.tfstate* # 아래 두 명령 결과 차이는? # Local에 State 파일이 없으므로 두 명령 모두 새로운 리소스 추가(add) 계획 **terraform plan** **terraform plan -refresh=false** # apply할 경우 어떤 결과 발생? # 이미 리소스가 있으므로 Error 발생: EntityAlreadyExists: User with name mytest1 already exists. **terraform apply -auto-approve** terraform state list **cat terraform.tfstate | jq** # iam 사용자 리스트 확인 aws iam list-users | jq # 다음 실습을 위해 iam user 삭제 **aws iam delete-user --user-name mytest1**

      ⇒ 🤔 위 상황에서 복구 하는 방법은? import 등 방법이 있습니다!

모듈

정의와 필요성

  • 테라폼 모듈은 재사용 가능한 테라폼 코드의 집합입니다.
  • 시간이 지날수록 인프라 구성이 복잡해지며, 이를 효과적으로 관리하기 위해 모듈이 필요합니다.

문제점

  • 단일 파일 구조에서 계속 업데이트할 경우 다음과 같은 문제가 발생합니다:
    • 코드를 찾고 수정하기 어려워짐
    • 리소스 간 복잡한 연관 관계로 인해 변경 분석이 어려워짐
    • 비슷한 구성이 여러 환경에서 반복됨
    • 새 프로젝트를 위해 기존 구성을 이해하기 어려움

종류

  • 루트 모듈 (Root Module): 최상위 모듈로, 테라폼이 실행되어 인프라를 프로비저닝하는 모듈
  • 자식 모듈 (Child Module): 루트 모듈에서 호출되는 추가적인 모듈 집합

모듈의 장점

  1. 관리성: 연관된 구성 요소를 묶어 단위별로 쉽게 찾고 업데이트 가능
  2. 캡슐화: 모듈은 논리적으로 묶여 독립적으로 관리되며, 필요한 부분만 외부에 노출
  3. 재사용성: 이미 검증된 모듈을 다른 프로젝트에서도 쉽게 사용 가능
  4. 일관성과 표준화: 모듈을 사용하면 구성의 일관성을 유지하고 복잡성 감

기본원칙

모듈은 테라폼 구성의 라이브러리나 패키지에 해당하는 개념입니다. 복잡한 테라폼 프로젝트를 더 효율적으로 관리할 수 있도록 도와주는 방법으로 사용됩니다.

원칙

  1. 디렉터리 명명 규칙:
    • 모듈의 디렉터리는 terraform-<프로바이더 이름>-<모듈 이름> 형식을 따르는 것을 권장합니다. 이는 Terraform Cloud와 Terraform Enterprise에서도 사용되며, 디렉터리가 테라폼에 특화되어 있고 어떤 프로바이더의 리소스를 사용하고 있는지, 그리고 모듈의 이름이 무엇인지 쉽게 알 수 있게 해줍니다.
  2. 모듈화 구조:
    • 처음부터 모듈화를 고려하여 테라폼 구성을 작성하는 것이 좋습니다. 이렇게 하면 나중에 다른 모듈에서도 이 모듈을 쉽게 호출할 수 있습니다. 또한 리소스들을 논리적으로 그룹화할 수 있습니다.
  3. 독립적 관리:
    • 각 모듈은 독립적으로 관리되어야 하며, 이는 Version Control System(VCS)에서의 관리도 쉽게 해줍니다. 특히 리모트 모듈을 사용하지 않더라도 독립적으로 관리하는 것이 좋습니다.

모듈화 해보기

# terraform init 시 생성되는 modules.json 파일 확인 tree .terraform .terraform ├── modules │ └── modules.json ... ## 모듈로 묶여진 리소스는 module이라는 정의를 통해 단순하게 재활용하고 반복 사용할 수 있다. ## 모듈의 결과 참조 형식은 module.<모듈 이름>.<output 이름>으로 정의된다. cat .terraform/modules/modules.json | jq { "Modules": [ { "Key": "", "Source": "", "Dir": "." }, { "Key": "mypw1", "Source": "../modules/terraform-random-pwgen", "Dir": "../modules/terraform-random-pwgen" }, { "Key": "mypw2", "Source": "../modules/terraform-random-pwgen", "Dir": "../modules/terraform-random-pwgen" } ] }

[도전과제4] 테라폼 레지스트리에 공개된 모듈을 사용하여 리소스를 배포해본다.

모듈 main.tf

resource "aws_db_instance" "mont" { allocated_storage = var.allocated_storage storage_type = "gp2" engine = "mysql" engine_version = var.engine_version instance_class = var.instance_class name = var.name username = var.username password = var.password parameter_group_name = var.parameter_group_name skip_final_snapshot = var.skip_final_snapshot vpc_security_group_ids = var.vpc_security_group_ids subnet_ids = var.subnet_ids }

모듈 variables.tf

variable "name" { description = "The name of the DB instance" type = string } variable "username" { description = "Username for the master DB user" type = string } variable "password" { description = "Password for the master DB user" type = string }

output.tfvars

db_name = "prod-db" db_admin_user = "admin" db_admin_password = "securepassword"

Untitled

해당구조와 같이 작성한 모듈과 tf파일들로 생성을 진행하였습니다.

Untitled