배포 파이프라인이 Error acquiring the state lock 메시지와 함께 멈춰버리는 현상은 DevOps 엔지니어라면 누구나 한 번쯤 겪는 식은땀 나는 상황입니다. 보통 Jenkins나 GitHub Actions 작업이 네트워크 이슈나 타임아웃으로 비정상 종료되었을 때, Terraform 프로세스가 State 파일에 걸어둔 잠금을 해제하지 못하고 죽으면서 발생합니다. 단순히 잠금을 강제로 푸는 것만이 능사가 아닙니다. 오늘은 이 문제의 근본 원인인 DynamoDB Locking 메커니즘을 파헤치고, IaC CI/CD 환경에서 재발을 방지하는 아키텍처를 다룹니다.
Terraform State Lock 현상 분석과 위험성
팀 단위로 인프라를 관리할 때, 여러 엔지니어가 동시에 terraform apply를 실행하면 State 파일이 오염될 위험이 있습니다. 이를 방지하기 위해 Terraform은 원격 백엔드(Remote Backend) 사용 시 잠금 기능을 제공합니다. AWS 환경에서는 S3가 State 저장소 역할을 하지만, S3 자체는 원자적(Atomic) 잠금을 지원하지 않습니다. 그래서 우리는 Amazon DynamoDB 테이블을 추가로 연동하여 잠금 장치(Mutex)로 사용합니다.
terraform.tfstate 파일이 깨질 수 있습니다. 이는 전체 인프라 관리 불능 상태로 이어집니다.
로그에서 아래와 같은 Terraform State Lock 에러가 발생했다면, LockID를 먼저 확인해야 합니다.
Error: Error acquiring the state lock
Error message: ConditionalCheckFailedException: The conditional request failed
Lock Info:
ID: 7f08465c-6b3b-155f-862d-04532587520e
Path: terraform.tfstate
Operation: OperationTypeApply
Who: runner@ip-10-0-1-23
Version: 1.5.7
Created: 2024-05-20 09:00:00 UTC
Info:
만약 Who 필드에 명시된 프로세스가 이미 종료된 것이 확실하다면(예: 30분 전에 실패한 CI Job), 그때 비로소 수동 개입이 필요합니다. 더 자세한 백엔드 설정 원리는 HashiCorp 공식 문서를 참고하시기 바랍니다.
해결책 1: 안전하게 잠금 해제하기 (테라폼 트러블슈팅)
가장 빠른 해결책은 Terraform CLI의 강제 해제 명령어를 사용하는 것입니다. 하지만 앞서 언급했듯, 이는 최후의 수단이어야 합니다. 테라폼 트러블슈팅 과정에서 저는 항상 팀원들에게 "해당 Lock ID가 현재 실행 중인 파이프라인의 것이 아닌지 AWS Console에서 확인하라"고 지시합니다.
# 1. 먼저 실행 계획을 확인하려 시도 (여기서도 Lock 에러가 뜹니다)
terraform plan
# 2. 에러 로그에 출력된 Lock ID를 복사하여 강제 해제
# 문법: terraform force-unlock [LOCK_ID]
terraform force-unlock 7f08465c-6b3b-155f-862d-04532587520e
# 3. 사용자 확인 프롬프트에서 'yes' 입력
Do you really want to force-unlock?
Terraform will remove the lock on the remote state.
This will allow local-terraform-state to be modified...
Enter a value: yes
해결책 2: DynamoDB Locking 설정 및 타임아웃 자동화
근본적으로 DevOps 자동화 환경에서는 이러한 좀비 잠금(Zombie Lock)을 최소화해야 합니다. 첫 번째 단계는 백엔드 설정 시 DynamoDB 테이블을 올바르게 연결하는 것입니다. 테이블 생성 시 파티션 키(Partition Key)는 반드시 LockID (String)여야 합니다.
# backend-config.tf
terraform {
backend "s3" {
bucket = "my-corp-terraform-state"
key = "prod/app/terraform.tfstate"
region = "ap-northeast-2"
# DynamoDB Locking 활성화 (필수)
dynamodb_table = "terraform-state-lock-table"
encrypt = true
}
}
-lock-timeout 옵션을 주어 재시도를 유도하는 것이 운영상 유리합니다.
# 5분 동안 잠금 획득을 대기하다가 실패 시 에러 리턴
terraform apply -lock-timeout=5m -auto-approve
잠금 메커니즘 적용 전후 비교
IaC CI/CD 파이프라인에서 State Locking을 적용했을 때와 하지 않았을 때의 안정성 차이는 극명합니다. 최근 프로젝트에서 동시 배포 시나리오를 테스트한 결과는 다음과 같습니다.
| 기능 | Local State (잠금 없음) | S3 단독 (잠금 없음) | S3 + DynamoDB (권장) |
|---|---|---|---|
| 동시성 제어 | 불가능 (덮어쓰기 발생) | 불가능 (Race Condition) | 완벽 지원 (대기열 처리) |
| 협업 안전성 | 매우 낮음 | 낮음 | 높음 |
| 복구 난이도 | 어려움 (Git 이력 의존) | 중간 (S3 버저닝 의존) | 쉬움 (Lock ID 추적 가능) |
안정적인 파이프라인 구축을 위해 Terraform 공식 가이드를 다시 한번 점검해 보시길 권장합니다. 잘못된 백엔드 설정은 인프라 전체의 리스크입니다.
Terraform Backend 설정 공식 가이드 확인SIGINT나 SIGTERM이 제대로 전달되지 않아 잠금이 남는 경우가 많습니다. CI 스크립트 레벨에서 trap 등을 이용해 종료 시그널을 우아하게 처리하거나, 타임아웃을 적절히 설정하는 것이 DevOps 자동화의 핵심입니다.
Conclusion
Terraform State Lock 에러는 시스템이 정상적으로 데이터를 보호하고 있다는 신호입니다. 에러를 두려워하지 말고 LockID를 분석하여 좀비 프로세스를 식별하는 것이 우선입니다. 그 후 force-unlock으로 해결하고, 장기적으로는 lock-timeout 설정과 견고한 CI/CD 종료 처리를 통해 운영 효율성을 높여야 합니다. DynamoDB Locking은 선택이 아닌 필수입니다.
Post a Comment