LabHub

Terraform/OpenTofu 기초 · plan 읽는 법 · 이론

계획을 읽는 법 — 기호, 종료 코드, 드리프트

LabHub 에서 이어서 보기

한 줄 요약

applyplan 이 이미 내린 결정을 실행할 뿐이다. 사고를 막을 수 있는 유일한 자리는 계획을 읽는 몇 분이고, 그 몇 분은 결국 사람이 아니라 스크립트가 대신해야 한다.

왜 이게 필요했나

인프라 코드에서 가장 비싼 실수는 "재생성을 제자리 수정으로 잘못 읽은 것"이다. 화면에 뜬 -/+~ 로 착각하면 프로덕션 데이터베이스가 지워졌다가 다시 만들어진다. 계획 출력은 길고, 배포는 대개 늦은 시간에 이뤄지며, 사람의 눈은 같은 화면을 세 번 보면 읽지 않기 시작한다.

그래서 성숙한 팀은 두 가지를 한다. 첫째, 계획을 파일로 저장해 리뷰한 그 계획을 그대로 적용한다. 저장하지 않으면 리뷰한 계획과 실제 적용되는 계획이 다를 수 있다. 그 사이에 누군가 다른 것을 바꿨을 수 있기 때문이다. 둘째, 계획을 기계가 읽는 형식으로 뽑아 규칙으로 판정한다. "삭제가 하나라도 있으면 사람 승인" 같은 규칙은 사람이 아니라 파이프라인이 지켜야 한다.

어떻게 동작하나

사람이 읽는 계획에는 기호가 붙는다.

| 기호 | 뜻 | 위험도 |
| --- | --- | --- |
| + | 생성 | 낮음 |
| ~ | 제자리 수정 | 보통 |
| - | 삭제 | 높음 |
| -/+ | 삭제 후 재생성 | 매우 높음 |
| +/- | 생성 후 삭제 (create_before_destroy) | 높음 |
| <= | 데이터 소스 읽기 | 없음 |

재생성이 나오는 이유는 대개 변경할 수 없는 인자를 건드렸기 때문이고, 그런 줄에는 # forces replacement 표시가 붙는다. 맨 아래 요약 줄인 Plan: X to add, Y to change, Z to destroy 에서 재생성은 add 와 destroy 양쪽에 1씩 잡힌다는 점도 기억해야 한다.

자동화에 필요한 것은 기호가 아니라 두 가지다. 하나는 -detailed-exitcode 다.

| 종료 코드 | 의미 |
| --- | --- |
| 0 | 변경 없음 |
| 1 | 오류 |
| 2 | 변경 있음 |

이 세 값 덕분에 "변경이 있으면 알린다" 같은 정기 드리프트 감지를 셸 한 줄로 만들 수 있다. 다른 하나는 JSON 표현이다. 계획 파일을 JSON 으로 바꾸면 resource_changes 배열이 나오고, 각 항목의 change.actions["create"], ["update"], ["delete"], 재생성이면 ["delete","create"] 로 들어 있다. 그리고 resource_drift 에는 조회 단계에서 발견한 코드 밖 변경이 따로 담긴다. 계획에 반영될 변경과 이미 벌어진 변경을 구분해서 볼 수 있다는 뜻이다.

-target 은 그래프의 일부만 골라 처리하는 옵션이다. 쓰면 도구가 경고를 낸다. 일부만 적용하면 나머지가 코드와 어긋난 채로 남아 상태가 일관되지 않을 수 있기 때문이다. 복구 상황의 도구이지 평소 워크플로가 아니다.

현장에서 만나는 모습

첫째, 프로바이더 업그레이드 후의 대량 드리프트. 메이저 버전을 올리면 새로 추가된 속성의 기본값 때문에 수백 개 리소스에 변경이 뜬다. 대부분은 실제 인프라를 바꾸는 것이 아니라 상태에 속성을 채워 넣는 것이다. 이 둘을 구분하지 않고 놀라서 되돌리거나, 반대로 확인 없이 적용하는 것이 모두 사고로 이어진다. JSON 으로 뽑아 동작별로 세어 보면 판단이 빨라진다.

둘째, 감지 자체의 비용. plan 은 관리 중인 모든 리소스에 대해 프로바이더 API 를 부른다. 규모가 크면 API 제한에 걸리고, 감지 도중에는 상태 잠금이 걸려 배포와 충돌한다. 감지 주기는 공짜가 아니다.

셋째, 계획 로그에 남는 비밀. 계획 출력에는 리소스 속성이 그대로 찍힌다. 알림 채널이나 CI 로그에 통째로 붙여 넣는 습관은 그대로 유출 경로가 된다. 요약만 보내고 전체는 접근이 통제된 곳에 두는 것이 안전하다.

다음 실습에서 할 것

/root/tf/plan 에서 계획을 파일로 저장해 JSON 으로 바꾸고, 동작별 개수를 세어 기록한다. -detailed-exitcode 의 두 가지 종료 코드를 직접 확인하고, 제자리 수정과 재생성이 한 계획 안에 함께 잡히게 만든다. 관리 중인 파일을 손으로 고쳐 resource_drift 를 보고, -target 으로 범위를 좁히며 도구의 경고를 읽는다. 마지막에는 삭제가 포함된 계획을 스스로 판정하는 리뷰 보고서를 만든다.