CCA — Cilium Certified Associate
Declaring a Cluster Without kube-proxy
한국어 원문으로 표시합니다.
목표
kube-proxy 를 대체하는 Cilium 설정을 값 파일로 정확히 선언하고, 실제 워크로드와 서비스로 백엔드가 잡히는 과정을 확인하며, "정말 kube-proxy 가 없는가"를 스스로 증명하는 스크립트를 만듭니다.
왜 중요한가
kubeProxyReplacement: true 한 줄이면 끝날 것 같지만 현장에서는 그렇지 않습니다. k8sServiceHost 를 빼면 Cilium 이 부팅 중 API 서버를 찾지 못해 클러스터 전체가 올라오지 않고, 기존 클러스터에서 kube-proxy 를 제거하며 전환하면 노드에 남은 KUBE- 체인이 eBPF 경로와 충돌합니다. 그래서 실무의 정석은 처음부터 설치하지 않는 것이고, 그것이 실제로 이뤄졌는지는 체인 개수를 세어 확인해야 합니다.
이 실습은 그 과정을 세 갈래로 나눠 익힙니다. 값 파일 작성은 "무엇을 켜는가"를, 실제 리소스 apply 는 "라벨과 셀렉터가 어떻게 백엔드를 만드는가"를, 검증 스크립트는 "어떻게 증명하는가"를 다룹니다. 세 번째가 특히 중요합니다. 문서에 적힌 기능과 이 노드에서 실제로 동작하는 것은 다른 명제입니다.
Cilium Helm values 와 스크립트는 /root/cca-config/ 아래에 작성하고, Kubernetes 기본 리소스는 실제로 apply 합니다.
단계
- 네임스페이스
cca-net을 만드세요. /root/cca-config/cilium-values.yaml을 만들고 최상위에kubeProxyReplacement: true,k8sServiceHost: 10.0.0.120,k8sServicePort: 6443, 그리고ipam.mode: kubernetes를 쓰세요.- 같은 파일에 이어서
routingMode: tunnel,tunnelProtocol: vxlan,bpf.masquerade: true,l7Proxy: true,encryption.enabled: true,encryption.type: wireguard를 추가하세요. - 노드
lab-node-0과lab-node-1에 라벨cca.homelab/tier=gpu를, 노드lab-node-2에 라벨cca.homelab/tier=cpu를 붙이세요. - 네임스페이스
cca-net에 디플로이먼트web을 3 레플리카로 배포하세요. 파드 라벨은app=web, 이미지는nginx:1.27-alpine, 파드 스펙의nodeSelector는cca.homelab/tier: gpu입니다. - 같은 네임스페이스에 서비스
web을 만드세요. 타입은ClusterIP,port는80,targetPort는8080, selector 는app=web입니다. /root/cca-config/verify-kubeproxy-free.sh를 작성하고 실행 권한을 주세요. 이 스크립트는 (1)kubectl로 kube-system 의 kube-proxy 파드 개수를 세고, (2)iptables-save출력에서KUBE-체인 개수를 세고, (3)cilium상태에서 KubeProxyReplacement 값을 확인해야 합니다. 개수가 0 이 아니면 메시지를 출력하고exit 1로 끝내세요.
참고
- 값 파일의 중첩은
ipam.mode처럼 점으로 쓰지 말고 실제 YAML 계층으로 작성하세요.ipam:아래mode: kubernetes입니다. - 라벨 키에 슬래시가 들어가면
kubectl label node lab-node-0 cca.homelab/tier=gpu처럼 그대로 쓰면 됩니다. - 파드가 Pending 이면
kubectl describe pod의 이벤트에서 nodeSelector 불일치를 확인하세요. - 흔한 실수 1: 서비스의
targetPort를 빠뜨려port와 같은 값으로 두는 것. 컨테이너가 듣는 포트와 서비스 포트는 별개입니다. - 흔한 실수 2: 검증 스크립트가 개수를 출력만 하고 판정하지 않는 것. 0 과 비교해 실패를 만들어야 검증입니다.
실습 네임스페이스 만들기
네임스페이스 cca-net 을 만드세요.
가장 단순한 첫 단계입니다. 이름만 정확히 맞추세요.
kube-proxy 대체 핵심 값 쓰기
/root/cca-config/cilium-values.yaml 을 만들고 최상위에 kubeProxyReplacement: true, k8sServiceHost: 10.0.0.120, k8sServicePort: 6443, 그리고 ipam.mode: kubernetes 를 쓰세요.
kube-proxy 가 없으면 Cilium 자신이 API 서버 VIP 를 풀어 줄 주체인데, 부트스트랩 시점에는 아직 뜨지 않았습니다. 그래서 실제 주소를 따로 알려 줘야 합니다. IPAM 은 노드의 PodCIDR 을 그대로 쓰는 모드를 고르세요.
데이터패스 옵션 채우기
같은 파일에 이어서 routingMode: tunnel, tunnelProtocol: vxlan, bpf.masquerade: true, l7Proxy: true, encryption.enabled: true, encryption.type: wireguard 를 추가하세요.
같은 파일에 이어서 씁니다. 언더레이가 PodCIDR 경로를 모르는 홈랩이니 캡슐화가 필요하고, SNAT 도 iptables 가 아니라 eBPF 로 넘겨야 합니다. HTTP 메서드 단위 정책을 쓰려면 켜야 하는 스위치가 하나 더 있습니다.
노드에 체급 라벨 붙이기
노드 lab-node-0 과 lab-node-1 에 라벨 cca.homelab/tier=gpu 를, 노드 lab-node-2 에 라벨 cca.homelab/tier=cpu 를 붙이세요.
쿠버네티스 입장에서는 모든 GPU 가 그냥 GPU 1개입니다. 의미 있는 배치를 하려면 사람이 라벨로 의미를 심어야 합니다. 라벨 키에 슬래시가 들어가는 것에 주의하세요.
배치 제약이 붙은 워크로드 배포
네임스페이스 cca-net 에 디플로이먼트 web 을 3 레플리카로 배포하세요. 파드 라벨은 app=web, 이미지는 nginx:1.27-alpine, 파드 스펙의 nodeSelector 는 cca.homelab/tier: gpu 입니다.
파드 템플릿에 nodeSelector 를 넣습니다. 앞 단계에서 붙인 라벨 키와 값이 정확히 같아야 하고, 어긋나면 파드가 Pending 에 머뭅니다.
서비스로 묶고 백엔드 확인하기
같은 네임스페이스에 서비스 web 을 만드세요. 타입은 ClusterIP, port 는 80, targetPort 는 8080, selector 는 app=web 입니다.
서비스 포트와 컨테이너 포트는 다를 수 있습니다. selector 가 파드 라벨과 어긋나면 서비스는 만들어지지만 백엔드가 0개가 됩니다. 이 상태가 kube-proxy 든 eBPF 든 트래픽이 안 가는 가장 흔한 원인입니다.
검증 스크립트 작성하기
/root/cca-config/verify-kubeproxy-free.sh 를 작성하고 실행 권한을 주세요. 이 스크립트는 (1) kubectl 로 kube-system 의 kube-proxy 파드 개수를 세고, (2) iptables-save 출력에서 KUBE- 체인 개수를 세고, (3) cilium 상태에서 KubeProxyReplacement 값을 확인해야 합니다. 개수가 0 이 아니면 메시지를 출력하고 exit 1 로 끝내세요.
주장이 아니라 측정이어야 합니다. kube-proxy 파드 개수와 노드의 KUBE- 체인 개수를 세어 0 인지 확인하고, Cilium 쪽 상태도 함께 봐야 합니다. 실패하면 0 이 아닌 종료 코드를 내고, 파일에 실행 권한도 주세요.