🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Terraform 프로바이더와 리소스 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 29. · 4 Views

Terraform 프로바이더와 리소스 완벽 가이드

Terraform의 핵심인 프로바이더와 리소스 개념을 실무 중심으로 설명합니다. AWS 프로바이더 설정부터 리소스 정의, 의존성 관리, 멀티 프로바이더 구성까지 초급 개발자도 쉽게 이해할 수 있도록 스토리텔링 방식으로 풀어냈습니다.


목차

  1. 프로바이더_개념과_종류
  2. AWS_프로바이더_설정
  3. 리소스_블록_정의
  4. 리소스_속성_참조
  5. 의존성_관리
  6. 멀티_프로바이더_구성

1. 프로바이더 개념과 종류

신입 개발자 김테라 씨가 첫 인프라 자동화 프로젝트를 맡게 되었습니다. 선배 박클라우드 씨가 Terraform 파일을 보여주며 말합니다.

"여기 provider 블록 보이죠? 이게 없으면 아무것도 시작할 수 없어요."

**프로바이더(Provider)**는 Terraform이 다양한 클라우드 플랫폼과 서비스와 소통하기 위한 플러그인입니다. 마치 외국어를 번역해주는 통역사처럼, Terraform 코드를 AWS, Azure, GCP 등이 이해할 수 있는 API 호출로 변환해줍니다.

각 프로바이더는 해당 플랫폼의 리소스를 생성, 수정, 삭제하는 방법을 알고 있습니다.

다음 코드를 살펴봅시다.

# AWS 프로바이더 설정
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

# 프로바이더 구성
provider "aws" {
  region = "ap-northeast-2"  # 서울 리전
}

김테라 씨는 대학교 때 배운 Python과 JavaScript만 다루다가, 이번에 처음으로 인프라 관리를 맡게 되었습니다. "인프라도 코드로 관리한다고요?" 반신반의하며 Terraform을 열어본 순간, 낯선 코드들이 눈에 들어왔습니다.

파일 맨 위에는 'provider "aws"'라는 블록이 있었습니다. 박클라우드 씨가 친절하게 설명을 시작합니다.

"Terraform은 그 자체로는 아무것도 할 수 없어요. 마치 스마트폰 본체만 있는 것과 같죠." 그렇다면 프로바이더란 정확히 무엇일까요?

쉽게 비유하자면, 프로바이더는 마치 스마트폰의 앱과 같습니다. 스마트폰 본체(Terraform)는 다양한 기능을 제공하지만, 실제로 은행 업무를 보려면 은행 앱이 필요하고, 쇼핑을 하려면 쇼핑 앱이 필요합니다.

마찬가지로 AWS 리소스를 관리하려면 AWS 프로바이더가 필요하고, Azure를 사용하려면 Azure 프로바이더가 필요합니다. 프로바이더가 없던 시절에는 어땠을까요?

개발자들은 각 클라우드 플랫폼의 웹 콘솔에 직접 접속하거나, 복잡한 CLI 명령어를 일일이 실행해야 했습니다. AWS에서 EC2 인스턴스 하나 만들려면 수십 번의 클릭이 필요했고, 같은 환경을 다시 만들려면 또 처음부터 시작해야 했습니다.

더 큰 문제는 실수하기 쉽다는 것이었습니다. 보안 그룹 설정을 빼먹거나, 리전을 잘못 선택하는 일이 비일비재했습니다.

바로 이런 문제를 해결하기 위해 프로바이더가 등장했습니다. 프로바이더를 사용하면 선언적 방식으로 인프라를 관리할 수 있습니다.

"이런 리소스를 만들어주세요"라고 선언하면, 프로바이더가 알아서 필요한 API를 호출하고 리소스를 생성합니다. 또한 **멱등성(Idempotence)**도 보장됩니다.

같은 코드를 여러 번 실행해도 결과는 동일합니다. 무엇보다 코드로 관리되기 때문에 Git으로 버전 관리하고, 코드 리뷰를 할 수 있다는 큰 이점이 있습니다.

위의 코드를 한 줄씩 살펴보겠습니다. 먼저 terraform 블록에서는 이 프로젝트에 필요한 프로바이더를 선언합니다.

required_providers 섹션은 "이 프로젝트는 AWS 프로바이더가 필요해요"라고 말하는 것입니다. source는 프로바이더를 어디서 다운로드할지 지정하고, version은 호환되는 버전을 명시합니다.

물결표(~>)는 "5.0 이상, 6.0 미만"을 의미합니다. 다음으로 provider "aws" 블록에서는 실제 프로바이더를 구성합니다.

여기서 region을 설정하면, 이후 생성되는 모든 AWS 리소스는 기본적으로 서울 리전(ap-northeast-2)에 만들어집니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 글로벌 서비스를 운영하는 회사를 생각해봅시다. 한국에는 서울 리전에, 미국에는 버지니아 리전에 똑같은 인프라를 구축해야 합니다.

프로바이더를 사용하면 region만 바꿔서 코드를 재사용할 수 있습니다. 많은 스타트업과 대기업에서 이런 패턴으로 수십 개의 리전을 동시에 관리하고 있습니다.

현재 Terraform에는 수천 개의 프로바이더가 존재합니다. 공식 프로바이더로는 AWS, Azure, Google Cloud가 있고, 파트너 프로바이더로는 MongoDB, Datadog, Kubernetes가 있습니다.

심지어 GitHub 저장소를 관리하는 GitHub 프로바이더, Slack 워크스페이스를 설정하는 Slack 프로바이더도 있습니다. 필요하다면 직접 커스텀 프로바이더를 만들 수도 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 프로바이더 버전을 고정하지 않는 것입니다.

버전을 명시하지 않으면 최신 버전이 자동으로 설치되는데, 메이저 버전이 올라가면 기존 코드가 작동하지 않을 수 있습니다. 따라서 version 제약을 반드시 설정해야 합니다.

다시 김테라 씨의 이야기로 돌아가 봅시다. 박클라우드 씨의 설명을 들은 김테라 씨는 고개를 끄덕였습니다.

"아, 그래서 프로바이더를 먼저 설정해야 하는군요!" 프로바이더를 제대로 이해하면 Terraform의 다음 단계로 자연스럽게 넘어갈 수 있습니다. 이제 본격적으로 리소스를 만들어볼 차례입니다.

실전 팁

💡 - 프로바이더 버전은 항상 명시하세요. 예상치 못한 업데이트로 인한 장애를 방지할 수 있습니다.

  • terraform init 명령어를 실행하면 프로바이더가 자동으로 다운로드됩니다.
  • 여러 리전을 사용한다면 alias를 활용해 프로바이더를 여러 개 선언할 수 있습니다.

2. AWS 프로바이더 설정

김테라 씨가 프로바이더 개념을 이해하고 나서 실제 AWS 프로바이더를 설정하려고 합니다. "그런데 AWS 인증은 어떻게 하죠?" 박클라우드 씨가 웃으며 답합니다.

"방법이 여러 가지 있어요. 가장 안전한 방법부터 알려드릴게요."

AWS 프로바이더 설정은 Terraform이 AWS 계정에 접근할 수 있도록 인증 정보를 구성하는 과정입니다. 마치 건물에 들어가려면 출입증이 필요한 것처럼, AWS API를 호출하려면 액세스 키나 IAM 역할이 필요합니다.

프로바이더 블록에서 리전, 인증 방식, 태그 등을 설정할 수 있습니다.

다음 코드를 살펴봅시다.

# AWS 프로바이더 상세 설정
provider "aws" {
  region  = "ap-northeast-2"
  profile = "dev-account"  # AWS CLI 프로파일 사용

  # 모든 리소스에 자동으로 적용될 태그
  default_tags {
    tags = {
      Environment = "Development"
      ManagedBy   = "Terraform"
      Team        = "DevOps"
    }
  }
}

김테라 씨는 첫 번째 관문을 통과했습니다. 프로바이더가 무엇인지는 이해했지만, 실제로 어떻게 설정하는지는 막막했습니다.

"AWS 액세스 키를 코드에 직접 넣으면 안 된다고 들었는데, 그럼 어떻게 하죠?" 박클라우드 씨가 진지한 표정으로 말합니다. "그건 정말 중요한 질문이에요.

절대로 액세스 키를 코드에 하드코딩해서는 안 됩니다." 그렇다면 AWS 프로바이더는 어떻게 설정해야 할까요? 쉽게 비유하자면, AWS 프로바이더 설정은 마치 호텔 체크인과 같습니다.

호텔에 들어가려면 신분증을 제시하고, 어느 층에 묵을지 정하고, 추가 서비스를 요청할 수 있습니다. 마찬가지로 AWS 프로바이더를 설정할 때는 인증 정보를 제공하고, 어느 리전을 사용할지 정하고, 기본 설정을 지정합니다.

과거에는 어땠을까요? 초창기 클라우드 시대에는 개발자들이 액세스 키를 코드에 직접 작성했습니다.

그러다 실수로 GitHub에 올려서 몇 시간 만에 수백만 원의 비용이 청구되는 사고가 빈번했습니다. 악의적인 사용자들이 공개된 액세스 키를 찾아내어 무단으로 리소스를 생성했기 때문입니다.

더 큰 문제는 이런 키가 노출되면 전체 인프라가 위험에 빠진다는 것이었습니다. 바로 이런 보안 문제를 해결하기 위해 다양한 인증 방식이 등장했습니다.

AWS 프로바이더는 여러 가지 인증 방법을 지원합니다. 환경 변수 방식AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY를 환경 변수로 설정하는 방법입니다.

프로파일 방식~/.aws/credentials 파일에 저장된 프로파일을 사용합니다. IAM 역할 방식은 EC2 인스턴스나 Lambda 함수에서 실행할 때 자동으로 임시 자격 증명을 받아옵니다.

현업에서는 프로파일이나 IAM 역할을 주로 사용합니다. 위의 코드를 한 줄씩 살펴보겠습니다.

먼저 region 설정은 필수입니다. 서울 리전(ap-northeast-2)을 지정하면 모든 리소스가 기본적으로 여기에 생성됩니다.

다음으로 profile = "dev-account"는 AWS CLI 프로파일을 사용한다는 의미입니다. 이 프로파일은 ~/.aws/credentials 파일에 저장되어 있어야 합니다.

가장 유용한 기능은 default_tags 블록입니다. 여기서 설정한 태그는 이 프로바이더로 생성하는 모든 리소스에 자동으로 적용됩니다.

"이 리소스는 개발 환경이고, Terraform으로 관리되며, DevOps 팀이 담당한다"는 정보가 자동으로 붙습니다. 실제 현업에서는 어떻게 활용할까요?

대부분의 회사는 멀티 어카운트 전략을 사용합니다. 개발용 계정, 스테이징용 계정, 프로덕션용 계정을 분리해서 운영합니다.

이때 프로파일을 다르게 설정하면 실수로 프로덕션 환경을 건드리는 것을 방지할 수 있습니다. 예를 들어 개발 환경에서는 profile = "dev", 프로덕션 환경에서는 profile = "prod"를 사용합니다.

태그 전략도 중요합니다. default_tags를 활용하면 비용 추적이 쉬워집니다.

AWS Cost Explorer에서 "Environment: Development" 태그로 필터링하면 개발 환경에서 얼마나 비용이 나가는지 한눈에 볼 수 있습니다. 또한 팀별로 태그를 나누면 각 팀의 리소스 사용량을 파악할 수 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 리전을 잘못 설정하는 것입니다.

예를 들어 미국 리전(us-east-1)에 리소스를 만들었는데 한국에서 접속하면 느립니다. 또 다른 실수는 프로파일 이름을 틀리게 입력하는 것입니다.

프로파일이 없으면 Terraform이 기본 자격 증명을 찾으려고 시도하다가 에러가 발생합니다. 박클라우드 씨가 추가로 조언합니다.

"로컬 개발 환경에서는 프로파일을 사용하고, CI/CD 파이프라인에서는 IAM 역할을 사용하는 게 베스트 프랙티스예요." 김테라 씨는 메모를 열심히 합니다. "프로파일로 개발하고, default_tags로 태그를 자동화하고, 리전은 신중하게 선택하고..." AWS 프로바이더 설정을 제대로 하면 이후 모든 작업이 훨씬 수월해집니다.

이제 본격적으로 리소스를 정의해볼 시간입니다.

실전 팁

💡 - 절대로 액세스 키를 코드에 하드코딩하지 마세요. Git 히스토리에 남으면 삭제해도 소용없습니다.

  • 로컬에서는 aws configure를 실행해 프로파일을 먼저 설정하세요.
  • default_tags는 회사 전체 표준으로 정하면 비용 관리가 훨씬 쉬워집니다.

3. 리소스 블록 정의

드디어 김테라 씨가 실제 리소스를 만들 차례입니다. "이제 EC2 인스턴스를 하나 만들어볼까요?" 박클라우드 씨가 코드를 보여주며 말합니다.

"resource 블록, 이게 Terraform의 심장이에요."

리소스 블록은 Terraform에서 실제로 생성하고 관리할 인프라 구성 요소를 정의하는 핵심 단위입니다. 마치 설계 도면에 건물의 각 요소를 그려 넣는 것처럼, 리소스 블록에는 EC2 인스턴스, S3 버킷, RDS 데이터베이스 등의 상세한 설정을 작성합니다.

각 리소스는 고유한 이름을 가지며, 다른 리소스에서 참조할 수 있습니다.

다음 코드를 살펴봅시다.

# EC2 인스턴스 리소스 정의
resource "aws_instance" "web_server" {
  ami           = "ami-0c9c942bd7bf113a2"  # Amazon Linux 2023
  instance_type = "t3.micro"

  # 태그로 리소스 식별
  tags = {
    Name = "WebServer-01"
    Role = "Frontend"
  }

  # 사용자 데이터로 초기 설정
  user_data = <<-EOF
              #!/bin/bash
              yum update -y
              yum install -y httpd
              systemctl start httpd
              EOF
}

김테라 씨는 드디어 실전에 들어갈 준비가 되었습니다. 프로바이더 설정은 끝났고, 이제 진짜 리소스를 만들 차례입니다.

"근데 리소스는 어떻게 정의하죠?" 박클라우드 씨가 화면을 가리키며 설명합니다. "Terraform의 모든 것은 리소스에서 시작해요.

리소스가 없으면 아무것도 만들 수 없죠." 그렇다면 리소스 블록이란 정확히 무엇일까요? 쉽게 비유하자면, 리소스 블록은 마치 레고 블록과 같습니다.

레고로 집을 만들 때 벽돌 하나하나를 쌓아가듯이, Terraform으로 인프라를 만들 때 리소스 블록 하나하나를 작성해 나갑니다. 각 블록은 특정한 모양과 크기가 있고, 다른 블록과 조합할 수 있습니다.

EC2 인스턴스라는 블록, S3 버킷이라는 블록, RDS 데이터베이스라는 블록을 조합하면 완전한 인프라가 완성됩니다. 리소스 블록이 없던 시절에는 어땠을까요?

개발자들은 AWS 콘솔에 접속해서 "EC2 대시보드 → 인스턴스 시작 → AMI 선택 → 인스턴스 타입 선택 → 스토리지 설정 → 태그 추가 → 보안 그룹 설정 → 검토 후 시작"이라는 긴 과정을 반복해야 했습니다. 10개의 서버를 만들려면 이 과정을 10번 해야 했고, 각 서버의 설정을 조금씩 다르게 하다 보면 실수가 생겼습니다.

더 큰 문제는 나중에 "이 서버를 누가 왜 만들었지?"라는 질문에 답하기 어려웠다는 것입니다. 바로 이런 문제를 해결하기 위해 리소스 블록이라는 개념이 등장했습니다.

리소스 블록을 사용하면 선언적으로 인프라를 정의할 수 있습니다. "어떻게 만들지"가 아니라 "무엇을 만들지"만 작성하면 됩니다.

또한 재사용성이 뛰어납니다. 같은 설정의 서버를 여러 개 만들려면 코드만 복사하면 됩니다.

무엇보다 버전 관리가 가능하다는 큰 이점이 있습니다. Git으로 관리하면 "누가 언제 무엇을 바꿨는지" 명확하게 추적할 수 있습니다.

위의 코드를 한 줄씩 살펴보겠습니다. 먼저 resource 키워드로 시작합니다.

다음에 오는 "aws_instance"리소스 타입입니다. "AWS의 EC2 인스턴스를 만들겠다"는 의미입니다.

그다음 "web_server"리소스 이름입니다. 이 이름은 Terraform 내부에서 이 리소스를 식별하는 고유 ID입니다.

중괄호 안에는 리소스의 **속성(Arguments)**을 작성합니다. ami는 사용할 이미지 ID이고, instance_type은 인스턴스의 크기입니다.

t3.micro는 프리티어에서 사용 가능한 작은 인스턴스입니다. tags 블록은 AWS 콘솔에서 리소스를 쉽게 찾을 수 있게 합니다.

Name 태그는 인스턴스 목록에서 표시되는 이름입니다. 마지막으로 user_data는 인스턴스가 처음 시작될 때 실행할 스크립트입니다.

여기서는 Apache 웹 서버를 자동으로 설치하고 시작합니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 스타트업에서 서비스를 런칭한다고 가정해봅시다. 웹 서버 3대, 데이터베이스 1대, 로드 밸런서 1개가 필요합니다.

리소스 블록으로 이 모든 것을 정의하면, terraform apply 명령어 한 번으로 전체 인프라가 자동으로 만들어집니다. 서비스가 성장해서 웹 서버를 10대로 늘려야 한다면?

코드를 수정하고 다시 apply하면 됩니다. 리소스 타입은 프로바이더마다 다릅니다.

AWS 프로바이더는 aws_로 시작하는 수백 가지 리소스 타입을 제공합니다. aws_s3_bucket은 S3 버킷, aws_rds_instance는 RDS 데이터베이스, aws_vpc는 VPC를 만듭니다.

각 리소스 타입마다 필수 속성과 선택적 속성이 다르므로, 공식 문서를 참고해야 합니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 리소스 이름에 하이픈(-)을 사용하는 것입니다. 리소스 이름은 Terraform 내부 식별자이므로 언더스코어(_)만 사용할 수 있습니다.

"web-server"는 에러가 나지만 "web_server"는 정상 작동합니다. 또 다른 실수는 필수 속성을 누락하는 것입니다.

ami와 instance_type은 필수이므로 반드시 지정해야 합니다. 박클라우드 씨가 강조합니다.

"리소스 블록을 작성할 때는 항상 공식 문서를 참고하세요. 각 속성이 무엇을 의미하는지 정확히 알고 써야 합니다." 김테라 씨는 코드를 저장하고 terraform plan을 실행해봅니다.

"오, 실제로 무엇이 생성될지 미리 보여주네요!" 리소스 블록을 제대로 이해하면 Terraform의 80%를 마스터한 것입니다. 이제 리소스 간의 관계를 알아볼 차례입니다.

실전 팁

💡 - 리소스 이름은 의미 있게 지어야 나중에 헷갈리지 않습니다. web_server_01보다는 frontend_web_server가 명확합니다.

  • terraform plan으로 실제 적용 전에 변경 사항을 미리 확인하세요.
  • 태그는 나중에 리소스를 찾고 비용을 추적하는 데 필수입니다. 반드시 의미 있는 태그를 붙이세요.

4. 리소스 속성 참조

김테라 씨가 EC2 인스턴스를 만들고 나서 다음 질문을 합니다. "이 서버의 IP 주소를 S3 버킷 정책에서 사용하고 싶은데, 어떻게 가져오죠?" 박클라우드 씨가 미소를 지으며 답합니다.

"바로 속성 참조(Attribute Reference)를 사용하면 됩니다."

리소스 속성 참조는 한 리소스의 값을 다른 리소스에서 사용하는 방법입니다. 마치 엑셀에서 다른 셀의 값을 참조하는 것처럼, Terraform에서도 리소스가 생성된 후의 정보를 가져와서 다른 곳에 사용할 수 있습니다.

리소스타입.리소스이름.속성 형식으로 참조하며, Terraform이 자동으로 의존 관계를 파악합니다.

다음 코드를 살펴봅시다.

# EC2 인스턴스 생성
resource "aws_instance" "app_server" {
  ami           = "ami-0c9c942bd7bf113a2"
  instance_type = "t3.micro"

  tags = {
    Name = "AppServer"
  }
}

# 보안 그룹 - EC2의 속성 참조
resource "aws_security_group" "allow_http" {
  name        = "allow-http-${aws_instance.app_server.id}"
  description = "Allow HTTP for ${aws_instance.app_server.private_ip}"

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# 출력값 정의
output "server_public_ip" {
  value = aws_instance.app_server.public_ip
}

김테라 씨는 첫 번째 EC2 인스턴스를 성공적으로 만들었습니다. 터미널에서 terraform apply를 실행하자 실제로 AWS에 서버가 생성되는 것을 확인했습니다.

그런데 문제가 생겼습니다. "이 서버의 IP 주소를 다른 설정에서 써야 하는데, 미리 알 수가 없잖아요?" 김테라 씨가 당황하며 묻습니다.

EC2 인스턴스는 생성될 때 AWS가 자동으로 IP 주소를 할당하기 때문에, 코드를 작성하는 시점에는 IP 주소를 알 수 없습니다. 박클라우드 씨가 고개를 끄덕입니다.

"바로 그 문제를 해결하는 게 속성 참조예요." 그렇다면 속성 참조란 정확히 무엇일까요? 쉽게 비유하자면, 속성 참조는 마치 전화번호부와 같습니다.

친구의 전화번호를 외우지 않아도, 이름만 알면 전화번호부에서 찾아서 전화를 걸 수 있습니다. 마찬가지로 Terraform에서도 EC2 인스턴스의 IP 주소를 직접 알 필요 없이, "app_server의 public_ip"라고 참조하면 Terraform이 알아서 값을 찾아줍니다.

속성 참조가 없던 시절에는 어땠을까요? 개발자들은 리소스를 먼저 만들고, AWS 콘솔에서 생성된 정보를 복사해서 다시 코드에 붙여넣어야 했습니다.

EC2 인스턴스를 만들고 IP 주소를 확인한 다음, 그 IP를 보안 그룹 설정에 수동으로 입력했습니다. 이 과정은 느리고 에러가 나기 쉬웠습니다.

더 큰 문제는 리소스를 다시 만들면 IP가 바뀌는데, 이를 모든 곳에서 업데이트해야 한다는 것이었습니다. 바로 이런 문제를 해결하기 위해 속성 참조 시스템이 만들어졌습니다.

속성 참조를 사용하면 동적으로 값이 연결됩니다. EC2 인스턴스가 만들어지면 Terraform이 자동으로 IP 주소를 가져와서 필요한 곳에 채워줍니다.

또한 의존 관계가 자동으로 설정됩니다. Terraform은 "보안 그룹을 만들기 전에 EC2 인스턴스를 먼저 만들어야 한다"는 것을 알아서 파악합니다.

무엇보다 코드 재사용성이 높아집니다. IP 주소를 하드코딩하지 않기 때문에 같은 코드를 다른 환경에서도 사용할 수 있습니다.

위의 코드를 한 줄씩 살펴보겠습니다. 먼저 aws_instance.app_server로 EC2 인스턴스를 만듭니다.

이 인스턴스가 생성되면 AWS가 자동으로 여러 속성을 할당합니다. id는 인스턴스 ID, public_ip는 공개 IP 주소, private_ip는 내부 IP 주소입니다.

다음으로 보안 그룹에서 이 값들을 참조합니다. name = "allow-http-${aws_instance.app_server.id}"는 EC2 인스턴스의 ID를 보안 그룹 이름에 포함시킵니다.

${...} 문법은 **문자열 보간(Interpolation)**으로, 변수나 참조를 문자열 안에 넣을 때 사용합니다. description 필드에서는 private_ip를 참조해서 설명에 포함시킵니다.

이렇게 하면 나중에 AWS 콘솔에서 "이 보안 그룹이 어느 서버용인지" 한눈에 알 수 있습니다. 마지막으로 output 블록은 Terraform이 작업을 마친 후 특정 값을 화면에 출력합니다.

terraform apply가 끝나면 "server_public_ip = 3.35.123.45"처럼 서버의 공개 IP가 표시됩니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 웹 서버와 데이터베이스를 함께 구성한다고 가정해봅시다. 웹 서버의 환경 변수에 데이터베이스 엔드포인트를 설정해야 합니다.

속성 참조를 사용하면 user_data = "DB_HOST=${aws_db_instance.main.endpoint}" 이런 식으로 자동으로 연결할 수 있습니다. 데이터베이스를 다시 만들어도 코드 수정 없이 새 엔드포인트가 자동으로 적용됩니다.

참조 가능한 속성은 리소스마다 다릅니다. 각 리소스 타입마다 Attributes Reference 섹션이 공식 문서에 있습니다.

EC2 인스턴스는 public_ip, private_ip, id, arn 등을 제공합니다. S3 버킷은 bucket, arn, region을 제공합니다.

RDS 인스턴스는 endpoint, address, port를 제공합니다. 필요한 속성이 무엇인지 확인하려면 항상 문서를 참고해야 합니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 존재하지 않는 속성을 참조하는 것입니다.

예를 들어 aws_instance.app_server.ip_address는 없습니다. 올바른 이름은 public_ip입니다.

Terraform이 에러 메시지를 출력하면 문서를 확인해야 합니다. 또 다른 실수는 순환 참조를 만드는 것입니다.

A가 B를 참조하고 B가 A를 참조하면 Terraform이 어느 것을 먼저 만들어야 할지 알 수 없어 에러가 발생합니다. 박클라우드 씨가 실전 팁을 알려줍니다.

"terraform state show 명령어를 사용하면 리소스가 가진 모든 속성을 볼 수 있어요. 문서에 없는 숨겨진 속성도 찾을 수 있죠." 김테라 씨는 감탄합니다.

"와, 이제 모든 리소스가 자동으로 연결되네요. 마치 살아있는 인프라 같아요!" 속성 참조를 마스터하면 복잡한 인프라도 우아하게 관리할 수 있습니다.

이제 의존 관계를 더 명시적으로 다루는 방법을 알아보겠습니다.

실전 팁

💡 - terraform console 명령어로 대화형 모드에 들어가면 참조 값을 즉시 테스트해볼 수 있습니다.

  • 속성 이름이 기억나지 않으면 terraform state show로 전체 속성 목록을 확인하세요.
  • output 블록을 활용하면 팀원들이 중요한 정보를 쉽게 확인할 수 있습니다.

5. 의존성 관리

김테라 씨가 복잡한 인프라를 구성하다가 문제에 부딪혔습니다. "이 리소스는 저 리소스가 완전히 준비된 다음에 만들어져야 하는데, 순서가 꼬이네요." 박클라우드 씨가 모니터를 가리킵니다.

"암묵적 의존성과 명시적 의존성, 둘 다 알아야 해요."

의존성 관리는 리소스 간의 생성 순서를 제어하는 메커니즘입니다. Terraform은 속성 참조를 통해 자동으로 의존 관계를 파악하는 **암묵적 의존성(Implicit Dependency)**과, depends_on 구문으로 명시적으로 지정하는 **명시적 의존성(Explicit Dependency)**을 지원합니다.

올바른 의존성 관리는 안정적인 인프라 배포의 핵심입니다.

다음 코드를 살펴봅시다.

# VPC 생성
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "MainVPC"
  }
}

# 서브넷 - VPC ID 참조로 암묵적 의존성
resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"

  tags = {
    Name = "PublicSubnet"
  }
}

# EC2 인스턴스 - depends_on으로 명시적 의존성
resource "aws_instance" "web" {
  ami           = "ami-0c9c942bd7bf113a2"
  instance_type = "t3.micro"
  subnet_id     = aws_subnet.public.id

  # S3 버킷이 먼저 생성되어야 함
  depends_on = [aws_s3_bucket.logs]

  tags = {
    Name = "WebServer"
  }
}

# S3 버킷
resource "aws_s3_bucket" "logs" {
  bucket = "my-app-logs-bucket"
}

김테라 씨는 이제 여러 리소스를 조합해서 복잡한 인프라를 만들 수 있게 되었습니다. VPC를 만들고, 서브넷을 추가하고, EC2 인스턴스를 배치하는 과정을 코드로 작성했습니다.

그런데 terraform apply를 실행하자 에러가 발생했습니다. "Error: subnet does not exist" 메시지를 보며 김테라 씨는 당황합니다.

"분명히 서브넷 코드를 작성했는데 왜 없다고 하죠?" 박클라우드 씨가 진단합니다. "순서가 문제예요.

EC2 인스턴스를 만들려고 할 때 서브넷이 아직 준비되지 않았던 거죠." 그렇다면 의존성이란 정확히 무엇일까요? 쉽게 비유하자면, 의존성은 마치 요리 순서와 같습니다.

파스타를 만들 때 물을 끓이지 않고 면을 넣을 수 없습니다. 소스를 만들지 않고 면과 섞을 수 없습니다.

각 단계에는 선행 조건이 있고, 순서를 지키지 않으면 실패합니다. 마찬가지로 인프라도 VPC 없이 서브넷을 만들 수 없고, 서브넷 없이 EC2 인스턴스를 배치할 수 없습니다.

의존성 관리가 자동화되지 않았던 시절에는 어땠을까요? 개발자들은 스크립트에 sleep 명령어를 넣어서 "10초 기다렸다가 다음 단계 진행"하는 식으로 작업했습니다.

하지만 네트워크가 느리거나 AWS API가 지연되면 10초로 부족할 수 있었습니다. 반대로 리소스가 빨리 준비되면 불필요하게 시간을 낭비했습니다.

더 큰 문제는 복잡한 인프라에서 모든 의존 관계를 수동으로 파악하기 어렵다는 것이었습니다. 바로 이런 문제를 해결하기 위해 자동 의존성 관리가 도입되었습니다.

Terraform은 두 가지 방식으로 의존성을 처리합니다. 암묵적 의존성은 속성 참조를 분석해서 자동으로 생성됩니다.

subnet_id = aws_subnet.public.id라고 쓰면 Terraform이 "아, EC2 인스턴스를 만들기 전에 서브넷을 먼저 만들어야겠구나"라고 자동으로 이해합니다. 이는 90% 이상의 경우에 충분합니다.

하지만 가끔 명시적 의존성이 필요한 경우가 있습니다. 예를 들어 EC2 인스턴스가 시작 스크립트에서 S3 버킷에 로그를 쓴다고 가정해봅시다.

코드상으로는 EC2가 S3 버킷을 직접 참조하지 않지만, 런타임에는 버킷이 필요합니다. 이럴 때 depends_on을 사용합니다.

위의 코드를 한 줄씩 살펴보겠습니다. 먼저 aws_vpc.main을 만듭니다.

VPC는 다른 리소스에 의존하지 않으므로 가장 먼저 생성됩니다. 다음으로 aws_subnet.public에서 vpc_id = aws_vpc.main.id를 참조합니다.

이것이 암묵적 의존성입니다. Terraform은 자동으로 "VPC → 서브넷" 순서를 인식합니다.

aws_instance.web에서는 두 가지 의존성이 있습니다. subnet_id = aws_subnet.public.id는 암묵적 의존성이고, depends_on = [aws_s3_bucket.logs]명시적 의존성입니다.

depends_on은 배열 형태로 여러 리소스를 지정할 수 있습니다. 마지막으로 aws_s3_bucket.logs는 독립적으로 만들어질 수 있지만, EC2 인스턴스의 depends_on 때문에 먼저 생성됩니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 데이터베이스 마이그레이션 스크립트를 실행하는 Lambda 함수가 있다고 가정해봅시다.

RDS 인스턴스가 완전히 준비된 후에 Lambda를 실행해야 합니다. 이때 depends_on = [aws_db_instance.main]을 추가하면 안전하게 순서를 보장할 수 있습니다.

많은 회사에서 초기 설정 스크립트나 데이터 시딩 작업에 이 패턴을 사용합니다. Terraform은 의존성을 **DAG(Directed Acyclic Graph)**로 관리합니다.

모든 리소스를 노드로, 의존 관계를 화살표로 표현한 그래프를 만듭니다. 그런 다음 위상 정렬(Topological Sort) 알고리즘으로 올바른 순서를 계산합니다.

terraform graph 명령어로 실제 그래프를 시각화할 수 있습니다. Graphviz로 변환하면 아름다운 다이어그램이 나옵니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 불필요한 depends_on을 남발하는 것입니다.

속성 참조만으로 충분한 경우가 대부분이므로, depends_on은 정말 필요할 때만 사용해야 합니다. 또 다른 실수는 순환 의존성을 만드는 것입니다.

A가 B에 의존하고 B가 A에 의존하면 Terraform이 에러를 냅니다. "cycle detected"라는 메시지가 보이면 의존 관계를 다시 설계해야 합니다.

박클라우드 씨가 조언합니다. "terraform plan을 실행하면 어떤 순서로 리소스가 생성될지 보여줘요.

+/- 기호 옆의 숫자가 순서를 나타내죠." 김테라 씨는 코드를 수정한 후 다시 apply를 실행합니다. "오, 이번엔 순서대로 만들어지네요!" 의존성을 제대로 관리하면 복잡한 인프라도 안정적으로 배포할 수 있습니다.

이제 마지막으로 여러 프로바이더를 동시에 사용하는 방법을 알아보겠습니다.

실전 팁

💡 - 속성 참조만으로 충분하다면 depends_on을 사용하지 마세요. 코드가 더 명확해집니다.

  • terraform graph 명령어로 의존성 그래프를 시각화하면 복잡한 관계를 한눈에 볼 수 있습니다.
  • create_before_destroy 같은 라이프사이클 메타-인자로 리소스 재생성 순서를 세밀하게 제어할 수 있습니다.

6. 멀티 프로바이더 구성

김테라 씨의 프로젝트가 확장되었습니다. "서울 리전과 미국 리전에 동시에 배포해야 해요.

그리고 Datadog으로 모니터링도 추가해야 하고요." 박클라우드 씨가 고개를 끄덕입니다. "멀티 프로바이더 구성을 배울 때가 왔네요."

멀티 프로바이더 구성은 여러 프로바이더를 동시에 사용하거나, 같은 프로바이더를 다른 설정으로 여러 번 선언하는 기법입니다. 마치 여러 개의 은행 계좌를 관리하는 것처럼, 여러 AWS 리전, 여러 클라우드 플랫폼, 서드파티 서비스를 하나의 Terraform 프로젝트에서 통합 관리할 수 있습니다.

alias를 사용해 각 프로바이더를 구분합니다.

다음 코드를 살펴봅시다.

# 기본 AWS 프로바이더 - 서울 리전
provider "aws" {
  region = "ap-northeast-2"

  default_tags {
    tags = {
      Environment = "Production"
      Region      = "Korea"
    }
  }
}

# 추가 AWS 프로바이더 - 미국 리전
provider "aws" {
  alias  = "us_east"
  region = "us-east-1"

  default_tags {
    tags = {
      Environment = "Production"
      Region      = "US"
    }
  }
}

# Datadog 프로바이더
provider "datadog" {
  api_key = var.datadog_api_key
  app_key = var.datadog_app_key
}

# 서울 리전에 EC2 인스턴스
resource "aws_instance" "web_kr" {
  ami           = "ami-0c9c942bd7bf113a2"
  instance_type = "t3.micro"
  # provider 지정 안 하면 기본 프로바이더 사용
}

# 미국 리전에 EC2 인스턴스
resource "aws_instance" "web_us" {
  provider      = aws.us_east  # alias로 프로바이더 지정
  ami           = "ami-0abcdef1234567890"
  instance_type = "t3.micro"
}

# Datadog 모니터 생성
resource "datadog_monitor" "web_health" {
  name    = "Web Server Health"
  type    = "metric alert"
  message = "Web server is unhealthy"

  query = "avg(last_5m):avg:aws.ec2.cpu{*} > 80"
}

김테라 씨는 몇 주간 Terraform을 열심히 공부했고, 이제 제법 복잡한 인프라를 코드로 관리할 수 있게 되었습니다. 그런데 새로운 요구사항이 들어왔습니다.

"김테라 씨, 글로벌 서비스를 시작하려고 해요. 한국 사용자를 위해 서울 리전에, 미국 사용자를 위해 버지니아 리전에 서버를 배포해주세요.

그리고 Datadog으로 모니터링도 설정해야 해요." 김테라 씨는 고민에 빠졌습니다. "프로바이더는 하나만 선언하는 거 아니었나?

그럼 프로젝트를 두 개로 나눠야 하나?" 박클라우드 씨가 미소를 지으며 답합니다. "아니요, 하나의 프로젝트에서 여러 프로바이더를 사용할 수 있어요." 그렇다면 멀티 프로바이더란 정확히 무엇일까요?

쉽게 비유하자면, 멀티 프로바이더는 마치 멀티탭과 같습니다. 콘센트 하나에 여러 개의 플러그를 꽂아 쓰듯이, Terraform 프로젝트 하나에 여러 프로바이더를 선언해서 사용합니다.

AWS 프로바이더를 두 개 꽂고, Datadog 프로바이더를 하나 더 꽂고, 필요하면 GitHub 프로바이더도 추가할 수 있습니다. 각 프로바이더는 독립적으로 작동하지만, 하나의 코드베이스에서 통합 관리됩니다.

멀티 프로바이더가 없던 시절에는 어땠을까요? 개발자들은 리전마다, 서비스마다 별도의 Terraform 프로젝트를 만들어야 했습니다.

seoul 폴더에 서울 리전 코드, us 폴더에 미국 리전 코드를 따로 관리했습니다. 코드 중복이 심했고, 설정을 변경하려면 모든 폴더를 돌아다니며 수정해야 했습니다.

더 큰 문제는 리전 간 리소스를 연결하기 어려웠다는 것입니다. 서울의 S3 버킷을 미국의 EC2에서 참조하려면 복잡한 수동 작업이 필요했습니다.

바로 이런 문제를 해결하기 위해 멀티 프로바이더 구성이 만들어졌습니다. 멀티 프로바이더를 사용하면 중앙 집중식 관리가 가능합니다.

모든 인프라가 하나의 프로젝트에 있으므로 전체 구조를 한눈에 파악할 수 있습니다. 또한 리소스 간 참조가 쉬워집니다.

서울의 RDS 엔드포인트를 미국의 EC2 환경 변수로 전달하는 것이 자연스럽게 됩니다. 무엇보다 일관성 있는 배포가 가능합니다.

terraform apply 한 번으로 모든 리전, 모든 서비스가 동시에 업데이트됩니다. 위의 코드를 한 줄씩 살펴보겠습니다.

먼저 기본 AWS 프로바이더를 선언합니다. alias가 없으므로 이것이 기본 프로바이더가 됩니다.

서울 리전(ap-northeast-2)을 사용하고, "Region: Korea" 태그가 자동으로 붙습니다. 다음으로 두 번째 AWS 프로바이더를 선언합니다.

여기서 핵심은 alias = "us_east"입니다. alias는 이 프로바이더를 식별하는 별명입니다.

같은 타입의 프로바이더를 여러 개 선언할 때는 alias로 구분해야 합니다. 이 프로바이더는 미국 동부 리전(us-east-1)을 사용합니다.

세 번째로 완전히 다른 프로바이더인 Datadog을 추가합니다. Datadog은 모니터링 SaaS 서비스입니다.

API 키를 변수로 받아서 설정합니다. 이렇게 하면 키를 코드에 하드코딩하지 않아도 됩니다.

리소스에서 프로바이더를 사용하는 방법을 봅시다. aws_instance.web_krprovider를 지정하지 않았으므로 기본 프로바이더(서울)를 사용합니다.

반면 aws_instance.web_usprovider = aws.us_east로 명시적으로 지정했으므로 미국 리전에 생성됩니다. datadog_monitor 리소스는 Datadog 프로바이더를 사용합니다.

Datadog 프로바이더는 하나뿐이므로 명시하지 않아도 자동으로 선택됩니다. 실제 현업에서는 어떻게 활용할까요?

글로벌 서비스를 운영하는 회사를 생각해봅시다. 한국, 미국, 유럽에 각각 서버를 배포하고, 모든 로그는 중앙의 S3 버킷에 모으고, Datadog으로 통합 모니터링합니다.

멀티 프로바이더를 사용하면 이 모든 것을 하나의 Terraform 프로젝트로 관리할 수 있습니다. 설정을 변경하면 모든 리전에 일관되게 적용되고, 의존 관계도 자동으로 처리됩니다.

프로바이더 조합은 무한합니다. AWS와 Azure를 동시에 사용해 하이브리드 클라우드를 구성할 수 있습니다.

Kubernetes 프로바이더로 클러스터를 관리하면서, Helm 프로바이더로 애플리케이션을 배포할 수 있습니다. GitHub 프로바이더로 저장소를 만들고, Terraform Cloud 프로바이더로 워크스페이스를 설정할 수 있습니다.

필요한 모든 인프라를 하나의 코드베이스에서 관리하는 것이 가능합니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 alias 이름을 틀리게 쓰는 것입니다. provider = aws.us-east처럼 하이픈을 쓰면 에러가 납니다.

올바른 형식은 aws.us_east입니다. 또 다른 실수는 기본 프로바이더를 가정하는 것입니다.

프로바이더가 여러 개 있을 때는 명시적으로 지정하는 것이 안전합니다. 멀티 프로바이더를 사용할 때는 state 파일 크기에도 주의해야 합니다.

너무 많은 리소스를 하나의 프로젝트에 넣으면 state 파일이 거대해지고 apply가 느려집니다. 적절히 프로젝트를 나누는 것도 고려해야 합니다.

박클라우드 씨가 마지막 조언을 합니다. "멀티 프로바이더는 강력하지만, 복잡도도 증가시켜요.

정말 필요한 경우에만 사용하고, 문서화를 철저히 하세요." 김테라 씨는 코드를 완성하고 apply를 실행합니다. 서울과 미국에 동시에 서버가 만들어지고, Datadog 대시보드에 자동으로 모니터링이 설정됩니다.

"와, 정말 모든 게 코드로 관리되네요!" 멀티 프로바이더까지 마스터하면 Terraform의 거의 모든 기능을 활용할 수 있습니다. 이제 여러분은 복잡한 글로벌 인프라도 자신 있게 관리할 수 있습니다.

실전 팁

💡 - alias는 의미 있는 이름으로 짓세요. us_east보다 production_us가 더 명확합니다.

  • 프로바이더가 3개 이상이면 providers.tf 파일을 별도로 만들어 관리하세요.
  • 각 리전의 AMI ID는 다르므로, data source를 활용해 자동으로 찾는 것이 좋습니다.

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Terraform#Provider#Resource#AWS#IaC

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스

HCL 문법과 기본 구조 완벽 가이드

Terraform의 핵심 언어인 HCL을 처음 배우는 초급 개발자를 위한 가이드입니다. 기본 문법부터 블록 구조, 데이터 타입, 주석, 포맷팅까지 실무에 필요한 모든 것을 다룹니다. 점프 투 자바 스타일로 쉽고 재미있게 배워보세요.

Terraform 소개 및 설치 완벽 가이드

인프라를 코드로 관리하는 IaC의 개념부터 Terraform의 특징, 설치 방법, 그리고 첫 번째 리소스 생성까지 초급 개발자를 위한 친절한 입문 가이드입니다. 실무에서 바로 활용할 수 있는 예제와 팁을 담았습니다.

Ansible 소개 및 설치 완벽 가이드

서버 수십 대를 손쉽게 관리하는 자동화 도구 Ansible의 기초부터 설치, 첫 명령어 실행까지 배웁니다. 초급 개발자를 위한 실무 중심 입문 가이드입니다.

실전 프로젝트 글로벌 엔터프라이즈급 AWS 아키텍처

글로벌 서비스를 위한 엔터프라이즈급 AWS 아키텍처 설계부터 구축까지 실전 프로젝트로 배우는 완벽 가이드입니다. 멀티 리전 고가용성, 보안, 모니터링, CI/CD까지 실무에서 바로 적용할 수 있는 노하우를 담았습니다.

CodePipeline으로 완전 자동화된 CI/CD 구축

AWS CodeCommit, CodeBuild, CodeDeploy, CodePipeline을 활용하여 코드 커밋부터 배포까지 완전히 자동화된 CI/CD 파이프라인을 구축하는 방법을 초급 개발자를 위해 쉽게 설명합니다. 실무 상황을 스토리로 풀어내며 각 단계를 자세히 다룹니다.