배포 마지막 단계에서 postgres pod가 계속 Pending이었고, 원인을 찾아가는 과정 자체가 "쿠버네티스 네트워킹이 실제로 어떻게 동작하는지"를 배울 수 있는 사례라 따로 정리.

1. ClusterIP는 실체가 없는 "가상 IP"다

ClusterIP는 어느 노드에도 실제로 존재하지 않는 가상 주소고, 클러스터의 모든 노드에서 동작하는 kube-proxy가 iptables(또는 IPVS) 규칙으로 "이 가상 IP로 온 패킷은 실제 파드 IP 중 하나로 바꿔치어서 보내라"는 규칙을 심어놓는다.

즉 postgres-service:5432로 접속한다는 건 실제로: (1) DNS가 서비스 이름을 ClusterIP로 풀어주고 (2) 그 IP로 나가는 패킷을 커널의 iptables 규칙이 가로채서 실제 postgres 파드 IP로 DNAT한다. 즉 ClusterIP 통신이 되려면 DNS와 kube-proxy 둘 다 정상이어야 한다.

2. CoreDNS — 서비스 이름을 IP로 바꿔주는 것

모든 파드의 /etc/resolv.conf가 기본적으로 CoreDNS를 가리키도록 kubelet이 자동 설정해준다. 이번에 앱 로그에 찍힌:

Caused by: java.net.UnknownHostException: postgres-service.c4i.svc.cluster.local

이건 "파드가 안 떠서 연결이 거부된"(그러면 Connection refused) 가 아니라 이름 자체를 못 찾았다는 뜻이다. Service는 이미 만들어져 있었으니 DNS 레코드 자체는 있어야 하는데 못 찾았다는 건, CoreDNS로 가는 경로(이것도 ClusterIP)가 막혀 있었다는 신호다.

3. 증상을 계층별로 좋혀나간 순서

1. kubectl get pods -n c4i          → postgres만 Pending
2. kubectl describe pod postgres    → Events 비어있음
3. kubectl get pvc                  → Pending, "waiting for first consumer"
4. kubectl describe pvc             → "ExternalProvisioning ... verify provisioner is running"
5. kubectl logs local-path-provisioner → "dial tcp 10.43.0.1:443: no route to host"
                                        (10.43.0.1 = 쿠버네티스 API 서버 ClusterIP!)

동시에 별개 경로로:

1. ArgoCD Application sync status → Unknown
2. kubectl describe application    → "dial tcp 10.43.21.196:8081: i/o timeout"(repo-server)
3. 컨트롤러 로그 상세               → 진짜 실패 지점은 argocd-redis 캐시 저장

그리고 앱 파드 로그: UnknownHostException: postgres-service...

세 가지 완전히 다른 컴포넌트(local-path-provisioner, argocd-application-controller, Spring Boot 앱)에서 또같은 패턴(ClusterIP 대상 연결/조회 실패)이 나왔다. 이게 "개별 컴포넌트를 하나씩 고친다"가 아니라 "공통 원인을 의심한다"로 방향을 틀는 근거였다.

4. 왜 "일단 재시작해보자"를 함부로 하면 안 되는가

argocd-redis pod를 재시작해서 문제가 해결되는지 시도했다(사용자 승인 후). 이건 가설을 검증하는 실험이었다: "혹시 이 특정 pod의 스터크된 커넥션 상태 때문인가?"를 확인하려는 목적. 재시작 후 다른 노드에서 새 pod가 떴는데도 동일 증상이 재현되었다는 결과 자체가 유의미한 정보였다 — "pod 자체 문제가 아니다"를 반증함으로써 원인을 kube-proxy/CNI 레벨로 더 좋힌 수 있었다.

공유 컨트롤플레인 컴포넌트(이번 세션에서 만들지 않은 리소스)를 함부로 재시작/삭제하는 건 다른 워크로드에 영향을 줄 수 있어, 실행 전 반드시 "왜 이걸 하려는지, 데이터 유실 위험이 있는지"를 명확히 하고 승인을 구하는 게 맞다.

5. 이 문제를 나중에 직접 진단한다면 확인할 순서

  1. kube-proxy 자체가 살아있는지
  2. CNI(플러그인) 상태 — flannel/CNI 관련 pod가 CrashLoopBackOff하고 있는지