CGOA — GitOps 인증 어소시에이트 · 삭제도 배포다: 보존과 승인 사이의 경계 · 이론
빈 목표의 초록불을 승인하기 전에
한 줄 요약
빈 목표는 의도한 폐기일 수도 있고 잘못된 생성 결과일 수도 있습니다. 보호를 해제하기 전에 현재 커밋과 실제 삭제 범위를 확인해야 합니다.
왜 이게 필요했나
환경별 디렉터리를 정리한 뒤 배포 화면이 OutOfSync가 됐습니다. 마지막 작업에는 Succeeded라고 적혀 있습니다.
한 사람은 조정이 느리니 기다리자고 하고, 다른 사람은 allowEmpty를 켜면 초록불이 된다며 설정을 바꾸려 합니다.
어느 쪽도 아직 무엇이 비었는지, 어떤 작업의 성공인지 확인하지 않았습니다. 잘못된 생성 결과를 승인하면
자동화가 의도하지 않은 전체 삭제를 수행할 수 있습니다.
이번 단원을 만들기 전 실제 Argo CD v3.5.2에서 작은 ConfigMap으로 실험했습니다. 빈 목표를 만들자 객체는
그대로 남았고 SyncError가 생겼지만 operationState.phase는 Succeeded였습니다. 확인해 보니 그 성공은
현재의 빈 목표 커밋이 아니라 이전에 객체를 만들었던 커밋의 기록이었습니다. 성공 문자열만 보는 검증은
실패를 놓치는 정도를 넘어, 보호 장치가 막고 있는 삭제를 성공했다고 보고할 수 있었습니다.
어떻게 동작하나
자동 prune에는 목표 리소스가 하나도 없을 때 대규모 삭제를 막는 보호가 있습니다. allowEmpty를 true로 두면
그 보호를 해제할 수 있습니다. 이것은 빠르게 오류를 지우는 수리 버튼이 아니라 빈 상태를 허용한다는 운영 결정입니다.
실습은 두 번째 Application에 disposable ConfigMap 하나만 맡깁니다. 첫 번째 Application의 retained와 anchor는
실험이 끝날 때까지 같은 UID와 데이터를 유지해야 합니다. 승인 대상의 크기를 작게 유지하면서도 경계를 검증합니다.
첫 번째 구분은 생성 실패와 유효한 빈 결과입니다. 존재하지 않는 source.path를 지정하면 매니페스트를 읽는
단계 자체가 실패할 수 있습니다. 이를 빈 목표 보호의 증거로 쓰면 안 됩니다. 이번 저장소에는 empty 디렉터리를
유지하고 resources.json을 다음과 같은 유효한 빈 List로 바꿉니다.
{"apiVersion":"v1","kind":"List","items":[]}두 번째 구분은 비교한 커밋과 실행한 작업입니다. status.sync.revision은 지금 비교한 원하는 상태의 좌표이고,
status.operationState.syncResult.revision은 그 작업 결과가 속한 좌표입니다. 두 값이 다르면 오래된 작업의
Succeeded를 현재 커밋의 실행 성공으로 읽을 수 없습니다. conditions도 함께 봐야 합니다.
이번 환경에서 거부 메시지는 auto-sync will wipe out all resources였으며, 처음 작성한 탐침은 문구에 empty가
있을 것으로 추측해 실제 보호를 놓쳤습니다. 그 실패도 검증 기록에 남겼습니다. 문구는 버전에 따라 변할 수
있으므로 학생 환경은 버전을 고정하며, 메시지 하나 외에 빈 목표·현재 revision·정책·보존 UID를 함께 확인합니다.
| 관측 | Git 목표 | 실제 disposable | 정책과 의미 |
| --- | --- | --- | --- |
| 기준선 | 한 객체 | 기준 UID | allowEmpty=false |
| 빈 목표 관측 | 0개 | 같은 UID | 자동 전체 삭제가 거부됨 |
| 검토 후 허용 | 0개, 같은 커밋 | 없음 | allowEmpty=true로 실제 삭제 |
| Git 복원 | 한 객체, 새 커밋 | 새 UID | 기본 보호 false 복원, 객체 재생성 |
같은 커밋에서 정책만 바뀌어도 실제 객체가 사라질 수 있다는 점을 확인하세요. Git diff만 검토했다는 주장만으로
Application 정책의 변경까지 검토한 것은 아닙니다. 변경 승인 기록에는 Git 좌표뿐 아니라 어느 Application,
어떤 정책, 어느 리소스 목록을 보고 결정했는지도 남겨야 합니다.
현장에서 만나는 모습
브랜치별 시험 환경을 폐기하는 경우처럼 목표가 비는 것이 정당할 수 있습니다. 그래도 렌더링이 실패한 것을
빈 결과로 취급하지 않았는지, 대상 환경이 정말 폐기 대상인지, 남겨야 할 데이터가 없는지를 확인해야 합니다.
반대로 환경을 유지하려는데 결과가 비었다면 필터 조건이나 경로 선택부터 복원하는 편이 의도에 맞습니다.
초록불을 얻는 것 자체를 완료 조건으로 삼으면, 자원이 전부 사라져서 더는 차이가 없는 상태도 성공으로 보입니다.
보고서를 작성할 때 다음 질문을 순서대로 답해 보세요. 현재 커밋의 렌더링은 성공했는가? 결과가 빈 이유는
의도한 폐기인가? 이 Application이 소유한 삭제 대상은 정확히 무엇인가? 승인 후 예상한 대상만 사라졌는가?
복원이 필요하다면 객체 선언과 데이터 중 각각 무엇을 어디에서 복구할 수 있는가?
마지막 질문은 이 실습에서 일부러 미완성으로 남깁니다. ConfigMap을 Git에서 다시 만들면 같은 데이터를 넣을
수 있지만 UID는 새로 생깁니다. 데이터베이스나 볼륨 내용이 함께 돌아오는 것은 아닙니다. 이 실험으로 백업이
검증됐다고 적지 마세요. 실제 데이터의 복구 가능성은 별도의 백업과 복원 시험을 통해 증명해야 합니다.
다음 실습에서 할 것
preview-empty는 빈 목표를 만들고 보호가 작동한 관측을 먼저 저장합니다. 이 시점에는 disposable이 아직
남아 있어야 합니다. guard-7.json에서 현재 커밋, 이전 작업 커밋, 대상 UID를 읽은 뒤 명시적으로 허용합니다.
다음 단계에서는 Git 정의와 기본 보호를 되돌리고 새 UID를 확인합니다. 이미 완료한 단계는 재실행해도 삭제를
반복하지 않으며, 채점은 실제 상태를 읽기만 합니다. 변경 기록이 pending에서 끊겼다면 완료를 추측하지 않고
자료를 보존합니다. 새 관측을 얻겠다고 같은 삭제를 무조건 다시 수행하는 습관을 피하기 위한 설계입니다.
공식 문서
- [Argo CD 자동 동기화](https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/): 자동 prune와 allowEmpty의 관계를 확인하세요.
- [Kubernetes ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/): 실험 객체가 담는 것과 담지 않는 것을 확인하세요.