본문 바로가기

Troubleshooting

Terraform Error acquiring the state lock 해결 방법

반응형

terraform plan을 실행했는데 "Error acquiring the state lock"이 뜨면서 아무 작업도 진행되지 않습니다. 팀원이 작업 중인 것도 아닌데 lock이 걸려 있습니다. CI/CD 파이프라인이 중간에 실패하면서 lock이 해제되지 않은 경우, 이 상황이 자주 발생합니다.

Troubleshooting DevOps/Terraform Level 2 10분

핵심 요약

구분 내용
에러 메시지 Error acquiring the state lock
원인 이전 Terraform 실행이 비정상 종료되면서 DynamoDB Lock이 해제되지 않음
즉시 해결 terraform force-unlock <LOCK_ID>
근본 원인 CI/CD timeout, 수동 중단(Ctrl+C), 네트워크 단절, 프로세스 강제 종료
재발 방지 CI/CD timeout 설정, Graceful shutdown, Lock 모니터링 알람

1. 에러 메시지 원문

│ Error: Error acquiring the state lock
│
│ Error message: ConditionalCheckFailedException: The conditional request failed
│ Lock Info:
│   ID:        a1b2c3d4-e5f6-7890-abcd-ef1234567890
│   Path:      my-terraform-state/prod/terraform.tfstate
│   Operation: OperationTypePlan
│   Who:       runner@github-actions-12345
│   Version:   1.8.2
│   Created:   2026-06-04 09:15:32.123456 +0000 UTC
│   Info:
│
│ Terraform acquires a state lock to protect the state from being written
│ by multiple users at the same time. Please resolve the lock issue listed
│ above before retrying this operation.
│
│ To "unlock" the state, use the force-unlock command:
│   terraform force-unlock a1b2c3d4-e5f6-7890-abcd-ef1234567890

이 에러는 Terraform이 State에 대한 Lock을 획득하려 했으나, 이미 다른 프로세스가 Lock을 보유하고 있어 실패했다는 의미입니다.

2. State Lock 동작 원리

Terraform은 plan, apply, destroy 등 State를 읽거나 쓰는 모든 작업 전에 Lock을 획득합니다. 작업이 완료되면 Lock을 해제합니다.

S3 Backend + DynamoDB 조합에서의 Lock 흐름:

  1. terraform plan 실행
  2. DynamoDB 테이블에 Lock 레코드 생성 (Conditional Put)
  3. S3에서 State 파일 읽기
  4. Plan 계산
  5. DynamoDB Lock 레코드 삭제
State Lock 정상 동작 흐름
State Lock 정상 동작 흐름

문제는 3~4단계에서 프로세스가 비정상 종료되면 5단계(Lock 해제)가 실행되지 않는다는 것입니다.

3. 원인별 분석

3-1. CI/CD 파이프라인 timeout

가장 흔한 원인입니다.

시나리오: GitHub Actions에서 terraform apply를 실행 중입니다. 대규모 인프라 변경으로 15분이 걸리는데, Job timeout이 10분으로 설정되어 있습니다. 10분 시점에 Runner가 강제 종료되면서 Lock이 남습니다.

# GitHub Actions — timeout으로 인한 Lock 잔류 원인
jobs:
  terraform:
    runs-on: ubuntu-latest
    timeout-minutes: 10  # 이 시간 초과 시 프로세스 강제 종료
    steps:
      - run: terraform apply -auto-approve
        # 대규모 변경 시 10분 초과 → Lock 미해제

3-2. 수동 중단 (Ctrl+C)

로컬에서 terraform apply 실행 중 Ctrl+C를 두 번 누르면 Graceful shutdown이 아닌 즉시 종료가 됩니다.

  • Ctrl+C 1회: Terraform이 현재 리소스 작업을 완료한 후 종료 (Lock 정상 해제)
  • Ctrl+C 2회: 즉시 종료 (Lock 미해제)

3-3. 네트워크 단절

terraform apply 실행 중 VPN 연결이 끊기거나 네트워크 장애가 발생하면, DynamoDB에 Lock 해제 요청을 보내지 못합니다.

3-4. 동시 실행

팀원 A가 terraform plan을 실행 중인 상태에서 팀원 B가 같은 State에 대해 terraform apply를 실행하는 경우입니다. 이 경우는 정상적인 보호 메커니즘이므로 A의 작업이 완료될 때까지 기다리면 됩니다.

State Lock 에러 원인 구조
State Lock 에러 원인 구조

4. 해결 방법

4-1. 먼저 확인: 실제로 누군가 작업 중인가?

Lock을 강제 해제하기 전에 반드시 확인해야 합니다.

# Lock 정보에서 Who 필드 확인
# Who: runner@github-actions-12345 → CI/CD에서 실행된 작업
# Who: username@hostname → 특정 팀원이 로컬에서 실행 중

# DynamoDB에서 Lock 레코드 직접 확인
aws dynamodb get-item \
  --table-name terraform-state-lock \
  --key '{"LockID": {"S": "my-terraform-state/prod/terraform.tfstate"}}' \
  --query 'Item.Info.S' \
  --output text

확인 결과에 따른 판단:

상황 조치
팀원이 현재 작업 중 기다림 (정상 Lock)
CI/CD Job이 이미 실패/종료됨 강제 해제 가능
Lock 생성 시간이 수 시간 전 높은 확률로 orphaned Lock → 강제 해제
본인이 Ctrl+C로 종료한 직후 강제 해제 가능

4-2. 강제 해제 (force-unlock)

Lock이 orphaned 상태임을 확인한 후 강제 해제합니다.

# Lock ID는 에러 메시지에 표시됨
terraform force-unlock a1b2c3d4-e5f6-7890-abcd-ef1234567890

실행하면 확인 프롬프트가 표시됩니다:

Do you really want to force-unlock?
  Terraform will remove the lock on the remote state.
  This will allow local Terraform commands to modify this state, even though it
  may still be in use. Only 'yes' will be accepted to confirm.

  Enter a value: yes

yes를 입력하면 DynamoDB에서 Lock 레코드가 삭제됩니다.

주의
force-unlock은 실제로 작업 중인 프로세스가 없을 때만 사용해야 합니다. 다른 프로세스가 State를 수정하는 중에 Lock을 해제하면 State 파일이 손상될 수 있습니다.

4-3. DynamoDB에서 직접 삭제 (비상 상황)

드문 경우지만, terraform force-unlock이 실패할 수 있습니다. 이때는 DynamoDB에서 Lock 레코드를 직접 삭제합니다.

# DynamoDB Lock 레코드 직접 삭제
aws dynamodb delete-item \
  --table-name terraform-state-lock \
  --key '{"LockID": {"S": "my-terraform-state/prod/terraform.tfstate"}}'

이 방법은 Terraform CLI를 통하지 않으므로 더 위험합니다. State 파일의 무결성을 반드시 확인해야 합니다.

# Lock 해제 후 State 무결성 확인
terraform plan
# "No changes" 또는 예상된 변경만 표시되면 정상
State Lock 해결 흐름
State Lock 해결 흐름

5. 실무 시나리오: CI/CD에서 반복 발생

상황: GitHub Actions에서 Terraform을 운영하는 팀입니다. 주 2~3회 terraform apply Job이 timeout으로 실패하면서 Lock이 남습니다. 매번 수동으로 force-unlock을 실행하고 있습니다.

근본 원인 분석:

  • Infrastructure 규모가 커지면서 apply 시간이 증가
  • Job timeout은 초기 설정(10분) 그대로 유지
  • timeout 시 Runner가 SIGKILL로 프로세스를 종료하므로 Graceful shutdown 불가

해결 전략:

# 1. Job timeout 충분히 확보
jobs:
  terraform:
    runs-on: ubuntu-latest
    timeout-minutes: 30  # apply 예상 시간 + 여유분

    steps:
      # 2. apply 전에 orphaned lock 자동 확인/해제
      - name: Check and clear stale locks
        run: |
          LOCK_INFO=$(aws dynamodb get-item \
            --table-name terraform-state-lock \
            --key '{"LockID": {"S": "my-terraform-state/prod/terraform.tfstate"}}' \
            --query 'Item.Info.S' \
            --output text 2>/dev/null)

          if [ "$LOCK_INFO" != "None" ] && [ -n "$LOCK_INFO" ]; then
            LOCK_CREATED=$(echo "$LOCK_INFO" | jq -r '.Created')
            LOCK_AGE_MINUTES=$(( ($(date +%s) - $(date -d "$LOCK_CREATED" +%s)) / 60 ))

            if [ $LOCK_AGE_MINUTES -gt 30 ]; then
              echo "Stale lock detected (${LOCK_AGE_MINUTES}min old). Force unlocking..."
              LOCK_ID=$(echo "$LOCK_INFO" | jq -r '.ID')
              terraform force-unlock -force "$LOCK_ID"
            else
              echo "Active lock detected (${LOCK_AGE_MINUTES}min old). Waiting..."
              exit 1
            fi
          fi

      # 3. apply 실행
      - name: Terraform Apply
        run: terraform apply -auto-approve

      # 4. 실패 시에도 lock 해제 시도
      - name: Cleanup lock on failure
        if: failure()
        run: |
          terraform force-unlock -force $(terraform show -json 2>/dev/null | jq -r '.lock_id // empty') || true

6. 재발 방지 전략

6-1. CI/CD timeout 설정

# GitHub Actions
timeout-minutes: 30

# GitLab CI
job:
  timeout: 30m

# Jenkins
timeout(time: 30, unit: 'MINUTES') {
  sh 'terraform apply -auto-approve'
}

apply 시간은 인프라 규모에 따라 달라집니다. 모니터링을 통해 평균 소요 시간을 파악하고, 2배 정도의 여유를 두는 것이 일반적입니다.

6-2. State 분리로 Lock 범위 축소

하나의 State에 모든 리소스를 넣으면 apply 시간이 길어지고 Lock 충돌 확률도 높아집니다.

# 단일 State (비권장 — 대규모 환경)
infrastructure/
  main.tf          # VPC + EKS + RDS + ... 모든 리소스
  terraform.tfstate # Lock 시간: 15분+

# 분리된 State (권장)
infrastructure/
  network/         # VPC, Subnet, NAT → Lock 시간: 2분
  compute/         # EKS, ASG → Lock 시간: 5분
  database/        # RDS, ElastiCache → Lock 시간: 3분

State를 분리하면: - 각 apply의 실행 시간이 짧아져 timeout 위험이 줄어듦 - Lock 범위가 좁아져 팀원 간 충돌 가능성이 감소 - 한 영역의 Lock 문제가 다른 영역에 영향을 주지 않음

6-3. Lock 모니터링 알람

DynamoDB에 Lock 레코드가 일정 시간 이상 존재하면 알람을 보냅니다.

# CloudWatch 알람으로 stale lock 감지
# DynamoDB Streams + Lambda 조합
# Lock 생성 후 30분 이상 해제되지 않으면 Slack 알림

6-4. Ctrl+C 사용 규칙 (로컬 작업)

팀 내 규칙으로 공유합니다:

상황 올바른 대응
apply 중 중단하고 싶을 때 Ctrl+C 1회만 누르고 대기
plan 중 중단하고 싶을 때 Ctrl+C 1회 (즉시 종료됨)
이미 Ctrl+C 2회 눌렀을 때 force-unlock 실행

7. State Lock Backend별 차이

State Lock은 Backend 유형에 따라 메커니즘이 다릅니다.

Backend Lock 메커니즘 Lock 저장 위치
S3 + DynamoDB DynamoDB Conditional Put DynamoDB 테이블
Azure Blob Storage Blob Lease Azure Storage Account
GCS (Google Cloud Storage) Object Lock GCS 버킷 내 .tflock 파일
Terraform Cloud 내장 Lock Terraform Cloud 서버
Consul KV Store Lock Consul 클러스터

Backend별 force-unlock 동작은 동일합니다. Terraform CLI가 Backend 유형에 맞게 Lock 해제를 처리합니다.

Tip
Azure Blob Storage Backend의 경우 Blob Lease가 만료 시간(보통 60초)을 가집니다. 프로세스가 비정상 종료되면 Lease가 자동 만료되므로, DynamoDB처럼 orphaned lock이 영구 지속되는 문제가 덜 발생합니다.

8. 정리

  • Error acquiring the state lock은 이전 실행이 비정상 종료되면서 Lock이 해제되지 않았을 때 발생합니다.
  • 강제 해제 전에 반드시 실제 작업 중인 프로세스가 없는지 확인합니다.
  • terraform force-unlock <LOCK_ID>로 해제하며, 해제 후 terraform plan으로 State 무결성을 검증합니다.
  • CI/CD에서 반복 발생하면 timeout 설정, State 분리, Lock 모니터링으로 근본 원인을 해결합니다.
  • Ctrl+C는 1회만 눌러 Graceful shutdown을 유도하는 것이 안전합니다.

관련 글

참고 문서

반응형