AWS ECS, Terraform, 그리고 GitHub Actions로 만드는 진정한 DevOps 자동화 환경 (팩트 체크와 최신 워크플로우)

클라우드 인프라의 자동화와 효율적 운영은 개발·운영팀에게 필수가 되고 있습니다. 이 글에서는 실제 사례를 바탕으로 Terraform, Docker, AWS ECS Fargate, 그리고 GitHub Actions 조합으로 프로덕션 환경을 구축하는 과정과 각 기술의 최신 변화, 그리고 워크플로우를 핵심만 간추려 설명합니다. 팩트 체크를 기반으로 최신 정보만 반영했습니다.
Terraform 상태 잠금과 관리 - 실제 변화점
과거 Terraform은 원격 상태 파일 관리에서 동시성 제어를 위해 S3와 DynamoDB 테이블의 상태 잠금(Locking) 기능을 함께 활용하는 것이 권장되었습니다. 하지만, 2024년 6월 기준 Terraform 최신 버전(1.6.x 이후)에서는 DynamoDB 잠금 기능이 공식적으로 제거되지 않았으며, 여전히 S3와 DynamoDB를 병행해 상태 잠금을 설정하는 것이 가능합니다.
팩트: DynamoDB Locking 기능이 제거되었다는 정보는 정확하지 않습니다. 단, 일부 Terraform 사용자의 워크플로우나 모듈에서 DynamoDB 잠금 적용을 생략하는 사례가 증가하는 추세는 있습니다. 공식적으로 잠금 기능 제거 및 미지원은 아닙니다.
따라서 S3만으로 상태 저장이 가능하지만, 생산 환경에서는 동시 작업 충돌 방지를 위해 DynamoDB를 통한 상태 잠금 활용이 권장됩니다.
노트: 이 문서에서는 S3만으로도 상태 관리는 가능하나, 팀의 상황에 맞게 DynamoDB 잠금 적용 여부를 선택할 수 있습니다.
DevOps 자동화 환경 - 준비물과 실제 구성
필수 준비물: AWS 계정, AWS CLI, Docker, Terraform 최신 버전
네트워크 구성: VPC, 퍼블릭 및 프라이빗 서브넷, NAT 게이트웨이, 보안그룹
운영 효율성: Bastion 인스턴스, RDS(Postgres)
상태 파일 관리: S3 버킷(필수), DynamoDB 테이블(선택)
CI/CD 보안: IAM 정책 적용 및 환경 변수 관리
모든 준비가 끝나면 자동화가 훨씬 빨라집니다.
DevOps 자동화 최신 워크플로우 (팩트 기준)
로컬 개발 및 커밋
코드 작성 및 lint/포매팅, 로컬 검토 또는 GitHub Actions로 자동 검사
Terraform 인프라 검토
Pull Request 생성 시,
terraform plan
으로 변경점 리뷰실행 플랜 본문에 자동 첨부
배포 승인 및 적용
승인 후 main 브랜치 병합, GitHub Actions가
terraform apply
수행Slack·이메일 알림(선택적 설정)
API 및 DB 테스트
자동 디플로이 이후 실제 엔드포인트 확인
Bastion 경유 DB 접근성 테스트, Postman 등으로 API 정상 동작 체크
자원 파괴 및 환경 정리
개발/스테이징 환경은
terraform destroy
로 리소스 사용 후 삭제프로덕션은 모니터링·복구·비용 관리 필수
모니터링, 백업, 장애 대응
CloudWatch, Prometheus, Slack 알림 등
주기적 백업, 비상대응 체계 마련
실전 인프라 구성 요약
VPC, 서브넷, NAT, Bastion 인스턴스
RDS(Postgres) 접근은 Bastion 인스턴스 경유만 허용
ECS Fargate에 Golang API 및 Nginx Reverse Proxy 배포
ALB, Route53으로 트래픽 및 SSL 인증 관리
상세 소스코드와 예시는 참조 문서 및 공식 예제를 이용하세요.
노트: 모든 설명은 2024년 6월 기준 Terraform 공식 문서, AWS 문서, 및 최신 DevOps 사례를 기반으로 팩트 체크하였습니다.
비용 관리와 안정성 팁
클라우드에서는 불필요한 자원 정리가 매우 중요합니다.
docker-compose -f docker-compose.yaml run --rm terraform destroy -auto-approve
Production 환경에서는 반드시 모니터링, 백업, 장애대응 프로세스를 준비하세요.
핵심 정리
인프라는 코드로 관리하고 배포 자동화
상태 잠금: S3+옵션 DynamoDB (생산 환경에서 권장)
비용과 보안 체크는 필수
2024년 기준 DynamoDB 상태 잠금은 사용 가능 (단, 워크플로우에 따라 생략 가능)
DevOps 자동화 구축, 직접 실습하며 궁금증은 댓글로 남겨주세요!
참고 문서 및 출처
실전 Terraform 코드 예제 섹션
아래는 실제 AWS ECS Fargate 기반의 DevOps 자동화 환경을 위한 Terraform 코드 예시입니다. 이 소스는 VPC, 서브넷, ECS 클러스터, 서비스, S3 상태 관리(옵션 DynamoDB), 그리고 IAM 권한 등의 기본 요소를 담고 있어, 바로 실무 적용이 가능합니다.
provider "aws" {
region = "ap-northeast-2"
}
terraform {
backend "s3" {
bucket = "your-terraform-state-bucket"
key = "ecs/terraform.tfstate"
region = "ap-northeast-2"
dynamodb_table = "your-tf-lock-table" # 옵션: 상태 잠금용 DynamoDB
encrypt = true
}
}
# VPC 생성
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = { Name = "devops-vpc" }
}
# 퍼블릭 서브넷 & 프라이빗 서브넷
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
tags = { Name = "public-subnet" }
}
resource "aws_subnet" "private" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.2.0/24"
availability_zone = "ap-northeast-2a"
tags = { Name = "private-subnet" }
}
# ECS 클러스터
resource "aws_ecs_cluster" "main" {
name = "devops-ecs-cluster"
}
# ECS Fargate 서비스 샘플 (API 서버)
resource "aws_ecs_task_definition" "api" {
family = "golang-api-task"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "256"
memory = "512"
container_definitions = jsonencode([
{
name = "app"
image = "your-dockerhub-id/your-golang-app:latest"
portMappings = [
{ containerPort = 8080, protocol = "tcp" }
]
environment = [
{ name = "ENV", value = "production" }
]
}
])
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
}
resource "aws_ecs_service" "api" {
name = "api-service"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.api.arn
desired_count = 1
launch_type = "FARGATE"
network_configuration {
subnets = [aws_subnet.private.id]
assign_public_ip = false
security_groups = [aws_security_group.api.id]
}
}
# ECS 실행 역할 예시
resource "aws_iam_role" "ecs_task_execution_role" {
name = "ecsTaskExecutionRole"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Principal = { Service = "ecs-tasks.amazonaws.com" },
Effect = "Allow"
}
]
})
}
resource "aws_iam_role_policy_attachment" "ecs_execution_policy" {
role = aws_iam_role.ecs_task_execution_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
# 보안 그룹 예시
resource "aws_security_group" "api" {
name = "api-sg"
vpc_id = aws_vpc.main.id
description = "Allow inbound traffic for API"
ingress = [
{ from_port = 8080, to_port = 8080, protocol = "tcp", cidr_blocks = ["0.0.0.0/0"] }
]
egress = [
{ from_port = 0, to_port = 0, protocol = "-1", cidr_blocks = ["0.0.0.0/0"] }
]
}
# DynamoDB 상태 잠금(선택)
resource "aws_dynamodb_table" "tf_locks" {
name = "your-tf-lock-table"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
# S3 백엔드 예시
resource "aws_s3_bucket" "tf_state" {
bucket = "your-terraform-state-bucket"
acl = "private"
force_destroy = true
versioning {
enabled = true
}
tags = { Name = "terraform-state" }
}
위 예시의 리소스 네이밍, Docker 이미지 경로 등은 실습 환경에 맞게 수정하세요. 실제 배포에서는 ALB, RDS, Bastion 등 추가 리소스와 GitHub Actions 연동(workflow yaml)도 함께 적용하면 됩니다.
이 코드를 참고하여 인프라를 코드로 신속하게 구축하고, DevOps 파이프라인에서 자동화의 완성도를 높일 수 있습니다.