Terraform Infrastructure Automation Guide: DevOps 효율성 극대화
Terraform을 활용한 인프라 자동화 가이드입니다. IaC 개념부터 AWS 리소스 프로비저닝, Docker/Kubernetes 환경 구축, CI/CD 연동까지 DevOps 엔지니어링 관점에서 자세히 다룹니다.
Terraform Infrastructure Automation Guide: DevOps 효율성 극대화
현대 IT 환경에서 인프라 관리는 더 이상 수동적인 작업이 아닌, 코드 기반의 자동화된 프로세스로 진화하고 있습니다. 특히 DevOps 문화가 확산되면서, Infrastructure as Code(IaC)는 개발 및 운영의 효율성을 극대화하는 핵심 요소로 자리매김했습니다. 이 글에서는 대표적인 IaC 도구인 Terraform을 사용하여 인프라를 효과적으로 자동화하는 방법을 DevOps 엔지니어링 관점에서 심층적으로 다루고자 합니다.
IaC(Infrastructure as Code)와 Terraform의 등장 배경
과거의 인프라 관리는 서버 한 대 한 대에 직접 접속하여 수동으로 설정하거나, 스크립트를 통해 작업을 반복하는 방식이었습니다. 이러한 방식은 인적 오류 발생 가능성이 높고, 환경 간 일관성을 유지하기 어려웠으며, 인프라 변경 이력 추적이 불가능하다는 치명적인 단점을 가지고 있었습니다. 서비스 규모가 커지고 복잡해짐에 따라 이러한 문제점들은 개발 및 배포 속도를 저해하고 운영 비용을 증가시키는 주요 원인이 되었습니다.
이러한 문제들을 해결하기 위해 등장한 개념이 바로 IaC입니다. IaC는 인프라를 코드로 정의하고 관리함으로써, 소프트웨어 개발과 동일한 방식으로 버전 관리, 테스트, 배포가 가능하게 합니다. Terraform은 HashiCorp에서 개발한 오픈소스 IaC 도구로, 다양한 클라우드 프로바이더(AWS, Azure, GCP 등) 및 온프레미스 환경의 인프라를 선언적인(Declarative) 방식으로 프로비저닝하고 관리할 수 있도록 지원합니다. Terraform은 인프라의 현재 상태를 코드로 명시하고, 원하는 상태와 현재 상태의 차이를 분석하여 필요한 변경사항만을 적용하므로, 예측 가능하고 안정적인 인프라 관리가 가능합니다.
Terraform 기본 개념 및 핵심 요소
Terraform은 HCL(HashiCorp Configuration Language)이라는 자체 언어를 사용하여 인프라를 정의합니다. 주요 구성 요소들은 다음과 같습니다.
- Provider: Terraform이 상호작용할 클라우드 또는 서비스(예:
aws,azurerm,google)를 정의합니다. 각 Provider는 해당 서비스의 리소스를 생성, 관리할 수 있는 API를 제공합니다. - Resource: 클라우드 환경에 생성될 실제 인프라 구성 요소(예:
aws_instance,aws_vpc,kubernetes_deployment)를 선언합니다. - Data Source: 이미 존재하는 리소스의 정보를 읽어와 Terraform 설정 내에서 활용할 수 있도록 합니다. (예:
aws_ami로 최신 AMI ID 조회) - Variable: 재사용 가능한 값을 정의하여 설정 파일의 유연성을 높입니다. 환경별 설정이나 민감한 정보(예:
access_key)를 외부에서 주입할 때 유용합니다. - Output: Terraform 스크립트 실행 후 얻고자 하는 결과값(예: 생성된 EC2 인스턴스의 Public IP)을 정의합니다.
- Module: 재사용 가능한 Terraform 코드 묶음으로, 복잡한 인프라를 구조화하고 관리하는 데 도움을 줍니다.
Terraform CLI 명령어는 인프라 관리에 필수적입니다.
-
terraform init: 작업 디렉토리를 초기화하고, 필요한 Provider 플러그인을 다운로드합니다. -
terraform plan: 현재 설정 파일과 기존 인프라 상태를 비교하여 어떤 변경 사항이 발생할지 미리 보여줍니다. 실제 리소스 변경은 일어나지 않습니다. -
terraform apply:plan에서 제시된 변경 사항을 실제 인프라에 적용합니다. -
terraform destroy: Terraform으로 관리되는 모든 리소스를 제거합니다.
AWS EC2 인스턴스 프로비저닝 예제
실제로 Terraform을 사용하여 AWS에 EC2 인스턴스를 프로비저닝하는 과정을 살펴보겠습니다. 이 예제에서는 VPC, Subnet, Security Group, 그리고 Docker가 설치된 EC2 인스턴스를 생성합니다.
먼저, main.tf 파일을 생성합니다.
# main.tf
# 1. AWS Provider 설정
provider "aws" {
region = "ap-northeast-2" # 서울 리전
}
# 2. VPC 생성
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "terraform-vpc"
}
}
# 3. Public Subnet 생성
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-2a"
map_public_ip_on_launch = true # Public IP 자동 할당
tags = {
Name = "terraform-public-subnet"
}
}
# 4. Internet Gateway 생성 및 VPC 연결
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "terraform-igw"
}
}
# 5. Route Table 생성 및 Public Subnet 연결
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0" # 모든 트래픽을 IGW로 라우팅
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "terraform-public-route-table"
}
}
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
# 6. Security Group 생성 (SSH, HTTP 허용)
resource "aws_security_group" "web_sg" {
vpc_id = aws_vpc.main.id
name = "web-security-group"
description = "Allow SSH and HTTP traffic"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # 모든 IP에서 SSH 허용 (실제 환경에서는 제한 필요)
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # 모든 IP에서 HTTP 허용
}
egress {
from_port = 0
to_port = 0
protocol = "-1" # 모든 프로토콜
cidr_blocks = ["0.0.0.0/0"] # 모든 IP로 아웃바운드 허용
}
tags = {
Name = "terraform-web-sg"
}
}
# 7. EC2 Key Pair 생성 (기존 키 페어를 사용하는 것이 일반적)
# resource "aws_key_pair" "my_key_pair" {
# key_name = "my-terraform-key"
# public_key = file("~/.ssh/id_rsa.pub") # 본인의 공개키 경로
# }
# 8. 최신 Amazon Linux 2 AMI ID 조회
data "aws_ami" "amazon_linux_2" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# 9. EC2 인스턴스 생성 및 Docker 설치
resource "aws_instance" "web_server" {
ami = data.aws_ami.amazon_linux_2.id
instance_type = "t2.micro"
subnet_id = aws_subnet.public.id
security_groups = [aws_security_group.web_sg.id]
# key_name = aws_key_pair.my_key_pair.key_name # Key Pair 사용 시 주석 해제
user_data = <<-EOF
#!/bin/bash
yum update -y
amazon-linux-extras install docker -y
service docker start
usermod -a -G docker ec2-user
echo "Hello from Terraform!" > /var/www/html/index.html
EOF
tags = {
Name = "terraform-web-server"
}
}
# 10. EC2 Public IP 출력
output "web_server_public_ip" {
description = "Public IP address of the web server"
value = aws_instance.web_server.public_ip
}
이 코드를 실행하려면:
# Terraform 초기화
terraform init
# 변경 사항 계획 확인
terraform plan
# 인프라 적용
terraform apply --auto-approve
# 인프라 제거 (주의: 모든 리소스가 삭제됩니다)
# terraform destroy --auto-approve
user_data 스크립트를 통해 EC2 인스턴스가 시작될 때 Docker를 자동으로 설치하고 시작하도록 설정했습니다. output을 통해 생성된 EC2 인스턴스의 Public IP를 쉽게 확인할 수 있습니다.
Docker 및 Kubernetes 환경 구축을 위한 Terraform 활용
Terraform은 단일 EC2 인스턴스뿐만 아니라, Docker 컨테이너 오케스트레이션 환경인 Kubernetes 클러스터 구축에도 강력한 도구로 활용됩니다. AWS EKS(Elastic Kubernetes Service), Azure AKS(Azure Kubernetes Service), GCP GKE(Google Kubernetes Engine)와 같은 관리형 Kubernetes 서비스를 Terraform으로 프로비저닝할 수 있습니다.
예를 들어, AWS EKS 클러스터를 Terraform으로 구축하려면, aws_eks_cluster, aws_eks_node_group과 같은 리소스를 사용하게 됩니다. 또한, kubernetes_config_map, kubernetes_deployment 등 Kubernetes Provider를 활용하여 클러스터 내부에 애플리케이션을 배포하는 것까지 자동화할 수 있습니다.
# EKS 클러스터 및 노드 그룹 생성 예시 (간략화)
# 1. EKS 클러스터 생성
resource "aws_eks_cluster" "main" {
name = "my-terraform-eks-cluster"
role_arn = aws_iam_role.eks_cluster_role.arn # EKS 클러스터 IAM Role
vpc_config {
subnet_ids = [aws_subnet.public.id, aws_subnet.private.id] # Public/Private Subnet
}
# ... 추가 설정
}
# 2. EKS 노드 그룹 생성
resource "aws_eks_node_group" "main" {
cluster_name = aws_eks_cluster.main.name
node_group_name = "my-node-group"
node_role_arn = aws_iam_role.eks_node_role.arn # EKS 노드 IAM Role
subnet_ids = [aws_subnet.private.id]
instance_types = ["t3.medium"]
scaling_config {
desired_size = 2
max_size = 3
min_size = 1
}
# ... 추가 설정
}
# 3. Kubernetes Provider 설정 (EKS 클러스터 정보 활용)
provider "kubernetes" {
host = aws_eks_cluster.main.endpoint
cluster_ca_certificate = base64decode(aws_eks_cluster.main.certificate_authority[0].data)
token = data.aws_eks_cluster_auth.main.token
}
data "aws_eks_cluster_auth" "main" {
name = aws_eks_cluster.main.name
}
# 4. Kubernetes Deployment 배포 예시
resource "kubernetes_deployment" "nginx" {
metadata {
name = "nginx-deployment"
labels = {
app = "nginx"
}
}
spec {
replicas = 2
selector {
match_labels = {
app = "nginx"
}
}
template {
metadata {
labels = {
app = "nginx"
}
}
spec {
container {
name = "nginx"
image = "nginx:latest"
port {
container_port = 80
}
}
}
}
}
}
이처럼 Terraform을 사용하면 Kubernetes 클러스터의 인프라부터 그 위에 배포될 애플리케이션의 기본 환경까지 일관된 IaC 방식으로 관리할 수 있습니다. 이는 개발자가 인프라 세부 사항에 덜 신경 쓰고 애플리케이션 개발에 집중할 수 있도록 돕는 진정한 DevOps 접근 방식입니다.
Terraform과 CI/CD 파이프라인 연동
Terraform의 가장 큰 장점 중 하나는 CI/CD(Continuous Integration/Continuous Deployment) 파이프라인과의 강력한 연동성입니다. GitOps 철학을 기반으로 인프라 변경 사항도 코드와 동일하게 Git 저장소에서 관리하고, CI/CD 파이프라인을 통해 자동화된 검증 및 배포를 수행할 수 있습니다.
일반적인 CI/CD 워크플로우는 다음과 같습니다.
- 개발자가 Terraform 코드 변경 후 Git 저장소에 푸시합니다.
- CI/CD 시스템(예: GitHub Actions, GitLab CI, Jenkins)이 변경을 감지합니다.
- 파이프라인이
terraform init및terraform plan을 실행하여 예상되는 변경 사항을 생성합니다. 이plan결과는 Pull Request(PR) 코멘트로 첨부되어 코드 리뷰어들이 인프라 변경을 검토할 수 있도록 합니다. - PR이 승인되고 Merge되면,
terraform apply단계가 실행되어 실제 인프라에 변경 사항을 적용합니다.
GitHub Actions를 사용한 간단한 terraform plan 워크플로우 예시입니다.
# .github/workflows/terraform-plan.yml
name: Terraform Plan
on:
pull_request:
branches:
- main
paths:
- 'terraform/**' # Terraform 코드 경로에 따라 변경
jobs:
terraform:
name: 'Terraform Plan'
runs-on: ubuntu-latest
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ap-northeast-2
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.x.x # 원하는 Terraform 버전
- name: Terraform Init
id: init
run: terraform init
working-directory: ./terraform # Terraform 코드 경로
- name: Terraform Plan
id: plan
run: terraform plan -no-color
working-directory: ./terraform
continue-on-error: true # plan 실패해도 다음 스텝 진행
- name: Add Terraform Plan to PR comment
uses: actions/github-script@v6
if: github.event_name == 'pull_request'
with:
script: |
const output = `#### Terraform Plan 📖
\`\`\`
${process.env.PLAN_OUTPUT}
\`\`\`
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
env:
PLAN_OUTPUT: ${{ steps.plan.outputs.stdout }}
이 워크플로우는 terraform 디렉토리 내의 변경 사항이 있는 PR이 생성될 때마다 terraform plan을 실행하고, 그 결과를 PR 코멘트로 남겨 인프라 변경 사항을 투명하게 검토할 수 있도록 합니다. terraform apply는 일반적으로 main 브랜치에 merge된 후에 실행되도록 설정하며, 안전을 위해 수동 승인 단계를 추가하는 것이 좋습니다.
Terraform State 관리 및 모듈화 전략
Terraform은 프로비저닝한 인프라의 실제 상태를 terraform.tfstate라는 파일에 기록합니다. 이 State 파일은 Terraform이 인프라의 현재 상태를 파악하고, plan 및 apply 작업을 수행하는 데 필수적인 역할을 합니다. State 파일이 손상되거나 유실되면 인프라를 제대로 관리할 수 없게 되므로, State 파일 관리는 매우 중요합니다.
원격 백엔드 (Remote Backend)
로컬에 State 파일을 저장하는 대신, AWS S3, Azure Blob Storage, Google Cloud Storage 등과 같은 원격 백엔드를 사용하는 것이 권장됩니다. 원격 백엔드를 사용하면 다음과 같은 이점을 얻을 수 있습니다.
- 협업 용이성: 여러 팀원이 동시에 작업할 때 State 파일 충돌을 방지하고 일관된 상태를 유지합니다.
- 안정성: State 파일 유실 위험을 줄이고, 백업 및 복구가 용이합니다.
- State Locking: 여러 사용자가 동시에
terraform apply를 실행하려 할 때, State 파일 잠금을 통해 충돌을 방지합니다. (예: AWS DynamoDB와 연동)
AWS S3와 DynamoDB를 활용한 원격 백엔드 설정 예시입니다.
# backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket-12345" # 고유한 버킷 이름
key = "dev/network/terraform.tfstate" # State 파일 경로
region = "ap-northeast-2"
encrypt = true # 암호화 활성화
dynamodb_table = "terraform-state-lock" # State Locking을 위한 DynamoDB 테이블
}
}
모듈화 (Module)
Terraform 모듈은 재사용 가능한 인프라 코드의 단위입니다. 반복되는 인프라 패턴(예: VPC, EC2 인스턴스 그룹, RDS 데이터베이스)을 모듈로 만들어두면, 다른 프로젝트나 환경에서 손쉽게 재사용할 수 있습니다. 이는 코드의 중복을 줄이고, 일관성을 유지하며, 복잡한 인프라를 구조화하는 데 매우 효과적입니다.
# main.tf (모듈 사용 예시)
# 기존에 정의된 VPC 모듈 사용
module "my_vpc" {
source = "./modules/vpc" # 로컬 경로 또는 Git 리포지토리 URL
vpc_cidr = "10.10.0.0/16"
subnet_cidrs = ["10.10.1.0/24", "10.10.2.0/24"]
}
# EC2 인스턴스 모듈 사용
module "web_servers" {
source = "./modules/ec2-instance"
instance_count = 3
instance_type = "t3.medium"
subnet_id = module.my_vpc.public_subnet_ids[0]
security_group_ids = [aws_security_group.web_sg.id]
}
모듈을 통해 인프라 코드를 추상화하고, 각 모듈이 특정 기능을 담당하도록 설계함으로써 대규모 인프라를 효율적으로 관리할 수 있습니다.
마무리
Terraform은 Infrastructure as Code(IaC)의 강력한 구현체로서, 현대 DevOps 엔지니어링의 핵심 도구로 자리매김했습니다. 인프라를 코드로 관리함으로써 수동 작업의 비효율성과 오류를 줄이고, 안정적이고 예측 가능한 방식으로 인프라를 프로비저닝하고 관리할 수 있게 됩니다. AWS, Docker, Kubernetes 환경 구축부터 CI/CD 파이프라인 연동에 이르기까지, Terraform은 인프라 자동화의 거의 모든 영역을 포괄하며 개발 및 운영 효율성을 극대화하는 데 크게 기여합니다. 지속적인 학습과 모범 사례 적용을 통해 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: DevOps 엔지니어링 가이드
Terraform을 활용한 인프라 자동화의 핵심 개념부터 실제 AWS 환경에서의 배포 예시까지, DevOps 엔지니어링 관점에서 자세히 알아봅니다. IaC, Docker, Kubernetes, CI/CD 파이프라인 통합 전략을 다룹니다.