Terraform 폴더구조 및 사용법

문한성·2023년 9월 19일
0

공부

목록 보기
27/28
post-thumbnail

어떤 폴더 구조가 좋은 구조일까?

개발 환경별 폴더 나누기

TerraformProject/

├── dev/
│   ├── main.tf
│   ├── variables.tf
├── stage/
│   ├── main.tf
│   ├── variables.tf 
└── prod/
    ├── main.tf
    └── variables.tf
    

개발 환경별로 폴더를 나누어 줄 필요가 있습니다.
Terraform은 terraform apply 명령어를 실행하면 실행한 위치의 모든 tf 파일을 읽어서 실행시킵니다.
각 환경을 나눠줌으로써 각각 환경에 맞게 실행할 수 있습니다.
또한 각 폴더마다 tfstate파일을 따로 생성함으로써 꼬임을 방지할 수 있습니다.

tfstate란?
terraform으로 적용한 인프라 상태가 저장된 파일입니다.
terraform의 backend 기능을 사용하지 않았을때 로컬에 생성됩니다.

  • 여러사람과 협업하려면 테라폼으로 관리한 상태정보를 로컬에서 혼자 보관하면 좋지않습니다.
  • Terraform backend 기능을 이용하여 AWS S3에 상태파일을 저장하는것을 추천합니다.

리소스 유형별로 폴더 나누기

TerraformProject/
├── dev/
│   ├── instances/
│   │   ├── main.tf  
│   │   └── variables.tf 
│   ├── vpc/
│   │   ├── main.tf
│   │   └── variables.tf
│   ├── storage/
│   │   ├── main.tf
│   │   └── variables.tf
├── stage/
│   ├── instances/
│   │   ├── main.tf  
│   │   └── variables.tf 
│   ├── vpc/
│   │   ├── main.tf
│   │   └── variables.tf
│   ├── storage/
│   │   ├── main.tf
│   │   └── variables.tf
├── prod/
    ├── instances/
    │   ├── main.tf  
    │   └── variables.tf 
    ├── vpc/
    │   ├── main.tf
    │   └── variables.tf
    ├── storage/
        ├── main.tf
        └── variables.tf

각 리소스 유형별로 폴더 구조를 분리하고 관리하는 방법입니다.
리소스 별로 폴더를 나누어 줌으로써 자주 변경되고 삭제와 생성이 많은 리소스들과 한번 만들어두고 변경사항이 적은 리소스들을 따로 분리할 수 있습니다.
또한 지워지면 안되는 storage 같은 리소스를 분리함으로써 각 리소스들을 좀 더 쉽게 관리할 수 있습니다.

위와 같이 리소스별로 폴더를 생성하여 따로 보관함으로써 유형별로 각각 관리해줄 수 있다는 이점을 얻을 수 있었습니다.

  • instance - ecs ec2와 같이 자주 변경 사항이 발생하고 삭제와 생성이 빈번하게 발생할 수 있습니다.
  • vpc - vpc, subnet, 보안그룹과 같이 변경사항이 미비하고 한번 생성후 계속 쓸수 있는 리소스들을 모아둡니다.
  • storage - RDS, DynamoDB와 같이 데이터를 저장하는 리소스들은 삭제를 하면 안되는 리소스들을 모아둡니다.

문제점

Terraform의 terraform apply명령어는 명령을 실행하는 위치의 tf파일들만 읽어옵니다.

즉, 한 폴더에 여러개의 tf파일을 두고 실행했을 때와 달리 다른 폴더에 있는 tf파일의 값들을 읽어오지 못합니다.

각 폴더끼리 변수값 읽어오는 방법

Terraform에서 다른 모듈 또는 폴더 간에 변수를 전달하고 읽어오는 방법을 output.tf 파일과 로컬에 생성된 .tfstate 파일을 이용하여 설명드리겠습니다.

instance폴더

instance 폴더에 output.tf 파일을 생성하고 다음과 같이 public ip값을 출력 합니다.

output "public_ip" {
  value = aws_instance.example.public_ip
}

여기서 aws_instance.example.public_ip는 인스턴스의 공용 IP 주소를 참조합니다.

출력한 값이 필요한 폴더

이제 다른 모듈에서 인스턴스 폴더의 public_ip 출력을 읽어오려면 해당 폴더의 main.tf 파일에서 데이터 소스를 사용하여 가져올 수 있습니다.

data "terraform_remote_state" "instance" {
  backend = "local" # 로컬 상태 파일을 사용합니다.
  config = {
    path = "../instance/terraform.tfstate" # web_server 모듈의 .tfstate 파일 위치를 지정합니다.
  }
}

resource "aws_security_group_rule" "example" {
  # 다른 설정들...
  source_security_group_id = data.terraform_remote_state.instance.outputs.public_ip
}

위에서 설명했던것처럼 .tfstate 파일을 로컬에 생성하여 사용하는것은 테스트할 때에만 사용하는것을 권장합니다.

terraform의 backend 기능을 이용한 예시

Terraform에서 AWS S3를 사용하여 terraform.tfstate 파일을 저장하려면 다음과 같이 backend 설정을 사용하여 백엔드를 구성하고, back.tf 파일에 해당 설정을 작성해야 합니다.

AWS S3 Backend 설정:

먼저, AWS S3 버킷을 생성하고 해당 버킷을 사용하여 terraform.tfstate 파일을 저장할 준비를 해야 합니다. AWS 인증 정보는 환경 변수 또는 AWS CLI를 통해 설정되어야 합니다.

Terraform Backend 설정 파일 (back.tf):

프로젝트 루트 디렉토리에 back.tf 파일을 생성하고 다음과 같이 백엔드 설정을 작성합니다.

    terraform {
      backend "s3" {
        bucket         = "your-unique-s3-bucket-name"
        key            = "terraform.tfstate" # 저장할 파일 이름
        region         = "your-aws-region"
        encrypt        = true # 데이터를 암호화할지 여부
        dynamodb_table = "your-lock-table-name" # 선택 사항: 상태 잠금을 위한 DynamoDB 테이블
      }
    }
    
  • bucket: Terraform 상태 파일을 저장할 S3 버킷의 이름을 지정합니다. 반드시 고유한 이름이어야 합니다.
  • key: 상태 파일의 이름을 지정합니다. 일반적으로 terraform.tfstate로 설정합니다.
  • region: 사용 중인 AWS 리전을 지정합니다.
  • encrypt: 데이터를 암호화할지 여부를 결정합니다. true로 설정하면 암호화가 활성화됩니다.
  • dynamodb_table (선택 사항): 상태 파일 잠금을 위한 DynamoDB 테이블의 이름을 지정합니다. 동시 수정을 방지하는 데 사용됩니다.

Terraform 초기화:

back.tf 파일을 작성한 후, 해당 디렉토리에서 Terraform을 초기화해야 합니다. 다음 명령을 실행하세요

terraform init

이렇게 하면 Terraform 상태 파일을 안전하게 저장하고 공유할 수 있으며, 동시 수정을 방지하기 위해 DynamoDB 테이블을 사용하여 잠금을 설정할 수 있습니다.

데이터소스 설정:

공유 모듈 디렉토리에서 원하는 데이터 소스를 설정합니다. 예를 들어, 다른 환경에서 사용할 VPC ID를 가져오려면 다음과 같이 설정할 수 있습니다.

    data "terraform_remote_state" "vpc" {
      backend = "s3"
      config = {
        bucket = "your-unique-s3-bucket-name"
        key    = "terraform.tfstate"
        region = "your-aws-region"
      }
    }

    output "vpc_id" {
      value = data.terraform_remote_state.vpc.outputs.vpc_id
    }

이 코드에서는 terraform_remote_state 데이터 소스를 사용하여 S3에서 VPC 모듈의 상태를 가져오고, 그 중에서도 vpc_id 값을 가져옵니다.

다른 환경 디렉토리에서 데이터 소스 사용 (instance/main.tf 예시):

이제 다른 환경 디렉토리에서 해당 데이터 소스를 사용하여 변수 값을 가져올 수 있습니다. 예를 들어, instance/main.tf 파일에서 VPC ID를 가져오려면 다음과 같이 사용합니다.

```
data "terraform_remote_state" "shared" {
  backend = "s3"
  config = {
    bucket = "your-unique-s3-bucket-name"
    key    = "terraform.tfstate"
    region = "your-aws-region"
  }
}

resource "aws_instance" "example" {
  # 다른 설정들...
  vpc_security_group_ids = [aws_security_group.example.id]
  subnet_id             = data.terraform_remote_state.shared.outputs.vpc_id
}

```

위 코드에서는 terraform_remote_state 데이터 소스를 사용하여 공유 모듈의 상태를 가져오고, 그 중에서도 vpc_id 값을 가져와 EC2 인스턴스의 subnet_id로 사용합니다.

Terraform backend 기능을 사용하여 얻는 이점

로컬의 .tfstate파일을 관리하는것이 아니라 s3에 저장하여 사용함으로써 모든 협업자들이 같은 파일에 접근하여 인프라 상태를 공유할 수 있습니다.

dynamodb를 사용하여 락을 걸면 동시 수정을 방지하는 기능을 제공합니다.
여러명의 사용자가 동시에 인프라를 변경하려고 할 때 충돌을 방지하고 변경사항을 순차적으로 적용할 수 있습니다.

또한 상태파일을 안전하게 저장하고 암호화 할 수 있습니다.
IAM역할을 사용하여 상태파일에 대한 접근을 제어할 수 있습니다.

불편한점 및 개선방법

이렇게 테라폼을 좋은 폴더구조롤 나누어 봤을 때 여러가지 불편사항들을 마주치게 된다.

  • 각 폴더마다 직접 들어가서 하나씩 순서대로 실행 시켜줘야한다.
  • provider.tf, back.tf등 각 폴더마다 복사 붙여넣기를 해줘야할 코드들이 발생한다.
    (이것은 DRY원칙에 위배되는 사항이다.)

이런 불편한점들을 해결하고 DRY원칙을 준수하는 방법이 Terragrunt를 사용하는 것이다.

DRY 원칙이란?

Dry 원칙을 준수해야하는 이유

  • 코드가 단순해지며, 한번만 작성할 수 있다
  • 한 곳에서만 코드를 변경하고 모든 인스턴스들에서는 변경사항만 확인할 수 있다
  • 시간과 노력이 절약되고 유지 관리가 쉬우며 버그 가능성도 줄어 든다

DRY 원칙 위반

  • 같은 코드나 로직을 반복해서 작성하거나 복사하여 붙여넣기를 하는 행위

DRY 원칙을 준수하는 방법

  • 코드와 로직을 재사용 가능한 더 작은 단위로 나누고 원하는 위치에서 해당 코드를 호출하여 사용하기

Terragrunt란?

profile
기록하고 공유하려고 노력하는 DevOps 엔지니어

0개의 댓글