How-toKubernetes

Cilium Gateway API 트래픽을 노드별 공인 IP로 받기

노드별 공인 IP를 VM에 연결하는 클라우드 SDN 환경에서 Cilium hostNetwork와 DNS로 외부 트래픽을 받습니다.

업데이트 검증 근거 자료이 페이지 편집

핵심 요약

  • 기준 구성은 각 control-plane 노드의 서로 다른 공인 IP를 공급자 SDN·가상 네트워크가 해당 VM vNIC와 fixed IP로 연결하고 DNS가 모든 공인 IP를 가리키는 방식임
  • 공인 IP가 eth0에 없다는 사실만으로 NAT를 단정할 수 없으며 VM이 실제로 수신한 패킷의 목적지 주소를 먼저 확인해야 함
  • fixed IP가 목적지이면 0.0.0.0:80/443의 Cilium hostNetwork 리스너가 수신할 수 있지만 공인 /32가 유지되면 Linux local delivery 구성이 추가로 필요할 수 있음
  • 공급자 공인 IP는 클라우드 인프라 인벤토리와 DNS에서 관리하고 LB IPAM용 Gateway.spec.addresses에는 선언하지 않음
  • 다중 A/AAAA 레코드는 중앙 LB처럼 정상 노드를 선택하지 않으므로 요구 RTO에 따라 health-checked DNS 또는 외부 LB가 필요함

노드별 공인 IP의 전달 계층을 구분함

  • 공급자 공인 IP와 게스트 OS의 인터페이스 주소는 서로 다른 관리 계층에 존재할 수 있음
    • 공급자 제어 계층은 203.0.113.11을 cp-a의 vNIC와 연결함
    • 게스트 OS의 eth0에는 fixed IP인 10.0.0.11/24만 표시될 수 있음
    • 이 상태는 공인 IP 연결이 없다는 뜻이 아니며 NAT를 사용한다는 증거도 아님

Provider SDN steering per-node public IPs to Cilium host network listeners

  • 기본 데이터 경로는 공인 IP → 공급자 SDN·가상 스위치 → 대상 VM vNIC·fixed IP → Cilium hostNetwork Envoy 순서로 이해함
    • 공급자 구현에 따라 VM에서 보이는 최종 목적지가 fixed IP일 수도 있고 공인 /32일 수도 있음
    • 특정 공급자의 주소 변환, 라우팅, 가상 NIC 동작은 해당 공급자 문서로 확인해야 함

VM에서 목적지 주소를 먼저 판별함

  • 외부 요청을 보내는 동안 tcpdump -ni any로 패킷이 대상 VM까지 도착하는지 먼저 확인함
sudo tcpdump -ni any 'tcp port 80 or tcp port 443'
ip -br address
ip route show
kubectl get nodes -o wide
sudo ss -lntp '( sport = :80 or sport = :443 )'
  • 패킷 목적지가 노드 fixed IP이면 wildcard hostNetwork 리스너로 local delivery되는 경로를 점검함

    • 10.0.0.11:443과 같은 SYN이 보이면 로컬 방화벽과 0.0.0.0:443 리스너를 확인함
    • SYN은 도착하지만 응답이 없으면 리스너 상태, 로컬 방화벽, 반환 경로를 확인함
    • 패킷이 전혀 보이지 않으면 공인 IP 연결 대상, 공급자 방화벽, 보안 그룹, 네트워크 ACL을 확인함
  • 패킷 목적지가 공인 /32로 유지되면 Linux가 그 주소를 local address로 인식하는지 별도로 확인함

ip addr
ip route get local 203.0.113.11
ip route show table local
  • 공인 목적지가 local address로 인식되지 않으면 hostNetwork 활성화만으로 수신 문제를 해결할 수 없음
    • 공급자 문서에 따라 공인 /32, local route, 추가 가상 NIC 중 필요한 구성을 적용해야 함
    • 공급자가 관리하는 주소를 임의로 eth0에 추가하면 중복 주소나 잘못된 반환 경로가 생길 수 있음
    • net.ipv4.ip_nonlocal_bind=1은 로컬에 없는 주소로의 bind만 허용하며 패킷을 local delivery로 전환하지 않으므로 일반 해결책이 아님

hostNetwork를 선택 노드에만 활성화함

  • Cilium hostNetwork는 Gateway listener를 선택 노드의 모든 인터페이스에 0.0.0.0 또는 ::로 노출함
    • 기본 LoadBalancer Service 모드는 자동 비활성화되므로 두 모드는 상호 배타적임
    • 모든 Gateway의 listener port는 선택 노드에서 충돌하지 않도록 고유해야 함
    • TCPRoute와 UDPRoute는 host network 모드와 호환되지 않음
kubectl label node cp-a cp-b cp-c gateway.cilium.io/public=true
values-direct-public-ip.yaml
gatewayAPI:
    enabled: true
    hostNetwork:
        enabled: true
        nodes:
            matchLabels:
                gateway.cilium.io/public: "true"

envoy:
    enabled: true
    securityContext:
        capabilities:
            keepCapNetBindService: true
            envoy:
                - NET_BIND_SERVICE
  • 80/443처럼 1023 이하 포트에 바인딩하려면 NET_BIND_SERVICE capability가 필요함
    • 기존 capability 목록을 교체하지 않고 설치된 chart의 기본 목록에 NET_BIND_SERVICE를 추가해야 함
    • 위 예시는 standalone Envoy DaemonSet 모드의 핵심 값만 표시함
    • embedded Envoy 모드는 securityContext.capabilities.ciliumAgent에 추가해야 함
helm upgrade cilium cilium/cilium \
  --namespace kube-system \
  --reuse-values \
  --values values-direct-public-ip.yaml

kubectl -n kube-system rollout status ds/cilium-envoy

Gateway 주소와 공급자 인벤토리를 분리함

  • host network 모드의 Gateway.status.addresses에는 Kubernetes Node가 보고한 InternalIP 또는 ExternalIP가 나타날 수 있음

    • Node가 fixed IP만 InternalIP로 보고하면 Gateway status에도 사설 주소만 표시될 수 있음
    • Cilium은 노드 주소를 정렬하며 Gateway status에는 최대 16개 주소를 게시함
    • 공급자 공인 IP가 status에 없더라도 Envoy 프로그래밍 실패를 의미하지 않음
  • 공급자 공인 IP를 LB IPAM용 Gateway.spec.addresses에 선언하지 않음

    • Cilium의 spec.addresses 지원은 LB IPAM과 함께 Service VIP를 지정하는 기능임
    • 이 필드가 공급자 SDN의 공인 IP 연결이나 VM 라우팅을 생성하지 않음
    • 노드별 공인 IP 연결은 클라우드 인프라 인벤토리에서 관리함
  • DNS는 각 노드에 연결된 서로 다른 공인 IP를 모두 가리키도록 구성함

app.example.com.  60  IN  A  203.0.113.11
app.example.com.  60  IN  A  203.0.113.12
app.example.com.  60  IN  A  203.0.113.13
  • 인증서는 공인 IP가 아니라 Gateway listener의 hostname을 기준으로 발급함
    • HTTP-01 challenge를 사용하면 모든 DNS 대상 노드에서 challenge Route가 도달해야 함
    • DNS-01 challenge는 노드별 HTTP 도달성에 덜 의존함

방화벽과 소스 IP를 관측으로 검증함

  • 클라우드 방화벽과 노드 방화벽에는 실제 listener 포트인 80/443만 필요한 출발지 범위에 허용함

    • Kubernetes API 6443은 관리자 VPN과 노드 CIDR로 제한함
    • etcd, kubelet, Cilium 관리 포트는 인터넷에 공개하지 않음
  • 공급자 네트워크가 원본 소스 IP를 보존하는지는 구현에 따라 달라질 수 있으므로 단정하지 않음

    • VM의 tcpdump에서 SYN의 출발지 주소를 확인함
    • Cilium Envoy access log에서 downstream remote address와 전달 헤더를 확인함
    • 관측 결과를 기준으로 네트워크 정책, rate limit, 감사 로그의 신뢰 경계를 정함
gateway-direct-public-ip.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
    name: public
    namespace: edge
spec:
    gatewayClassName: cilium
    listeners:
        - name: https
          hostname: "*.example.com"
          protocol: HTTPS
          port: 443
          tls:
              mode: Terminate
              certificateRefs:
                  - name: wildcard-example-com

DNS 기반 분산의 한계를 수용함

  • 여러 A/AAAA 레코드는 클라이언트에 후보를 제공하지만 중앙 LB처럼 매 요청의 정상 노드를 선택하지 않음

    • resolver와 클라이언트가 TTL보다 오래 주소를 캐시할 수 있음
    • 기존 TCP 연결은 DNS 변경과 무관하게 실패 노드에 남을 수 있음
    • 재시도와 주소 순회 동작은 클라이언트마다 다름
  • 요구 RTO가 단순 DNS 제거 시간보다 짧으면 health-checked DNS 또는 외부 LB가 필요함

    • health-checked DNS는 장애 감지, TTL, 전파, 클라이언트 캐시 시간을 합산해 평가함
    • 수 초 단위의 일관된 failover와 연결 단위 health check가 필요하면 외부 LB가 더 적합함
  • control-plane 노드를 직접 공개하면 관리 트래픽과 사용자 트래픽이 같은 서버 자원을 공유함

    • 가능한 경우 공인 IP와 Gateway listener를 전용 infra 노드로 이동함
    • 불가피하면 Envoy connection limit, rate limit, resource limit와 API server 보호 지표를 설정함

각 공인 IP를 외부에서 독립 검증함

  • DNS round-robin이 단일 노드 장애를 숨기지 않도록 모든 공인 IP를 직접 고정해 검사함
kubectl get gateway -n edge public -o yaml
kubectl -n kube-system get pods -l k8s-app=cilium-envoy -o wide
sudo ss -lntp '( sport = :80 or sport = :443 )'
for ip in 203.0.113.11 203.0.113.12 203.0.113.13; do
  curl --fail-with-body \
    --connect-timeout 3 \
    --resolve app.example.com:443:$ip \
    https://app.example.com/healthz
done
  • 공인 IP별 검사에서 TLS, Route, 백엔드 경로를 한 요청으로 검증함
    • 한 노드를 중지하고 health-checked DNS가 실패 주소를 제거하는 시간을 측정함
    • 복구 노드가 listener와 최신 Envoy 설정을 받은 뒤 DNS 대상에 복귀하는지 확인함
    • 패킷 캡처와 Envoy access log를 함께 비교해 소스 IP 보존 여부를 확인함

실행 제안

  • 먼저 노드별 공인 IP 연결과 VM에서 보이는 목적지를 확인한 뒤 hostNetwork + 선택 노드 label + 공인 DNS를 적용함
  • 공인 /32가 local address로 인식되지 않으면 공급자 요구사항에 맞는 route·vNIC 구성을 먼저 해결함
  • 운영 RTO가 DNS 장애 제거 시간보다 짧으면 외부 LB 또는 health-checked DNS 계층을 추가함

참고 문서