핵심 요약
- 기준 구성은 각 control-plane 노드의 서로 다른 공인 IP를 공급자 SDN·가상 네트워크가 해당 VM vNIC와 fixed IP로 연결하고 DNS가 모든 공인 IP를 가리키는 방식임
- 공인 IP가
eth0에 없다는 사실만으로 NAT를 단정할 수 없으며 VM이 실제로 수신한 패킷의 목적지 주소를 먼저 확인해야 함 - fixed IP가 목적지이면
0.0.0.0:80/443의 CiliumhostNetwork리스너가 수신할 수 있지만 공인/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를 사용한다는 증거도 아님
- 공급자 제어 계층은
- 기본 데이터 경로는
공인 IP → 공급자 SDN·가상 스위치 → 대상 VM vNIC·fixed IP → Cilium hostNetwork Envoy순서로 이해함- 공급자 구현에 따라 VM에서 보이는 최종 목적지가 fixed IP일 수도 있고 공인
/32일 수도 있음 - 특정 공급자의 주소 변환, 라우팅, 가상 NIC 동작은 해당 공급자 문서로 확인해야 함
- 공급자 구현에 따라 VM에서 보이는 최종 목적지가 fixed IP일 수도 있고 공인
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또는::로 노출함- 기본
LoadBalancerService 모드는 자동 비활성화되므로 두 모드는 상호 배타적임 - 모든 Gateway의 listener port는 선택 노드에서 충돌하지 않도록 고유해야 함
TCPRoute와UDPRoute는 host network 모드와 호환되지 않음
- 기본
kubectl label node cp-a cp-b cp-c gateway.cilium.io/public=truegatewayAPI:
enabled: true
hostNetwork:
enabled: true
nodes:
matchLabels:
gateway.cilium.io/public: "true"
envoy:
enabled: true
securityContext:
capabilities:
keepCapNetBindService: true
envoy:
- NET_BIND_SERVICE80/443처럼1023이하 포트에 바인딩하려면NET_BIND_SERVICEcapability가 필요함- 기존 capability 목록을 교체하지 않고 설치된 chart의 기본 목록에
NET_BIND_SERVICE를 추가해야 함 - 위 예시는 standalone Envoy DaemonSet 모드의 핵심 값만 표시함
- embedded Envoy 모드는
securityContext.capabilities.ciliumAgent에 추가해야 함
- 기존 capability 목록을 교체하지 않고 설치된 chart의 기본 목록에
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--values values-direct-public-ip.yaml
kubectl -n kube-system rollout status ds/cilium-envoyGateway 주소와 공급자 인벤토리를 분리함
-
host network 모드의
Gateway.status.addresses에는 Kubernetes Node가 보고한InternalIP또는ExternalIP가 나타날 수 있음- Node가 fixed IP만
InternalIP로 보고하면 Gateway status에도 사설 주소만 표시될 수 있음 - Cilium은 노드 주소를 정렬하며 Gateway status에는 최대 16개 주소를 게시함
- 공급자 공인 IP가 status에 없더라도 Envoy 프로그래밍 실패를 의미하지 않음
- Node가 fixed IP만
-
공급자 공인 IP를 LB IPAM용
Gateway.spec.addresses에 선언하지 않음- Cilium의
spec.addresses지원은 LB IPAM과 함께 Service VIP를 지정하는 기능임 - 이 필드가 공급자 SDN의 공인 IP 연결이나 VM 라우팅을 생성하지 않음
- 노드별 공인 IP 연결은 클라우드 인프라 인벤토리에서 관리함
- Cilium의
-
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 관리 포트는 인터넷에 공개하지 않음
- Kubernetes API
-
공급자 네트워크가 원본 소스 IP를 보존하는지는 구현에 따라 달라질 수 있으므로 단정하지 않음
- VM의
tcpdump에서 SYN의 출발지 주소를 확인함 - Cilium Envoy access log에서 downstream remote address와 전달 헤더를 확인함
- 관측 결과를 기준으로 네트워크 정책, rate limit, 감사 로그의 신뢰 경계를 정함
- VM의
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-comDNS 기반 분산의 한계를 수용함
-
여러
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 계층을 추가함
참고 문서
관련 글
Cilium Gateway API 외부 트래픽 설계Cilium Gateway API 3편: 멀티 컨트롤 플레인에서 경계 나누기고가용성 Kubernetes 컨트롤 플레인과 Cilium Gateway API 데이터 플레인의 로드 밸런서, 노드 역할, 장애 경계를 분리합니다.Cilium Gateway API 외부 트래픽 설계Cilium Gateway API 2편: 클러스터 앞에 외부 LB가 있을 때기존 외부 로드 밸런서에서 Cilium Gateway API로 트래픽을 전달하는 LoadBalancer, NodePort, hostNetwork 구성을 비교합니다.Cilium Gateway API 외부 트래픽 설계Cilium Gateway API 1편: 외부 트래픽 진입점 선택하기Cilium Gateway API의 데이터 경로를 이해하고 LoadBalancer, NodePort, hostNetwork 중 환경에 맞는 외부 노출 방식을 선택합니다.