Troubleshooting 2026.08.09 5 min read

Rancher 502와 단일 장애점: Tunnel부터 Pod까지 추적하기

이슈 발생: 2026-08-08 · 발행 기준: 2026-08-09 18:43 KST
환경: RKE2, Rancher, Cloudflare Tunnel, Traefik/Service DNS

Rancher를 Cloudflare Tunnel로 공개할 때 502만 보고 Rancher 자체의 문제라고 단정하면 진단이 길어진다. 이 구성에서 502는 Cloudflare Edge, Tunnel connector, Kubernetes DNS, Service, EndpointSlice, Rancher Pod 중 어느 계층에서도 만들어질 수 있다.

이번 점검에서는 접속 경로와 고가용성을 함께 살폈다. 기존에는 Rancher를 한 노드의 Pod 하나로 실행하고, cloudflared는 두 Pod로 구성했지만 서로 다른 노드에 배치되도록 강제하지 않았다. 외부 접속이 되더라도 구조상 단일 장애점이 남아 있던 셈이다.

구조부터 한 줄로 그리기

사용자 → Cloudflare → Tunnel → cloudflared Pod ×2
       → rancher.cattle-system.svc.cluster.local:80
       → Rancher Service → Rancher Pod ×3

Cloudflare Tunnel은 내부 connector가 바깥으로 연결을 생성하는 outbound-only 방식이다. 홈 라우터나 클라우드 VM의 80/443 포트를 직접 인터넷에 열지 않아도 된다.

502를 계층별로 분리하기

1. 외부 DNS와 Tunnel 상태

공개 hostname이 올바른 Tunnel을 가리키는지, connector가 Connected 상태인지 먼저 본다. 이 단계가 실패하면 Kubernetes 설정을 바꿔도 해결되지 않는다.

2. cloudflared가 내부 DNS를 해석하는지

Tunnel 원점으로 Service DNS를 사용하려면 cloudflared가 클러스터 안에서 실행되고 CoreDNS를 사용할 수 있어야 한다.

kubectl -n cloudflared get pod -o wide
kubectl -n cloudflared logs deploy/cloudflared --tail=200
kubectl -n cloudflared exec deploy/cloudflared -- \
  sh -c 'getent hosts rancher.cattle-system.svc.cluster.local'

이미지에 getent나 shell이 없을 수 있다. 그때는 같은 namespace에 임시 진단 Pod를 띄운다.

3. Service와 EndpointSlice

Service가 있어도 Ready Pod를 선택하지 못하면 트래픽을 보낼 곳이 없다.

kubectl -n cattle-system get svc rancher -o wide
kubectl -n cattle-system get endpointslice \
  -l kubernetes.io/service-name=rancher -o wide
kubectl -n cattle-system get pod -l app=rancher -o wide

EndpointSlice 주소 수와 Ready Rancher Pod 수를 비교한다. selector가 Pod label과 어긋났거나 readiness probe가 실패하면 endpoint가 비어 있을 수 있다.

4. 클러스터 내부 요청

kubectl run rancher-curl --rm -it --restart=Never \
  --image=curlimages/curl -- \
  curl -sv http://rancher.cattle-system.svc.cluster.local/ping

내부 /ping이 정상인데 외부만 502라면 Tunnel hostname/origin, TLS 설정, Host 헤더 쪽으로 범위를 좁힐 수 있다.

단일 Pod에서 3개 Pod로

Rancher의 replicas를 3으로 늘리는 것만으로는 충분하지 않다. 스케줄러가 세 Pod를 한 노드에 놓으면 노드 장애 한 번에 모두 사라진다. 안정적으로 사용할 core 노드에 label을 붙이고, 같은 hostname에 두 Rancher Pod를 놓지 않는 anti-affinity를 추가했다.

spec:
  replicas: 3
  template:
    spec:
      nodeSelector:
        rancher-stable: "true"
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values: [rancher]
              topologyKey: kubernetes.io/hostname

required...는 조건을 만족하지 않으면 Pod를 Pending으로 남기는 강한 규칙이다. 노드가 세 대보다 적은데 replicas가 3이면 일부가 Pending이 될 수 있으므로 가용 노드 수를 먼저 확인해야 한다.

kubectl get nodes -L rancher-stable
kubectl -n cattle-system rollout status deploy/rancher
kubectl -n cattle-system get pod -l app=rancher -o wide

cloudflared도 노드 장애를 견디게 만들기

cloudflared를 두 replicas로 유지하고 동일한 방식의 필수 pod anti-affinity를 적용했다. 두 connector는 같은 Tunnel token을 사용해도 된다. 이 복제의 핵심 목적은 애플리케이션 트래픽의 일반적인 로드밸런싱보다는 connector 또는 노드 장애 시 Tunnel 연결을 유지하는 것이다.

kubectl -n cloudflared rollout status deploy/cloudflared
kubectl -n cloudflared get pod -o wide

Pod 이름보다 NODE 열을 본다. 두 Pod가 Running이어도 같은 노드라면 노드 장애에 대한 이중화는 아니다.

Helm 환경에서 놓치기 쉬운 것

실행 중 Deployment를 kubectl patch로 수정하면 즉시 효과는 난다. 그러나 Helm으로 설치한 Rancher나 cloudflared는 다음 helm upgrade에서 저장된 values로 되돌아갈 수 있다.

따라서 최종 상태를 다음처럼 남겨야 한다.

  • replicas
  • nodeSelector 또는 nodeAffinity
  • podAntiAffinity
  • image 버전 또는 digest
  • readiness/liveness 설정
  • Rancher hostname 및 인증서 SAN

운영 중인 live 리소스와 Helm values의 차이를 배포 전에 비교하는 절차도 필요하다.

검증 체크리스트

  • Rancher Pod 3개가 서로 다른 안정 노드에 존재한다.
  • Rancher Service EndpointSlice에 Ready endpoint가 3개 보인다.
  • cloudflared Pod 2개가 서로 다른 노드에 존재한다.
  • cloudflared 로그에 origin DNS/TCP 오류가 없다.
  • 클러스터 내부 Rancher /ping이 성공한다.
  • 외부 주소가 HTTPS로 열리고 Cloudflare Access 정책도 정상이다.
  • 노드 한 대를 배제했을 때도 나머지 경로로 접속할 수 있다.
  • 변경값이 Helm values에 영구 반영돼 있다.

참고 자료