DB 클라이언트(TablePlus 등)로 postgres-service에 직접 접속하려다가 격은 문제와, ArgoCD의 selfHeal이 왜 수동 변경을 되돌리는지, 그리고 ignoreDifferences로 어떻게 우회했는지 정리.

1. 문제 상황

postgresql://admin:[email protected]:5432/defense_db 형태로 워커 노드의 Tailscale IP에 직접 접속을 시도했는데 연결이 안 됐다.

원인: postgres-service는 기본 ClusterIP 타입이다. ClusterIP는 클러스터 내부에서만 유효한 가상 IP(10.43.x.x)이고, 노드 자체의 물리/오버레이 네트워크 IP(100.x.x.x)에는 아무 포트도 바인딩되지 않는다.

2. 1차 시도 — 그냥 NodePort로 패치 → 되돌아감

kubectl patch svc postgres-service -n c4i -p '{"spec": {"type": "NodePort", "ports": [
  {"port":5432,"targetPort":5432,"protocol":"TCP","nodePort":30432}
]}}'

패치 직후에는 NodePort로 바낀 걸 확인했지만, 몇 십 초 뒤 다시 확인하니 다시 ClusterIP로 되돌아가 있었다.

왜 되돌아갔나 — ArgoCD selfHeal의 동작 원리

  1. ArgoCD는 주기적으로(기본 3분 polling + 리소스 변경 감지 시 즉시) git의 desired state와 클러스터의 live state를 diff한다.
  2. postgres-service는 apps/target-tracking-service/postgres.yaml(git)에 type 필드가 없다 → 기본값 ClusterIP가 desired state다.
  3. kubectl patch로 live state를 NodePort로 바꾸면, 다음 reconcile 때 ArgoCD가 "git과 다르다"고 판단하고 selfHeal이 live state를 git 상태(ClusterIP)로 강제로 되돌린다.

반면 argocd-server의 NodePort(30443)는 왜 안 되돌아갔나 — argocd-server 자체는 어떤 ArgoCD Application에도 속하지 않기 때문이다. 어느 리소스가 어느 Application에 속해 있는가가 selfHeal 적용 여부를 갈른다.

3. 해결 — ignoreDifferences

ArgoCD Application 스펙에 ignoreDifferences를 추가하면, 지정한 JSON 경로에 대해서는 diff 비교 자체를 하지 않는다.

# argocd/applications/target-tracking-service.yaml
spec:
  ignoreDifferences:
    - group: ""
      kind: Service
      name: postgres-service
      jsonPointers:
        - /spec/type
        - /spec/ports

4. 이 방식의 장단점 — git에 직접 NodePort를 박는 것과 비교

<table header-row="true"><tr><td></td><td>ignoreDifferences</td><td>git에 type: NodePort 직접 커밋</td></tr><tr><td>DB 외부 노출 여부가 git에 드러나는가</td><td>아니오</td><td>예</td></tr><tr><td>재배포/재마이그레이션 시 자동 재현</td><td>안 됨</td><td>자동으로 재현됨</td></tr><tr><td>"앱 배포 스펙"과 "운영 편의용 노출"의 분리</td><td>분리됨</td><td>섞임</td></tr></table>

5. 최종 접속 정보

postgresql://admin:[email protected]:30432/defense_db

6. 같은 방식이 필요할 다른 상황