Terraform Infrastructure Automation: DevOps 엔지니어링 가이드
Terraform을 활용한 인프라 자동화의 핵심 개념부터 실제 AWS 환경에서의 배포 예시까지, DevOps 엔지니어링 관점에서 자세히 알아봅니다. IaC, Docker, Kubernetes, CI/CD 파이프라인 통합 전략을 다룹니다.
Terraform Infrastructure Automation: DevOps 엔지니어링 가이드
클라우드 환경이 보편화되고 서비스 규모가 확장됨에 따라, 인프라를 수동으로 관리하는 것은 비효율적일 뿐만 아니라 오류 발생 가능성을 높이는 주된 원인이 되었습니다. 이러한 문제점을 해결하기 위해 Infrastructure as Code (IaC) 패러다임이 등장했으며, 그 중심에는 Terraform이 강력한 도구로 자리 잡고 있습니다. 이 글에서는 Terraform을 활용하여 인프라를 효율적으로 자동화하는 방법을 DevOps 엔지니어링 관점에서 심층적으로 다루고자 합니다.
1. Terraform과 Infrastructure as Code (IaC)의 이해
Infrastructure as Code (IaC)는 인프라를 코드로 정의하고 관리하는 접근 방식입니다. 이는 소프트웨어 개발에서 소스 코드를 관리하는 것과 유사하게, 버전 관리, 재사용성, 자동화된 배포 등의 이점을 인프라 관리에 적용할 수 있게 합니다. IaC의 도입은 인프라의 일관성을 보장하고, 배포 속도를 향상시키며, 휴먼 에러를 줄이는 데 결정적인 역할을 합니다.
Terraform은 HashiCorp에서 개발한 오픈소스 IaC 도구로, 다양한 클라우드 프로바이더(AWS, Azure, GCP 등) 및 온프레미스 환경의 인프라를 선언적(declarative) 구성 언어인 HashiCorp Configuration Language (HCL)를 사용하여 프로비저닝하고 관리할 수 있도록 지원합니다.
Terraform의 핵심 개념
Terraform을 이해하기 위해 알아야 할 몇 가지 핵심 개념들이 있습니다.
- Provider: Terraform이 특정 클라우드 또는 서비스(예: AWS, Kubernetes, Docker)와 상호작용할 수 있도록 하는 플러그인입니다. 각 Provider는 해당 서비스의 리소스를 생성, 업데이트, 삭제하는 기능을 제공합니다.
- Resource: Provider를 통해 관리되는 인프라 구성 요소입니다. 예를 들어, AWS S3 버킷, EC2 인스턴스, Kubernetes Pod 등이 Resource에 해당합니다.
- Data Source: 기존에 생성된 인프라 리소스의 정보를 Terraform 구성 파일로 가져와 사용할 수 있게 해줍니다. 예를 들어, 특정 AMI ID나 VPC ID를 조회하는 데 사용됩니다.
- Variable: 재사용 가능한 값을 정의하여 Terraform 구성 파일의 유연성을 높입니다. 환경별 설정(예: 개발/운영 리전)을 관리할 때 유용합니다.
- Output: Terraform이 인프라를 성공적으로 프로비저닝한 후 사용자에게 보여줄 값을 정의합니다. 예를 들어, 생성된 EC2 인스턴스의 공인 IP 주소를 Output으로 설정할 수 있습니다.
- Module: 재사용 가능한 Terraform 구성 파일의 묶음입니다. 복잡한 인프라를 모듈화하여 관리 효율성을 높이고, 일관된 패턴으로 인프라를 배포할 수 있도록 돕습니다.
- State File: Terraform이 관리하는 인프라의 실제 상태를 기록하는 파일입니다.
.tfstate파일에 저장되며, Terraform은 이 파일을 사용하여 현재 인프라 상태와 HCL 파일에 정의된 목표 상태를 비교하고 필요한 변경 사항을 계획합니다. 이 파일은 매우 중요하며, 원격 백엔드에 안전하게 저장해야 합니다.
2. Terraform 설치 및 기본 사용법
Terraform을 사용하기 위한 첫 단계는 로컬 시스템에 Terraform CLI를 설치하는 것입니다. 여기서는 Linux (Ubuntu/Debian) 환경을 기준으로 설명합니다.
Terraform 설치 (Linux 예시)
# HashiCorp GPG 키 추가
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
# HashiCorp 레포지토리 추가
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
# 패키지 목록 업데이트 및 Terraform 설치
sudo apt update && sudo apt install terraform
# 설치 확인
terraform --version
AWS Provider 설정
Terraform이 AWS 인프라를 관리하려면 AWS Provider를 설정해야 합니다. versions.tf 파일에 필요한 Provider와 Terraform 버전을 정의합니다.
# versions.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # 사용할 AWS Provider 버전 지정
}
}
required_version = "~> 1.0" # 사용할 Terraform CLI 버전 지정
}
# provider.tf
provider "aws" {
region = "ap-northeast-2" # 인프라를 배포할 AWS 리전
# credentials 설정은 환경 변수 (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) 또는 AWS CLI 설정 파일을 통해 관리하는 것이 일반적입니다.
}
첫 번째 리소스 배포: S3 버킷
간단한 S3 버킷을 생성하는 예시를 통해 Terraform의 기본 사용법을 익혀보겠습니다. main.tf 파일을 생성하고 다음 내용을 추가합니다.
# main.tf
resource "aws_s3_bucket" "my_terraform_bucket" {
bucket = "my-unique-terraform-bucket-example-12345" # 전역적으로 고유한 버킷 이름으로 변경해야 합니다.
acl = "private"
tags = {
Name = "MyTerraformBucket"
Environment = "Dev"
ManagedBy = "Terraform"
}
}
output "s3_bucket_id" {
description = "생성된 S3 버킷의 ID"
value = aws_s3_bucket.my_terraform_bucket.id
}
output "s3_bucket_arn" {
description = "생성된 S3 버킷의 ARN"
value = aws_s3_bucket.my_terraform_bucket.arn
}
이제 다음 Terraform CLI 명령어를 사용하여 인프라를 배포합니다.
-
terraform init: Terraform 구성 파일을 초기화하고, 필요한 Provider 플러그인을 다운로드합니다.
terraform init
-
terraform plan: 현재 구성 파일과 Terraform State 파일(또는 실제 인프라 상태)을 비교하여,apply명령 실행 시 어떤 변경 사항이 발생할지 미리 보여줍니다. 실제 인프라에는 아무런 변경도 가하지 않습니다.
terraform plan
-
terraform apply:plan에서 계획된 변경 사항을 실제 인프라에 적용합니다.--auto-approve옵션을 사용하지 않으면, 변경 사항 적용 전에 사용자에게 확인을 요청합니다.
terraform apply --auto-approve
-
terraform destroy: Terraform으로 프로비저닝된 모든 리소스를 삭제합니다. 이 명령은 매우 강력하므로, 프로덕션 환경에서는 신중하게 사용해야 합니다.
terraform destroy --auto-approve
3. Terraform으로 Docker 및 Kubernetes 인프라 구축
Terraform은 단일 리소스뿐만 아니라 복잡한 컨테이너 인프라(Docker, Kubernetes)를 구축하는 데도 활용될 수 있습니다. 여기서는 Docker 컨테이너를 호스팅할 EC2 인스턴스를 프로비저닝하고, Kubernetes 클러스터 구축에 Terraform이 어떻게 활용되는지 개념적으로 살펴봅니다.
Docker 호스팅을 위한 EC2 인스턴스 프로비저닝
Docker 컨테이너를 실행할 수 있는 EC2 인스턴스를 Terraform으로 생성하고, user_data를 활용하여 인스턴스 시작 시 Docker를 자동으로 설치하고 설정하는 예시입니다.
# ec2-docker.tf
resource "aws_instance" "docker_host" {
ami = "ami-0abcdef1234567890" # 사용하려는 리전의 Ubuntu Server LTS AMI ID로 변경 (예: ap-northeast-2의 Ubuntu 22.04 LTS)
instance_type = "t2.micro"
key_name = "my-ssh-keypair" # SSH 접속을 위한 키 페어 이름 지정
tags = {
Name = "DockerHost"
Environment = "Dev"
}
# 인스턴스 시작 시 실행될 스크립트 (Docker 설치 및 설정)
user_data = <<-EOF
#!/bin/bash
sudo apt-get update -y
sudo apt-get install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker ubuntu # 'ubuntu' 사용자를 docker 그룹에 추가
newgrp docker # 현재 세션에 docker 그룹 권한 적용 (재부팅 또는 재로그인 필요)
EOF
vpc_security_group_ids = [aws_security_group.docker_host_sg.id]
}
resource "aws_security_group" "docker_host_sg" {
name = "docker-host-security-group"
description = "Allow SSH and HTTP traffic to Docker host"
vpc_id = "vpc-xxxxxxxxxxxxxxxxx" # 실제 VPC ID로 변경
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # SSH 접속 허용 (보안을 위해 특정 IP로 제한하는 것이 좋습니다)
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # HTTP 접속 허용
}
egress {
from_port = 0
to_port = 0
protocol = "-1" # 모든 아웃바운드 트래픽 허용
cidr_blocks = ["0.0.0.0/0"]
}
}
output "docker_host_public_ip" {
description = "Docker 호스트의 공인 IP 주소"
value = aws_instance.docker_host.public_ip
}
이 구성을 terraform apply하면, Docker가 설치된 EC2 인스턴스가 프로비저닝되고 해당 인스턴스의 공인 IP를 확인할 수 있습니다.
EKS 클러스터 프로비저닝 (개념적 접근)
Kubernetes 클러스터, 특히 AWS EKS(Elastic Kubernetes Service)를 Terraform으로 프로비저닝하는 것은 앞선 예시보다 훨씬 복잡합니다. EKS 클러스터는 VPC, 서브넷, 보안 그룹, IAM 역할, 노드 그룹 등 다양한 AWS 리소스의 조합으로 이루어지기 때문입니다.
일반적으로 EKS 클러스터를 Terraform으로 구축할 때는 terraform-aws-modules/eks/aws와 같은 공식 또는 커뮤니티에서 제공하는 Terraform 모듈을 활용하는 것이 좋습니다. 이러한 모듈은 EKS 클러스터 구축에 필요한 모든 리소스를 추상화하여, 몇 줄의 코드로 복잡한 클러스터를 손쉽게 배포할 수 있도록 돕습니다.
# eks-cluster.tf (개념적 예시)
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 19.0"
cluster_name = "my-terraform-eks-cluster"
cluster_version = "1.28"
vpc_id = "vpc-xxxxxxxxxxxxxxxxx" # 기존 VPC ID
subnet_ids = ["subnet-xxxxxxxxxxxxxxxxx", "subnet-yyyyyyyyyyyyyyyyy"] # EKS 클러스터가 사용할 서브넷 ID들
# 추가적인 설정 (IAM 역할, 노드 그룹, 보안 그룹 등)
# ...
}
output "eks_cluster_endpoint" {
description = "EKS 클러스터 API 엔드포인트"
value = module.eks.cluster_endpoint
}
이처럼 모듈을 사용하면 복잡한 Kubernetes 인프라도 IaC 원칙에 따라 관리할 수 있으며, 일관된 방식으로 개발 및 운영 환경에 클러스터를 배포할 수 있습니다.
4. Terraform과 CI/CD 파이프라인 통합
Terraform을 CI/CD(Continuous Integration/Continuous Deployment) 파이프라인에 통합하는 것은 DevOps 문화의 핵심입니다. 이를 통해 인프라 변경 사항을 자동으로 검증하고 배포하여 안정성과 효율성을 극대화할 수 있습니다.
일반적인 CI/CD 워크플로우는 다음과 같습니다.
- Pull Request (PR) 단계: 개발자가 인프라 변경 사항을 PR로 제출하면, CI/CD 파이프라인은
terraform fmt(코드 포맷 검사),terraform validate(구문 및 설정 유효성 검사),terraform plan(변경 계획 생성)을 자동으로 실행합니다.plan결과는 PR 코멘트로 공유되어 동료 검토에 활용됩니다. - Merge 및 배포 단계: PR이 승인되어
main브랜치에 병합되면, CI/CD 파이프라인은terraform apply를 실행하여 실제 인프라에 변경 사항을 적용합니다.
GitHub Actions를 활용한 CI/CD 예시
GitHub Actions를 사용하여 Terraform CI/CD 파이프라인을 구축하는 간단한 예시입니다. 이 워크플로우는 PR 시 plan을 실행하고, main 브랜치에 푸시될 때 apply를 실행합니다.
# .github/workflows/terraform.yml
name: Terraform CI/CD
on:
pull_request:
branches:
- main
push:
branches:
- main
jobs:
terraform:
name: "Terraform"
runs-on: ubuntu-latest
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: "ap-northeast-2" # Terraform Provider 설정과 동일하게 지정
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.x.x # 원하는 Terraform 버전 지정 (예: 1.5.x)
- name: Terraform Init
id: init
run: terraform init
- name: Terraform Format Check
id: fmt
run: terraform fmt -check
- name: Terraform Validate
id: validate
run: terraform validate
- name: Terraform Plan
id: plan
if: github.event_name == 'pull_request'
run: terraform plan -no-color
- name: Terraform Apply
id: apply
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: terraform apply -auto-approve
이 워크플로우는 AWS 자격 증명(Access Key ID, Secret Access Key)을 GitHub Secrets에 저장하여 보안을 유지합니다. terraform plan의 출력은 GitHub Actions 로그에서 확인할 수 있으며, 실제 프로덕션 환경에서는 이 출력을 PR 코멘트로 자동 게시하는 등의 추가적인 작업을 통해 리뷰 프로세스를 강화할 수 있습니다.
5. Terraform 모범 사례 및 고급 활용 팁
Terraform을 효율적이고 안정적으로 사용하기 위한 몇 가지 모범 사례와 고급 활용 팁을 소개합니다.
원격 Backend 설정 (AWS S3 + DynamoDB)
Terraform State 파일은 인프라의 실제 상태를 추적하는 중요한 파일이므로, 로컬에 저장하는 대신 원격으로 관리해야 합니다. S3 버킷에 State 파일을 저장하고 DynamoDB 테이블로 잠금(Locking) 기능을 구현하여 여러 명이 동시에 작업을 수행할 때 발생할 수 있는 State 충돌을 방지하는 것이 일반적인 방법입니다.
먼저 S3 버킷과 DynamoDB 테이블을 수동으로 생성하거나, 별도의 Terraform 설정으로 생성해야 합니다.
# S3 버킷 생성 (예시)
aws s3 mb s3://my-terraform-state-bucket-12345 --region ap-northeast-2
# DynamoDB 테이블 생성 (예시)
aws dynamodb create-table \
--table-name terraform-lock-table \
--attribute-definitions AttributeName=LockID,AttributeType=S \
--key-schema AttributeName=LockID,KeyType=HASH \
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
--region ap-northeast-2
그 다음 Terraform 설정에 backend 블록을 추가합니다.
# backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket-12345" # 위에서 생성한 S3 버킷 이름
key = "global/terraform.tfstate" # State 파일이 저장될 경로 및 이름
region = "ap-northeast-2"
encrypt = true # State 파일 암호화
dynamodb_table = "terraform-lock-table" # 위에서 생성한 DynamoDB 테이블 이름
}
}
terraform init 명령을 다시 실행하면 Terraform은 State 파일을 S3 버킷으로 마이그레이션하고 DynamoDB를 통해 잠금 기능을 활성화합니다.
Terraform Workspace 활용
Terraform Workspace는 동일한 구성 파일로 여러 환경(예: 개발, 스테이징, 프로덕션)의 인프라를 관리할 때 유용합니다. 각 Workspace는 별도의 State 파일을 가지므로, 환경별로 독립적인 인프라를 유지할 수 있습니다.
# 새로운 Workspace 생성
terraform workspace new dev
terraform workspace new prod
# Workspace 목록 확인
terraform workspace list
# Workspace 전환
terraform workspace select dev
# 현재 Workspace 확인
terraform workspace show
Workspace를 사용하면 terraform.tfvars 파일이나 변수를 조합하여 환경별 설정을 유연하게 적용할 수 있습니다.
모듈화 (Modularity)
반복되는 인프라 패턴이나 복잡한 리소스 그룹은 모듈로 만들어 재사용성을 높여야 합니다. 예를 들어, 모든 서비스에 필요한 VPC, 서브넷, 보안 그룹 등을 하나의 네트워크 모듈로 만들고, 각 서비스는 해당 모듈을 호출하여 일관된 네트워크 환경을 구축할 수 있습니다.
# modules/network/main.tf (모듈 정의 예시)
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
# ...
}
# main.tf (모듈 사용 예시)
module "my_network" {
source = "./modules/network" # 로컬 모듈 경로
vpc_cidr = "10.0.0.0/16"
}
보안: 민감한 데이터 관리
Terraform 구성 파일에 데이터베이스 비밀번호, API 키 등 민감한 정보를 직접 포함하는 것은 보안상 매우 위험합니다. 다음과 같은 방법을 사용하여 민감한 데이터를 안전하게 관리해야 합니다.
- 변수 사용 및 CLI 입력:
terraform apply시--var옵션이나 환경 변수를 통해 민감한 값을 전달합니다. - 클라우드 서비스 통합: AWS Secrets Manager, HashiCorp Vault와 같은 비밀 관리 서비스를 활용하여 민감한 정보를 저장하고, Terraform이 이 서비스를 통해 동적으로 값을 가져오도록 설정합니다.
- Terraform Cloud / Enterprise: 원격 State 관리와 더불어 변수 암호화 기능을 제공하여 민감한 데이터를 안전하게 관리할 수 있습니다.
마무리
이 글에서는 Terraform을 활용한 인프라 자동화의 기본 개념부터 Docker 및 Kubernetes 인프라 구축, CI/CD 파이프라인 통합, 그리고 모범 사례에 이르기까지 DevOps 엔지니어링 관점에서 심도 있게 살펴보았습니다. Terraform은 선언적인 코드로 인프라를 관리하여 일관성, 확장성, 효율성을 크게 향상시키는 강력한 도구입니다.
IaC의 핵심인 Terraform을 숙달함으로써, 여러분은 더욱 빠르고 안정적으로 서비스를 배포하고 관리할 수 있는 현대적인 DevOps 엔지니어링 역량을 갖추게 될 것입니다. 지금 바로 Terraform을 시작하여 여러분의 인프라를 코드로 정의하고 자동화하는 여정을 시작하시길 바랍니다.
관련 게시글
GitOps Workflow 설계 가이드: Kubernetes와 CI/CD를 활용한 자동화
GitOps는 선언적 인프라 및 애플리케이션 관리를 위한 강력한 패러다임입니다. 이 가이드에서는 Git을 Single Source of Truth로 활용하여 Kubernetes 환경에서 안정적이고 효율적인 GitOps 워크플로우를 설계하는 방법을 Docker, CI/CD 자동화 예시와 함께 상세히 설명합니다.
GitHub Actions Advanced Workflows: Docker, Kubernetes CI/CD
GitHub Actions를 활용한 Docker, Kubernetes 기반 CI/CD 파이프라인 구축 심화 가이드. DevOps 엔지니어링 관점에서 자동화 전략을 탐구합니다.
Terraform Infrastructure Automation Guide: DevOps 효율성 극대화
Terraform을 활용한 인프라 자동화 가이드입니다. IaC 개념부터 AWS 리소스 프로비저닝, Docker/Kubernetes 환경 구축, CI/CD 연동까지 DevOps 엔지니어링 관점에서 자세히 다룹니다.