이전 게시물에서는 cilium에서 native / vxlan tunnel 모드에 대해서 알아보았다.
이번에는 cilium에서 serivce 객체에 external ip IPAM을 설정하여 활용하는 방법과
할당한 external ip를 다른 네트워크 대역의 노드와 통신하기 위한 방법에 대해서 알아보려고 한다.
[Cilium][4주차] Node & Pod 네트워크 통신, Native vs VXLAN
이전 3주차에서는 cilium routing-mode를 Natvie로 설정해서 테스트를 했었다.그래서 같은 네트워크 대역에서 Pod끼리 통신을 할 때는 Node IP로 NAT하지 않고 통신하는것을 알 수 있었다.그렇다면 다른 네
dobby-isfree.tistory.com
Cilium Serive LB-IPAM
제목에서 알 수 있듯이 Service 객체에 IPAM, 즉 IP를 EXTERNAL-IP 필드에 할당하도록 한다.
cilium에서는 CiliumLoadBalancerIPPool 객체로 되어 있고 약어로는 여러가지가 있지만 lbippool을 사용한다.
service 객체의 type은 ClusterIP, NodePor 그리고 LoadBalancer(이하 LB 타입) 타입이 있다.
하지만 클라우드 환경이 아닌 이상 일반적으로 LB 타입은 많이 사용하지 않는다.
- 클라우드 환경에서도 자주 쓰이는 타입은 아닌것 같다.
- GCP는 잘 모르겠지만 AWS의 경우에는 aws-loadbalancer-controller를 배포하고 Ingress 객체를 활용한다.
- ingress 객체로 ALB, NLB를 다 만들 수 있고 ACM, Path Control 등 Service를 생성하는것보다 훨씬 제어의 폭이 넓다.
IDC 환경이거나, 별도 CNI 또는 MetalLB 등이 없으면 LoadBalancer 타입으로 선언하더라도 EXTERNAL-IP가 안된다.
하지만 Service를 외부에 노출한다고 생각해보면, 해당 서비스가 어떤 서비스로 노출되어 있는지 확인할 필요가 있다.
그리고 이러한 요구사항을 만족하기 위해서 cilium에서는 lbippool 객체를 만들어서 사용한다.
(⎈|HomeLab:kube-system) root@k8s-ctr:~# k expose deploy webpod --name=webpod-lbtype --type=LoadBalancer --port 80 --target-port=8080
service/webpod-lbtype exposed
(⎈|HomeLab:kube-system) root@k8s-ctr:~# k get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
webpod-lbtype LoadBalancer 10.96.73.250 <pending> 80:32640/TCP 2s
cilium의 lbippool은 미리 EXTERNAL-IP를 pool형태로 객체로 만들어서 Service 객체에서 해당 pool의 IP를 사용하도록 한다.
pool을 지정하는 방법은 다양하다. cidr로 넣을 수도 있고, blocks 형태로 넣을수도 있고 섞을수도 있다.
그리고 정해진 labels을 가진 service에서만 사용할 수 있도록 제한을 둘 수도 있다.
apiVersion: cilium.io/v2
kind: CiliumLoadBalancerIPPool
metadata:
name: pool-cidr
spec:
blocks:
- cidr: "203.0.113.0/28"
spec:
blocks:
- start: "203.0.113.10"
stop: "203.0.113.20"
spec:
blocks:
- cidr: "203.0.113.0/28"
- cidr: "2001:db8:1::/112"
- start: "198.51.100.50"
stop: "198.51.100.60"
spec:
blocks:
- cidr: "203.0.113.0/28"
serviceSelector:
matchLabels:
color: blue
Cilium Service LB-IPAM 테스트
cat << EOF | kubectl apply -f -
apiVersion: "cilium.io/v2" # v1.17 : cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
name: "cilium-lb-ippool"
spec:
blocks:
- start: "192.168.10.211"
stop: "192.168.10.215"
EOF
kubectl get lbippool -A
lbippool객체를 배포하면 기존에 EXTERNLA-IP Pending이였던 상태에 바로 pool 에 할당된 IP 1개를 할당한다.
그리고 lbippool 상태를 보면 사용 가능한 pool이 줄어든 모습을 볼 수 있다.

그리고 Service의 CLUSTER-IP, EXTERNAL-IP 모두 호출이 가능하다.

어떻게 통신이 되는걸까? 먼저 routing을 보면 추가된게 없다.
(⎈|HomeLab:kube-system) root@k8s-ctr:~# ip route
default via 10.0.2.2 dev eth0 proto dhcp src 10.0.2.15 metric 100
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100
10.0.2.2 dev eth0 proto dhcp scope link src 10.0.2.15 metric 100
10.0.2.3 dev eth0 proto dhcp scope link src 10.0.2.15 metric 100
10.10.0.0/16 via 192.168.10.200 dev eth1 proto static
172.20.0.0/24 via 172.20.0.70 dev cilium_host proto kernel src 172.20.0.70
172.20.0.0/16 via 192.168.10.200 dev eth1 proto static
172.20.0.70 dev cilium_host proto kernel scope link
172.20.1.0/24 via 172.20.0.70 dev cilium_host proto kernel src 172.20.0.70 mtu 1450
172.20.2.0/24 via 172.20.0.70 dev cilium_host proto kernel src 172.20.0.70 mtu 1450
--- 192.168.10.0/24에 대해서는 eth1으로 라우팅이 되어 있다. 이건 원래부터 있던 라우팅이다.
192.168.10.0/24 dev eth1 proto kernel scope link src 192.168.10.100
192.168.20.0/24 via 192.168.10.200 dev eth1 proto static
그 해답은 cilium-dbg를 보면 service list에 추가되어 있다.
service list를 보면 EXTERNAL-IP가 포함되어 있고 endpoint로 각 pod의 ip가 지정되어 있다.
- calico 등의 CNI에서는 iptables를 봐야했다.
- 하지만 cilium은 eBPF 기술을 사용하기 때문에 iptables 보다는 cilium-dbg를 먼저 참고하면 좋다.

그리고 당연하게도 EXTERNAL-IP는 현재 클러스터 외부에는 아직 알려지지 않은 IP이기 때문에 당연히 통신이 불가능하다.
- router 노드에서는 통신이 불가능하다.
그렇다면 왜 EXTERNAL-IP를 사용하는가? 사용은 가능하다. BGP 혹시 별도의 기술이 있다면...
cilium에서는 별도의 기술로 L2 Announcement 객체를 제공하고 있다.
Cilium L2 Announcement
BGP.. BGP... 지난주부터 Node & Pod 네트워크 통신을 주제로 스터디를 하고 있다.
그리고 native 모드를 사용하거나, 위와 같이 EXTERNAL-IP를 사용할 때 마다 BGP가 필요하다고 했다.
그리고 Cilium에서는 BGP 만큼은 아니지만 같은 L2 네트워크에서 EXTERNAL-IP를 광고할 수 있는 객체를 제공한다.

위 Service LB-IPAM 테스트때 router 노드에서는 클러스터의 svc EXTERNAL-IP 사용이 불가능하다.
routing이 없고, EXTERNAL-IP는 클러스터 외부로 아직 알려지지 않았기 때문에 당연한 결과이다.
L2 Announcement 구성 방법
먼저 helm values로 l2announcements 옵션을 활성화해야한다. 그리고 옵션 반영을 위해 cilium을 재시작한다.
- cilium 재시작 중에는 기존 서비스는 영향이 없다.
- 다만 endpoint가 변경되거나, service가 변경되거나 routing에 변경사항이 있을만한 요소는 반영 못한다.
- cilium 재시작을 해야 configmap에 설정이 반영이 된다.
helm upgrade cilium cilium/cilium --namespace kube-system --version 1.18.0 --reuse-values \
--set l2announcements.enabled=true
---
kubectl rollout restart -n kube-system ds/cilium
---
(⎈|HomeLab:kube-system) root@k8s-ctr:~# k get cm cilium-config -oyaml |grep enable-l2
enable-l2-announcements: "true"
enable-l2-neigh-discovery: "true"
L2 Announcement 테스트
객체는 복잡하지 않다. 어떤 svc에 대해서 L2 광고를 할지 labels만 지정하면 된다.
그리고 lease를 통해서 보면 k8s-w1이 리더로 선출되어 있다.
webpod은 k8s-ctr, k8s-w0, k8s-w1에 모두 포함되어 있으나, EXTERNAL-IP에 대한 리더는 k8s-w1인것이다.
cat << EOF | kubectl apply -f -
apiVersion: "cilium.io/v2alpha1" # not v2
kind: CiliumL2AnnouncementPolicy
metadata:
name: policy1
spec:
serviceSelector:
matchLabels:
app: webpod
# 스터디에서는 아래의 k8s-w0을 제외안하면 lease 선출이 안된다고 하는데,
# 실제로 제외하고 배포해보면 lease 선출이 잘 된다.
nodeSelector:
matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- k8s-w0
interfaces:
- ^eth[1-9]+
externalIPs: true
loadBalancerIPs: true
EOF
---
(⎈|HomeLab:kube-system) root@k8s-ctr:~# k get lease
NAME HOLDER AGE
cilium-l2announce-kube-system-webpod k8s-w1 16s
객체를 배포한 다음에 router 노드에서 ARP 패킷을 요청을 하고 전/후를 비교해보면
적용 후 EXTERNAL-IP 에 대한 L2 경로가 잡혔다. L2 announcement는 객체 이름에도 알 수 있듯이 같은 L2 대역에서만 동작한다.
--- router에서 EXTERNAL-IP에 대한 ARP 패킷을 요청하면
arping -i eth1 $LBIP -c 1000
curl --connect-timeout 1 $LBIP
---
root@router:~# arp -a
_gateway (10.0.2.2) at 52:55:0a:00:02:02 [ether] on eth0
? (192.168.20.100) at <incomplete> on eth1
? (192.168.10.101) at 08:00:27:a0:a6:a1 [ether] on eth1
? (192.168.20.100) at 08:00:27:a7:88:8a [ether] on eth2
? (192.168.10.100) at 08:00:27:2f:61:e6 [ether] on eth1
# EXTERNAL-IP에 대해서 k8s-w1 MAC 주소로 ARP 경로가 잡혀있다.
? (192.168.10.212) at 08:00:27:a0:a6:a1 [ether] on eth1
? (10.0.2.3) at 52:55:0a:00:02:03 [ether] on eth0
? (192.168.10.100) at <incomplete> on eth2
그리고 router에서 EXTERNAL-IP로 통신을 해보면 이전에는 통신이 안됬지만 이제는 arp에 경로가 있기 때문에 통신이 잘된다.

그렇다면 l2announcement를 배포하고 나면 lease를 선출하는데, lease의 의미는 무엇이고, 어떤 흐름으로 통신이 되는걸까?
도식화를 해보면 lease로 선출된 노드가 이제 새로운 router같이 트래픽을 받아서, 이후 다시 분배를 하게 된다.
lease로 선출되게 되면, router 노드에는 lease interface의 mac 주소가 등록된다.
그러면 모든 트래픽은 우선적으로 lease 노드로 전달이 된다. 그리고 이후에는 cilium-dbg에서 볼 수 있듯이 endpoint로 분배된다.

이번 주차에서는 cilium을 사용할 때 가장 고려를 많이 하는 natIve와 tunnel 특히 vxlan 모드에 대해서 알아보았다.
어떤 모드를 사용하는지에 따라서 동작 방식도 너무 다르고, 지원해야 하는 범위도 많이 달라지는것 같다.
natvie 모드를 사용하면 네트워크 지연과 오버헤드는 최소화하는 반면에 BGP 에이전트가 선행되어야 하고
어떤곳은 네트워크 지연을 최소화하는것이 최우선 과제이기 때문에 natvie 모드를 선택할 수 있고
어떤곳은 복잡한 네트워크 구성을 변경할 수 없어서 tunnel 모드를 선택하는 곳이 있을것 같다.
tunnel 모드는 그러한 네트워크 작업에서 자유로울수는 있지만 그만큼 오버헤드가 생겨난다.
어떤 모드가 좋다! 정답이 있다고 생각하지는 않는다. 각 모드마다 장단점이 있고 각사가 처한 환경이 다르다.
어떤것을 선택할지는 각 사의 상황과 내가 처한 문제와 감당할 수 있는 수준내에서 선택을 하면 될것 같다.

'기술 토론장 > [K8s] Kubernetes' 카테고리의 다른 글
| [Cilium][5주차] Cilium Clsuter Mesh (5) | 2025.08.17 |
|---|---|
| [Cilium][5주차] Cilium native + BGP 활용 (2) | 2025.08.16 |
| [Cilium][4주차] Node & Pod 네트워크 통신, Native vs VXLAN (6) | 2025.08.09 |
| [Cilium][3주차] Node & Pod 네트워크 통신 상세 - Routing, DNS (0) | 2025.08.03 |
| [Cilium][3주차] Node & Pod 네트워크 통신 상세 - IPAM (4) | 2025.08.02 |