GitOps 와 ArgoCD · 초록불의 근거를 직접 쓴다 · 이론
초록불은 누가 켜 주는가
한 줄 요약
Argo CD 의 헬스는 종류마다 다른 판정 규칙이 만들어 내고, 내장 규칙이 없는 CRD 는 argocd-cm 에 Lua 로 직접
써 줘야 하며, 그 규칙은 서버 없이 argocd admin settings resource-overrides health 로 그 자리에서 시험할 수 있다.
왜 헬스가 동기화와 따로 있나
GitOps 를 배울 때 먼저 만나는 축은 동기화다 — 저장소에 적힌 것과 클러스터에 있는 것이 같은가. 그런데
이 축만으로는 답할 수 없는 질문이 하나 남는다. 같긴 한데, 잘 돌고 있나? 저장소에 적힌 이미지 태그가
존재하지 않아도 Deployment 객체 자체는 저장소와 똑같이 만들어진다. 동기화 축은 초록이고 파드는 하나도
뜨지 않는다. 그래서 Argo CD 는 축을 둘로 나눈다. 동기화는 "선언과 실물이 같은가", 헬스는 "실물이 제
구실을 하는가" 다. 두 축이 따로 있어야 "Synced 인데 Degraded" 라는, 현장에서 가장 자주 만나는 상태를
표현할 수 있다.
헬스 값은 여섯 가지다 — Healthy, Progressing, Degraded, Suspended, Missing, Unknown.
앱 전체의 헬스는 자식 자원들의 값을 모아 가장 나쁜 쪽으로 정해진다. 그래서 자식 하나의 규칙이 잘못돼도
앱 전체가 잘못된 색으로 보인다.
어떻게 동작하나
Deployment, StatefulSet, Service, Ingress, Job, PVC 같은 내장 종류에는 Argo CD 안에 판정 코드가 이미 있다.
예를 들어 Deployment 는 status 의 updatedReplicas·readyReplicas·availableReplicas 와observedGeneration 을 보고, 아직 다 올라오지 않았으면 Progressing 과 함께 "몇 개 중 몇 개" 라는
메시지를 만든다.
CRD 에는 이런 코드가 없다. 그래서 argocd-cm 에 규칙을 얹는다. 키 이름이 중요하다.
data: resource.customizations.health.example.com_Widget: | hs = {} if obj.status ~= nil and obj.status.phase == "Ready" then hs.status = "Healthy" hs.message = "widget is ready" return hs end hs.status = "Progressing" hs.message = "waiting for widget" return hs<그룹>_<종류> 이고 구분자는 밑줄이다. 여기서 종류 이름을 매니페스트의 kind 와 다르게 적으면
오류가 나지 않는다 — 그냥 규칙이 없는 것처럼 동작한다. 이 종류의 실수가 오래 살아남는 이유다.
Lua 조각은 obj 라는 전역 변수로 리소스를 통째로 받고, status 와 message 를 채운 테이블을 돌려준다.
규칙을 쓸 때 제일 자주 빠뜨리는 것이 status 가 아직 없는 순간이다. 방금 만들어져 컨트롤러가 손대기
전인 자원에는 status 자체가 없다. 여기서 Degraded 를 내면 새로 만든 자원이 매번 빨간불로 시작하고,
알림을 건 팀은 곧 그 알림을 끈다. 기본 가지는 Progressing 이어야 한다.
Suspended 는 따로 말할 값어치가 있다. 사람이 일부러 멈춰 둔 것 — 점검 중인 파이프라인, 정지한
CronJob — 을 가리키는 칸이다. 이걸 Degraded 로 내면 계획된 정비마다 호출기가 울린다. 그리고 가지의
순서가 결과를 바꾼다. 멈춰 둔 자원의 status.phase 가 여전히 Ready 라면, Ready 가지를 먼저 쓴
규칙은 초록불을 내고 만다.
현장에서 만나는 모습
가장 흔한 사고는 "CRD 가 늘 초록불" 이다. 오퍼레이터가 만든 데이터베이스 자원이 몇 시간째 프로비저닝에
실패하고 있는데 화면에는 아무 표시가 없다. Argo CD 가 거짓말을 한 것이 아니라, 판정할 규칙을 아무도
써 주지 않아서 그 자원이 헬스 계산에 참여하지 않았을 뿐이다. 알림은 대개 사용자가 먼저 한다.
두 번째로 흔한 것은 규칙이 조용히 낡는 것이다. 오퍼레이터를 판올림하면서 status.phase 가status.conditions 로 바뀌었는데 argocd-cm 의 Lua 는 그대로다. 규칙은 이제 항상 기본 가지를 타서
모든 자원이 Progressing 으로 굳는다. 아무도 오류를 보지 못한다. 그래서 규칙을 쓰면 **표본 리소스와
기대 판정을 표로 묶어 저장소에 함께 두는 것**이 규칙 자체만큼 중요하다. 이 표를 CI 에서 한 번 돌리면
필드 이름이 바뀐 날 바로 빨간불이 뜬다.
이 실습 환경의 한계
실습 파드에는 Argo CD 컨트롤러가 없다. 그래서 "규칙을 반영했더니 화면 색이 바뀌었다" 는 볼 수 없고,
헬스가 Degraded 라서 동기화가 멈추는 것 같은 컨트롤러 동작도 확인할 수 없다. 대신 판정을 실제로 수행하는
그 코드가 CLI 안에 그대로 들어 있어서, argocd-cm 한 장과 리소스 YAML 한 장만으로 같은 답을 받아 볼 수 있다.
다음 실습에서 할 것
내장 판정을 먼저 보고, 규칙이 없는 CRD 가 어떤 문장을 내는지 확인한다. 그다음 Lua 를 한 가지씩 늘려
Healthy·Degraded·Progressing·Suspended 네 칸을 모두 만들어 보고, 키 이름을 한 글자 틀렸을 때 무슨 일이
생기는지 눈으로 본다. 마지막에는 표본과 기대를 표로 묶어 한 번에 돌리는 검사 스크립트를 만든다.