[CloudNet-Cilium-Study[1기]] 6주차

진웅·2025년 8월 23일

CILIUM

목록 보기
9/14

Cilium Service Mesh

생각 정리

  • msa 아키텍처는 기존 서비스 구조보다 복잡합니다.
  • k8s pod 기준으로만 보아도 한개의 서비스를 위한 수많은 pod,container 연계해야합니다.
  • 그럼 이 app간의 통신을 위한 보안 설정, 모니터링 설정, 트레이싱 설정을 다 개발자가 일일이 코드에 넣어야 한다면 너무 복잡합니다.
  • Service Mesh 는 이런 공통 설정 부분을 별도 빼서 관리하도록 구현하는 인프라로 개발자 부담과 관리 유연성을 가져다 줍니다.
  • Istio 는 이를 envoy 라는 별도의 proxy 를 활용
  • cilium은 이를 ebpf 를 활용하여 더 좋은 성능으로 구현가능합니다.

Cilium Ingress

  • Cilium은 표준 Kubernetes Ingress 리소스를 사용 L7 라우팅 및 보안 기능 제공

Cilium Ingress 기본 설정

  • Cilium은 ingressClassNamecilium으로 지정하여 표준 Kubernetes Ingress 리소스를 사용합니다.
  • 이를 통해 경로 기반 라우팅과 TLS 종료(Termination)를 설정할 수 있습니다.

하위 호환성을 위해 kubernetes.io/ingress.class: cilium 어노테이션도 지원됩니다.

기본적으로 Cilium Ingress 컨트롤러는 LoadBalancer 타입의 서비스를 생성하므로, 사용 환경에서 LoadBalancer 서비스 타입을 지원해야 합니다.

로드밸런서 모드 (Load Balancer Mode)

Cilium은 Ingress 리소스에 대해 두 가지 로드밸런서 모드를 제공합니다.

  • dedicated: Ingress 리소스마다 전용 로드밸런서를 생성합니다.

  • shared: 모든 Ingress 리소스에 대해 공유 로드밸런서를 사용합니다.

    • shared 모드는 단일 로드밸런서 설정을 공유하여 리소스를 절약하는 반면,
    • dedicated 모드는 리소스 간의 잠재적인 충돌(예: 경로 접두사 충돌)을 방지하는 데 도움이 됩니다.

⚠️ 주의: 로드밸런서 모드를 변경하면 Ingress 리소스에 새로운 로드밸런서 IP 주소가 할당될 수 있습니다. 이 과정에서 기존 백엔드로의 활성 연결이 종료될 수 있습니다.


필수 조건

  • Cilium Ingress를 사용하기 위한 설정 요구사항
  1. NodePort 활성화: nodePort.enabled=true 또는 kube-proxy 교체 기능(kubeProxyReplacement=true)을 활성화해야 합니다.
  2. L7 프록시 활성화: l7Proxy=true로 설정해야 합니다 (기본값으로 활성화됨).
  3. 서비스 노출: 기본적으로 LoadBalancer 타입의 서비스를 지원하는 환경이 필요합니다. 대안으로 NodePort 타입을 사용하거나, Cilium 1.16부터는 Cilium L7 프록시를 호스트 네트워크에 직접 노출할 수도 있습니다.

Cilium Ingress는 어떻게 다른가?

Cilium의 Ingress 및 Gateway API 지원이 다른 컨트롤러와 다른 가장 큰 차이점은 구현이 CNI와 얼마나 밀접하게 연결되어 있는지입니다.

  • 다른 Ingress 컨트롤러: 일반적으로 클러스터에 DeploymentDaemonSet으로 배포되고 LoadBalancer 서비스를 통해 외부로 노출됩니다.
  • Cilium Ingress: 네트워킹 스택의 일부로 동작합니다. 트래픽이 서비스 포트에 도달하면, 커널 레벨의 eBPF 코드가 트래픽을 가로채 Envoy 프록시로 투명하게 전달합니다.

TPROXY를 이용한 투명한 트래픽 처리

Cilium은 Envoy를 L7 데이터플레인으로 사용하지만, 단순한 포트 포워딩(REDIRECT)이 아닌 커널의 TPROXY (Transparent Proxy) 기능을 활용합니다.

TPROXY란?
커널의 netfilter/iptables에서 지원하는 특수 기능으로, 클라이언트는 원래 목적지로 연결했다고 생각하지만 실제로는 로컬 프록시(Envoy)로 트래픽이 리디렉션됩니다. 이 과정에서 원본 Source IP/Port와 Destination IP/Port 정보가 그대로 유지됩니다.

즉, Envoy는 자신이 직접 80/443 포트에서 리스닝하는 것처럼 패킷을 수신하며, 이 모든 과정은 클라이언트에게 완전히 투명합니다.

동작 경로


Cilium Ingress에서 Envoy를 사용할 때의 트래픽 흐름을 TC(Traffic Control) 기준으로 draw.io XML 형식으로 작성했습니다.

주요 트래픽 흐름 단계:

  1. 외부 클라이언트 → HTTP 요청 발생
  2. NIC → 네트워크 인터페이스에서 패킷 수신
  3. TC @ NIC → bpf_network 프로그램에서 패킷 처리
  4. XDP Prefilter → bpf_xdp를 통한 조기 패킷 필터링
  5. Load Balancer → PREROUTING에서 로드밸런싱 결정
  6. TC @ cilium_host → bpf_host에서 호스트 레벨 처리
  7. Envoy Proxy → L7 정책 적용 및 고급 라우팅
  8. Pod Network Namespace → 대상 Pod 네트워크로 전환
  9. TC @ Endpoint → bpf_lxc에서 최종 엔드포인트 처리
  10. Application Pod → 최종 애플리케이션으로 전달

핵심 특징:

  • eBPF 기반: 커널 레벨에서 고성능 패킷 처리
  • 노드 단위 Envoy: 리소스 효율적인 L7 프록시
  • 선택적 암호화: WireGuard/IPSec 지원
  • Overlay 네트워크: VXLAN/Geneve를 통한 클러스터 간 통신

이 구조는 전통적인 사이드카 방식보다 리소스 효율적이면서도 강력한 L7 기능을 제공합니다.

실습 설치 부분 확인

helm install cilium cilium/cilium --version $2 --namespace kube-system \
--set k8sServiceHost=192.168.10.100 --set k8sServicePort=6443 \
--set ipam.mode="cluster-pool" --set ipam.operator.clusterPoolIPv4PodCIDRList={"172.20.0.0/16"} --set ipv4NativeRoutingCIDR=172.20.0.0/16 \
--set routingMode=native --set autoDirectNodeRoutes=true --set endpointRoutes.enabled=true --set directRoutingSkipUnreachable=true \
--set kubeProxyReplacement=true --set bpf.masquerade=true --set installNoConntrackIptablesRules=true \
--set endpointHealthChecking.enabled=false --set healthChecking=false \
--set hubble.enabled=true --set hubble.relay.enabled=true --set hubble.ui.enabled=true \
--set hubble.ui.service.type=NodePort --set hubble.ui.service.nodePort=30003 \
--set prometheus.enabled=true --set operator.prometheus.enabled=true --set hubble.metrics.enableOpenMetrics=true \
--set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,httpV2:exemplars=true;labelsContext=source_ip\,source_namespace\,source_workload\,destination_ip\,destination_namespace\,destination_workload\,traffic_direction}" \
--set ingressController.enabled=true --set ingressController.loadbalancerMode=shared --set loadBalancer.l7.backend=envoy \
--set localRedirectPolicy=true --set l2announcements.enabled=true \
--set operator.replicas=1 --set debug.enabled=true

Ingress 및 Envoy 설정 상세 분석

  • ingress Controller 설정
--set ingressController.enabled=true
--set ingressController.loadbalancerMode=shared
--set loadBalancer.l7.backend=envoy

상세 분석

1. ingressController.enabled=true
- 기능: Cilium에 내장된 Ingress Controller를 활성화

  • 의미: 별도의 NGINX나 Traefik 같은 외부 Ingress Controller 없이 Cilium이 직접 Ingress 기능을 제공
  • 장점:
    • 추가적인 리소스 사용량 없음
    • Cilium의 eBPF 기반 네트워킹과 완전히 통합된 성능
    • 단일 컨트롤 플레인으로 네트워킹과 Ingress 관리
  1. ingressController.loadbalancerMode=shared
  • 기능: 로드밸런서 모드를 공유(shared)로 설정
  • 의미:
    여러 Ingress 리소스가 동일한 로드밸런서 인스턴스를 공유
    리소스 효율성 증대 (각 Ingress마다 별도의 LoadBalancer 생성하지 않음)
  • 대안:
    dedicated: 각 Ingress마다 전용 로드밸런서 생성
    shared가 일반적으로 권장됨 (리소스 절약)
  1. loadBalancer.l7.backend=envoy
  • 기능: Layer 7 로드밸런싱 백엔드로 Envoy Proxy 사용
  • 의미:
    HTTP/HTTPS 트래픽 처리를 위해 Envoy 프록시를 사용
    Cilium이 Envoy를 내부적으로 관리하고 설정

Envoy와 Cilium의 통합 구조

Internet → NodePort/LoadBalancer → Cilium Ingress Controller → Envoy Proxy → Backend Pods
트래픽 유입: 외부 트래픽이 Kubernetes Service를 통해 유입
Cilium Ingress Controller: Ingress 규칙을 해석하고 라우팅 결정
Envoy Proxy: L7 프로토콜 처리, 로드밸런싱, SSL 종료 등 수행
Backend Pods: 실제 애플리케이션으로 트래픽 전달

  • Envoy 설정의 장점
    • 성능: eBPF와 결합된 고성능 데이터 평면
    • 보안: Cilium의 네트워크 정책과 완벽 통합
    • 관찰성: Hubble과 연동하여 L7 트래픽 시각화
    • 확장성: 마이크로서비스 아키텍처에 최적화

  • 실제 사용 예시
    Cilium Ingress Controller와 Envoy가 활성화되면 다음과 같은 Ingress 리소스를 생성할 수 있습니다.
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    ingress.cilium.io/loadbalancer-mode: shared
spec:
  ingressClassName: cilium
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: example-service
            port:
              number: 80

이 설정을 통해 Cilium이 Envoy를 백엔드로 사용하여 HTTP 트래픽을 처리하고 적절한 서비스로 라우팅.

cilium 실습 설정 확인

(⎈|HomeLab:N/A) root@k8s-ctr:~# cilium config view | grep -E '^loadbalancer|l7'

enable-l7-proxy                                   true
loadbalancer-l7                                   envoy
loadbalancer-l7-algorithm                         round_robin
loadbalancer-l7-ports  

ingress 에 예약된 내부 IP 확인 : node(cilium-envoy) 별로 존재

(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -it -n kube-system ds/cilium -- cilium ip list | grep ingress

172.20.0.217/32     reserved:ingress                                                                    
172.20.1.74/32      reserved:ingress 

envoy docket 확인

(⎈|HomeLab:N/A) root@k8s-ctr:~# ls -al /var/run/cilium/envoy/sockets

total 0
drwxr-xr-x 3 root root 120 Aug 23 21:45 .
drwxr-xr-x 4 root root  80 Aug 23 21:45 ..
srw-rw---- 1 root 1337   0 Aug 23 21:45 access_log.sock
srwxr-xr-x 1 root root   0 Aug 23 21:45 admin.sock
drwxr-xr-x 3 root root  60 Aug 23 21:45 envoy
srw-rw---- 1 root 1337   0 Aug 23 21:45 xds.sock

(⎈|HomeLab:N/A) root@k8s-ctr:~#kubectl get svc,ep -n kube-system cilium-envoy

Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME                   TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
service/cilium-envoy   ClusterIP   None         <none>        9964/TCP   6d4h
NAME                     ENDPOINTS                                 AGE
endpoints/cilium-envoy   192.168.10.100:9964,192.168.10.101:9964   6d4h

(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get svc,ep -n kube-system cilium-ingress

Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME                     TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
service/cilium-ingress   LoadBalancer   10.96.20.205   <pending>     80:32752/TCP,443:32058/TCP   6d4h
NAME                       ENDPOINTS              AGE
endpoints/cilium-ingress   192.192.192.192:9999   6d4h

LB-IPAM 설정 실습

(⎈|HomeLab:N/A) root@k8s-ctr:~# cilium config view | grep l2

enable-l2-announcements                           true
enable-l2-neigh-discovery                         false

(⎈|HomeLab:N/A) root@k8s-ctr:~# cat << EOF | kubectl apply -f -

apiVersion: "cilium.io/v2"
kind: CiliumLoadBalancerIPPool
metadata:
name: "cilium-lb-ippool"
spec:
blocks:

  • start: "192.168.10.211"
    stop: "192.168.10.215"
    EOF
    ciliumloadbalancerippool.cilium.io/cilium-lb-ippool created

(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl get ippool

NAME               DISABLED   CONFLICTING   IPS AVAILABLE   AGE
cilium-lb-ippool   false      False         4               27s

(⎈|HomeLab:N/A) root@k8s-ctr:~# cat << EOF | kubectl apply -f -

apiVersion: "cilium.io/v2alpha1"
kind: CiliumL2AnnouncementPolicy
metadata:
name: policy1
spec:
interfaces:

  • eth1
    externalIPs: true
    loadBalancerIPs: true
    EOF
    ciliuml2announcementpolicy.cilium.io/policy1 created

현재 리더 역할 노드 확인

(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl -n kube-system get lease | grep "cilium-l2announce"

cilium-l2announce-kube-system-cilium-ingress   k8s-w1                                                                      23s

K8S 클러스터 내부 LB EX-IP로 호출 가능

  • (⎈|HomeLab:N/A) root@k8s-ctr:~# LBIP=$(kubectl get svc -n kube-system cilium-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    echo $LBIP
    arping -i eth1 $LBIP -c 2
192.168.10.211
ARPING 192.168.10.211
60 bytes from 08:00:27:e0:f3:02 (192.168.10.211): index=0 time=4.834 usec
60 bytes from 08:00:27:e0:f3:02 (192.168.10.211): index=1 time=430.791 usec
--- 192.168.10.211 statistics ---
2 packets transmitted, 2 packets received,   0% unanswered (0 extra)
rtt min/avg/max/std-dev = 0.005/0.218/0.431/0.213 ms

k8s 외부 노드(router)에서 LB EX-IP로 호출 가능 확인

(⎈|HomeLab:N/A) root@k8s-ctr:~# sshpass -p 'vagrant' ssh vagrant@router sudo arping -i eth1 $LBIP -c 2

profile
bytebliss

0개의 댓글