테라폼으로 AWS 환경 구축하기 4장. 모듈을 이용하여 코드 다시 쓰기 2

2022.04.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

이전 글에서는 하나의 tf 파일에 정의되어 있던 코드를 모듈화하여 효율적인 코드로 바꾸어 보았습니다.
또한 환경 디렉터리를 나누어 환경 별로 다른 리소스가 생성되도록 설정하는 작업도 하였습니다.

이번 글에서는 workspace기능을 이용하여 환경을 나누는 방법을 알아보고 그 외에 테라폼의 상태 파일을 로컬이 아닌 s3에 저장하여 다른 팀원들과 공유하는 방법을 알아봅니다.

알아볼 내용

이번 글에서는 다음에 대하여 알아봅니다

  • workspace기능
  • 테라폼에서 지원하는 모듈
  • 백엔드 설정

workspace

이전 글에서 잠깐 언급했지만 환경을 나누는 방법은 디렉터리 자체를 나누는 방법도 있지만 테라폼에서 제공하는 workspace라는 기능을 이용하는 방법도 있습니다.
workspace에는 다음과 같은 옵션이 있습니다.

# 워크스페이스 생성
$ terraform workspace new dev
Created and switched to workspace "dev"!

You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.

# 워크스페이스 목록 확인
$ terraform workspace list
  default
* dev

# 현재 워크스페이스 확인
$ terraform workspace show
* dev

# 대상 워크스페이스 변경
$ terraform workspace select default
Switched to workspace "default".

# 워크스페이스 제거
$ terraform workspace delete dev
Deleted workspace "dev"!

new 옵션으로 환경을 생성하면 명령을 실행한 디렉터리에 terraform.tstate.d라는 디렉터리가 생성되며 그 아래에 본인이 생성한 환경의 디렉터리가 생성됩니다.
해당 환경에서 실행한 테라폼의 결과는 이 디렉터리에 저장됩니다.

모듈에서 워크스페이스의 환경을 구분하는 방법은 다음과 같습니다.

resource "foo" "bar" {
  name = "${terraform.workspace == "prd" ? "prd-resource" : "dev-resource"}"
}

이번에 작성한 코드를 예로 들자면 이렇게 되겠네요.

data "aws_ami" "amazonLinux" {
  ...
}

resource "aws_instance" "ec2" {
  count         = terraform.workspace == "prd" ? 4 : 2
  ami           = data.aws_ami.amazonLinux.id
  instance_type = terraform.workspace == "prd" ? "m5.medium" : "t3.small"
  vpc_security_group_ids = [
    var.private_sg
  ]
  subnet_id = element(var.private_subnets, count)
  key_name  = "publicTestKey"

  root_block_device {
    volume_size = terraform.workspace == "prd" ? 500 : 50
    volume_type = "gp3"
    tags = {
      "Name" = "${terraform.workspace}-private-ec2-${count.index + 1}-vloume-1"
    }
  }

  tags = {
    "Name" = "${terraform.workspace}-private-ec2-${count.index + 1}"
  }
}

terraform.workspace 파라미터를 이용하면 현재 환경 값을 불러올 수 있습니다.
이렇게 코드를 작성하면 환경마다 다른 terraform.tfvars, variables.tf를 만들지 않아도 되고, 모듈 파일에서 해당 값을 직관적으로 확인할 수 있기 때문에 변수에 의한 작동 실패도 확인할 수 있습니다.

테라폼에서 지원하는 모듈

테라폼 레지스트리에서는 다양한 프로바이더와 모듈을 제공하고 있습니다.
이 중에는 값만 지정하면 사용할 수 있는 AWS 모듈도 있습니다.

이를 이용하여 resource블록이 아닌 module블록으로 간단하고 빠르게 각 기능의 모듈화를 할 수 있습니다. 사용 방법은 다음과 같습니다.

# modules/network/main.tf
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "3.14.0"
  cidr = var.vpc_cidr
  tags = {
    "Name" = "${terraform.workspace}-vpc"
  }
}

# modules/network/outputs/tf
output "vpc_id" {
  value = module.vpc.id
}

모듈을 바로 불러오기 때문에 코드 작성 후 terraform init이 필요합니다.
또한 정의되어 있는 인수를 사용하기 때문에 인수명이 다르면 에러가 발생합니다.
필요한 옵션만 사용하거나 인수명을 자유롭게 사용하는 등 좀 더 자유롭게 코드를 쓰고 싶은 경우라면 resource블록을 사용하여 정의하는 것을 추천합니다.

백엔드 설정

혼자서 테라폼으로 작업을 한다면 상태 파일(terraform.tfstate)이나 상태 잠금 파일(.terraform.lock.hcl) 어디에 저장되어 있든 어떻게 관리하든 상관없지만 협업을 하는 경우 이러한 파일을 공유하고 관리할 필요가 있습니다.
이를 위해 상태 파일을 S3에 상태 잠금 파일을 DynamoDB에 저장하는 방법을 가장 많이 사용합니다.

각 리소스를 직접 손으로 작성해도 되고 all 이나 global 등 모든 환경에서 사용되는 리소스를 저장하는 디렉터리를 생성하고 그 아래에 백엔드용 리소스를 생성하는 코드를 작성해도 됩니다.
코드의 내용은 다음과 같습니다.

# env/all/main.tf
terraform {
  required_version = "~> 1.0.9"

  required_providers {
    aws = "~> 4.0"
  }
}

# S3 생성 코드
resource "aws_s3_bucket" "tfstate"{
 bucket = "sujae-terraform-tfstate-bucket"

 versioning {
  enabled = true
 }
}

# DynamoDB 생성 코드
resource "aws_dynamodb_table" "terraform_lock" {
  name           = "sujae-terraform-lock"
  hash_key       = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

그리고 리소스를 생성하면 S3 버킷과 DynamoDB 테이블이 생성된 것을 확인할 수 있습니다.

백엔드를 설정하기 위해서 backend블록을 추가하면 됩니다.
저는 backend.tf라는 파일을 새로 만들었지만 main.tf에 지정해도 상관없습니다.

# env/dev/backend.tf
terraform {
  backend "s3" {
    bucket         = "sujae-terraform-tfstate-bucket"
    key            = "terraform.tfstate"
    region         = "ap-northeast-1"
    dynamodb_table = "sujae-terraform-lock"
    encrypt        = true
  }
}

terraform init을 한 후 리소스를 생성해보면 버킷과 테이블에 각각 상태 파일과 잠금 파일이 추가된 것을 확인할 수 있습니다.

마치며

백엔드의 설정까지 기본적인 환경 구성하는 방법을 알아보았습니다.
다음에는 CI/CD 와 다른 구성을 구현하는 코드를 알아보도록 하겠습니다.

긴 글 읽어주셔서 감사합니다.
오탈자 및 내용 피드백은 언제나 환영합니다. must01940 지메일로 연락 주시면 감사합니다!


본 블로그 게시글을 보시고 문의 사항이 있으신 분들은
클래스메소드코리아 (info@classmethod.kr)로 연락 주시면 빠른 시일 내 담당자가 회신 드릴 수 있도록 하겠습니다 !