테라폼으로 AWS 서비스 구축하기 3장. 테라폼 더 잘쓰기

테라폼을 더 효율적으로 쓰기 위해 테라폼 언어를 알아봅니다
2021.04.27

시작하며

간단한 구성을 테라폼으로 작성해보며 테라폼을 어떻게 쓰는지 알아보았습니다.
본인만 쓰는 환경에서 간단한 구성이라면 그대로 하더라도 괜찮겠지만
코드가 복잡해지거나 규모가 커질수록 단순한 방식으로는 처리하기 힘들어질 것입니다.
이번엔 이러한 문제들을 해결하기 위해서 어떤 식으로 테라폼을 사용하면 될지 알아보겠습니다.

설명할 내용이 많기에 '대충 이런 느낌이구나' 정도로만 읽어주세요.
대충 어떤 느낌인지 알고 공식 문서의 각 내용을 읽으시면 금방 이해할 수 있습니다.

알아볼 내용

  • 상태 파일(terraform state file)
  • 데이터 소스(data)
  • 워크스페이스(workspace)
  • 모듈(module)
  • 변수(variable)
  • 아웃풋(outputs)

기술하는 내용의 상세한 설명은 공식문서를 참고해주세요.

상태 파일

이전 글에서 apply를 하니 tfstate 라는 파일이 생성되었습니다.
상태 파일에는 구성된 AWS 리소스에 관한 정보들이 담겨있습니다.
이 파일을 기반으로 테라폼은 리소스의 갱신을 합니다.
그렇기에 공동으로 작업하기 위해선 상태 파일을 공유해야 합니다.
다양한 방법이 있겠지만 AWS를 구축한다면 S3를 사용하는 방법이 많이 사용됩니다.

데이터 소스

단어 그대로 사용할 데이터의 소스입니다.
데이터 소스를 사용하면 항상 변동하는 값(최신 AMI를 사용하는 등)을 간단하게 사용할 수 있습니다.
프로바이더마다 제공하는 데이터 소스가 다르므로 문서를 참조해야합니다.
선언은 data 블록으로 할 수 있으며 간단한 예로 현재 사용할 수 있는 가용 영역을 찾는 템플릿은 다음과 같습니다
(출처 : 테라폼 예시)

# 데이터 소스 선언
data "aws_availability_zones" "available" {
  state = "available"
}

# 사용 가능한 첫 번째, 두 번째 가용 영역 지정하기
resource "aws_subnet" "primary" {
  availability_zone = data.aws_availability_zones.available.names[0]

  # ...
}

resource "aws_subnet" "secondary" {
  availability_zone = data.aws_availability_zones.available.names[1]

  # ...
}

워크스페이스

인프라를 구성하다 보면 dev, prd 등 환경을 나누어 구축하는 경우가 많습니다.
테라폼에서도 이렇게 환경을 나누기 위해 워크스페이스라는 기능을 제공하고 있습니다.

# 현재 워크스페이스 목록
$ terraform workspace show                                                                                              
default

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

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
* test

모듈

A Terraform module is a set of Terraform configuration files in a single directory.

테라폼에서는 하나의 디렉터리를 모듈로서 인식합니다.
모듈을 사용하면 반복되는 코드를 재사용 할 수 있습니다.
사용할 수 있는 meta-arguments 로는

가 있습니다.
이 중 count 와 for each를 사용하여 동일한 구성의 리소스를 원하는 만큼 반복하여 생성할 수 있습니다.
동일한 동작을 하지만 몇 가지 다른 점이 있습니다.(참고)

작성하는 방법을 설명하기 전 간단히 용어 정리를 하자면

  • 루트 모듈: 테라폼의 가장 상위 디렉터리(모듈)입니다.
  • 하위 모듈: 루트 모듈 이외의 모든 모듈 입니다.
  • 메인 파일: 템플릿의 프로파이더를 AWS로 설정한 파일 입니다.

모듈을 사용하는 방법은 다음과 같습니다.

  1. 하위 모듈 작성
  2. 메인 파일에 모듈 등록
  3. terraform get 실행

예시

프로바이더는 다음과 같이 내용이 적혀있으며 vpc에는 이전 글에서 작성한 것과 같이 보안 그룹이나 서브넷 그룹 등 다양한 리소스가 포함되어 있습니다.

# 디렉터리 구성
$ tree
├── provider.tf
├── terraform.tfstate.d
│   └── test
└── vpc.tf
# provider.tf
terraform {
  required_version = "0.14.9"

  required_providers {
      aws = {
          source = "hashicorp/aws"
          version = "~> 3.0"
      }
  }
}

provider "aws" {
  region = "ap-northeast-2"
}

이 중 vpc를 모듈화하기 위해선 루트 모듈에서 vpc 라는 폴더를 생성 한 후 vpc 내부의 리소스들을 분리하여 구성해줍니다. (디렉터리의 생성이나 리소스의 상세한 내용은 넘어가겠습니다)

작성 후 메인 파일에 module 블록으로 모듈을 지정해 줍니다.

디렉터리 구성은 다음과 같습니다.

├── provider.tf
├── terraform.tfstate.d
│   └── test
└── vpc
    ├── Gataway.tf
    ├── Route Table.tf
    ├── Security Groups.tf
    ├── Subnets.tf
    └── VPC.tf

그리고 메인 파일에 모듈의 내용을 추가해줍니다.

# provider.tf
--- 내용 동일 ---
module "vpc" {
  source  = "./vpc"
}

이후 get 명령어를 실행합니다.

튜토리얼을 보며 직접 따라 해보시길 권장합니다.

변수

구축에 사용할 값들을 템플릿에 직접 작성하지 않고 변수 파일에 따로 작성하여 변수 만을 따로 관리하거나 apply를 할 때 사용자에게 직접 입력 받을 수 있습니다.

보통 모듈별로 사용할 변수를 담은 variable.tf 파일을 만들어 관리합니다.

사용할 수 있는 타입은 공식 문서를 참조해주세요.

variable "user_information" {
  type = object({
    name    = string
    address = string
  })
  sensitive = true
}

resource "some_resource" "a" {
  name    = var.user_information.name
  address = var.user_information.address
}
$ terraform plan
Terraform will perform the following actions:

  # some_resource.a will be created
  + resource "some_resource" "a" {
      + name    = (sensitive)
      + address = (sensitive)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

아웃풋

사용자가 템플릿을 적용한 후 결과값을 확인하고 싶을 때 사용하며 아웃풋을 apply를 실행한 결과물을 콘솔창에서 확인할 수 있습니다.
output 블록으로 조작할 수 있습니다.

output "instance_ip_addr" {
  value = aws_instance.server.private_ip
}

변수와 마찬가지로 모듈별로 outputs.tf 파일을 작성하여 관리하면 편합니다.

마치며

내용이 많다보니 글이 정리되지 못했네요.(틈틈이 수정해야겠네요)

내용의 피드백 및 오탈자 제보는 언제나 환영합니다! must01940(G메일) 으로 보내주시길 바랍니다.
긴 글 읽어주셔서 감사합니다!

글 목록

1장. 테라폼 설치하기 - 해당 글 2장. EC2 RDS S3 구축하기 - 1 2장. EC2 RDS S3 구축하기 - 2 3장. 테라폼 더 잘쓰기