Kubernetes

[ Kans 3 Study - 8w ] 1. Cilium

su''@ 2024. 10. 27. 05:04
CloudNetaStudy - Kubernets Networtk 3기 실습 스터디 게시글입니다.

 

[ 1.1 BPF/eBPF 소개 ]

  • Linux Network Stack : 리눅스 네트워크 스택의 단점은 복잡하고, 변경에 시간이 걸리고, 레이어를 건너뛰기 어렵다.
    출처 : https://bit.ly/3EiLsU3
    출처 : https://cilium.io/blog/2020/11/10/ebpf-future-of-networking/

    • BPF replaces IPtables
    • BPF (Berkeley Packet Filter) kernel hooks : BPF 는 커널에 삽입하여 패킷통제(필터링) 할 수 있으며, 다양한 영역에서 Hook 을 통해서 접근 할 수 있습니다.
      출처 : https://bit.ly/3EiLsU3
  • extended Berkeley Packet Filter - 링크
    • Dynamically program the kernel for efficient networking, observability, tracing, and security
      출처 : https://ebpf.io/
    • BPF(1992년) 를 확장해서 eBPF가 (2014년, Alexei Starovoitov) 가 나왔고, eBPF다양한 영역 (보안, 추적, 네트워킹, 모니터링)에서 활용하기 시작하였습니다.
    • eBPF is a revolutionary technology that can run sandboxed programs in the Linux kernel without changing kernel source code or loading kernel modules.
      → 커널 내에 (샌드박스 내에서) 자유롭게 프로그래밍하여 적용 할 수 있다
      출처 : https://ebpf.io/

[ 1.2 Cilium 소개 ]

  • Cilium은 eBPF (Berkeley Packet Filter)를 기반으로 Pod Network 환경 + 보안 을 제공하는 CNI Plugin 입니다
    출 처 : https://isovalent.com/blog/post/migrating-from-metallb-to-cilium/
  • Kubernetes와 같은 Linux 컨테이너 관리 플랫폼을 사용하여 배포된 응용 프로그램 서비스 간의 네트워크 및 API 연결을 제공하는 오픈 소스 소프트웨어 입니다.
    출처 : https://cilium.io/blog/2020/11/10/ebpf-future-of-networking/
  • Cilium eBPF 는 추가적인 App 이나 설정 변경 없이 리눅스 커널을 자유롭게 프로그래밍하여 동작 가능 - 링크
    • Kernel Layer에서 동작하는 Bytecode를 안전하게 Kernel에 Loading(injection) 할 수 있다
      출처 : https://cilium.io/blog/2020/11/10/ebpf-future-of-networking/
  • Cilium attaches eBPF programs to ingress TC hooks of these links in order to intercept all incoming packets for further processing.
    • 모든 패킷을 가로채기 위해서 수신 NIC 의 ingress TC hooks 을 사용한다
    • Linux TC(Traffic Control) : 커널에서 동작하는 패킷 스케줄러 - 링크
      그림의 NIC 에 TC Hooks 에 eBPF 프로그램이 Attach 되어서 실행됩니다
  • 2가지 네트워크 모드를 제공 : 터널 모드(VXLAN, GENEVE), 네이티브 라우팅 모드
    • In the tunnel mode, Cilium sets up a number of VXLAN(UDP 8472) or Geneve(UDP 6081) interfaces and forwards traffic over them.
    • In the native-routing mode, Cilium does nothing to setup reachability, assuming that it will be provided externally.
      출처 : ttps://docs.cilium.io/en/stable/concepts/networking/routing/#native-routing
  • 2021.10월 Cilium CNCFJoin 되었습니다 - 링크
  • 또한 Google GKE dataplane 과 AWS EKS Anywhere 에 기본 CNI 로 Cilium 을 사용합니다 - 링크
  • 100% Kube-proxy replacement : iptables 거의 사용하지 않아도 동작, Datapath Optimizations (iptables bypass) - Docs
    • 하지만 iptables 기능을 활용하는 일부 동작들은 이슈가 발생할 수 있음, 물론 지속해서 해당 이슈를 해결하고 있음 (예. istio, FHRP/VRRP - 링크)
  • 예시) 기존의 IPtables 를 사용하지 않고, eBPF 로 Masqueading(SNAT) 처리
  • alico vs Cilium 성능 비교 - 링크

[ 1.3 Cilium 아키텍처 ]

  • 구성요소 - 링크
    출처 : https://github.com/cilium/cilium
  • Cilium Agent : 데몬셋으로 실행, K8S API 설정으로 부터 '네트워크 설정, 네트워크 정책, 서비스 부하분산, 모니터링' 등을 수행하며, eBPF 프로그램을 관리한다.
  • Cilium Client (CLI) : Cilium 커멘드툴, eBPF maps 에 직접 접속하여 상태를 확인할 수 있다.
  • Cilium Operator : K8S 클러스터에 대한 한 번씩 처리해야 하는 작업을 관리.
  • Hubble : 네트워크와 보안 모니터링 플랫폼 역할을 하여, 'Server, Relay, Client, Graphical UI' 로 구성되어 있다.
  • Data Store : Cilium Agent 간의 상태를 저장하고 전파하는 데이터 저장소, 2가지 종류 중 선택(K8S CRDs, Key-Value Store)
    Cilium control flow
  • eBPF Datapath - 링크
    • Introduction - 링크
      • The Linux kernel supports a set of BPF hooks in the networking stack that can be used to run BPF programs.
      • XDP : 네트워킹 드라이버의 가장 앞 단에서 XDP BPF hook 을 통해서 BPF program 을 트리거되기 때문에, 가능한 최고의 패킷 처리 성능을 제공https://cilium.io/blog/2020/06/22/cilium-18
        출처 : https://cilium.io/blog/2020/06/22/cilium-18
        • Prefilter: An XDP program and provides a set of prefilter rules used to filter traffic from the network for best performance.
        • LoadBalancer & NodePort XDP Acceleration
        • XDP-based Standalone Load Balancer : Maglev Consistent Hashing , n-Tuple PCAP Recorder
      • TC (Traffic Control) Ingress/Egress
        • Network Interfacetc ingress hook 에서 BPF programs 실행된다.
        • 파드와 연결된 veth pair 의 lxc 의 tc ingress hook 에서 BPF programs 실행된다. 노드(호스트)로 in/out 트래픽 모두를 모니터링 및 통제/정책을 적용할 수 있다.
      • Socket operations : BPF socket operations program 은 root cgroup 에 연결되며 TCP event(ESTABLISHED) 에서 실행됨
      • Socket send/recv : The socket send/recv hook 은 TCP socket 의 모든 송수신 작업에서 실행, hook 에서 검사/삭제/리다이렉션을 할 수 있다
      • Endpoint Policy: 정책에 따라 패킷을 차단/전달하거나, 서비스로 전달하거나, L7 정책 전달 할 수 있다.
        • the Cilium datapath responsible for mapping packets to identities and enforcing L3 and L4 policies.
      • Service: 모든 패킷의 목적지 IP/Port 의 map 조회 시 일치하면 L3/L4 endpoint 로 전달하며, Service block 는 모든 인터페이스의 TC ingress hook 에서 동작할 수 있다.
      • L3 Encryption, Socket Layer Enforcement : skip~
      • L7 Policy: The L7 Policy object redirect proxy traffic to a Cilium userspace proxy instance. Cilium uses an Envoy instance as its userspace proxy. Envoy will then either forward the traffic or generate appropriate reject messages based on the configured L7 policy.
  • Life of a Packet
    • Endpoint to Endpoint : 그림처럼 L7 정책 시에는 커널 hookpoint 와 Userspace Proxy 사용으로 성능이 조금 떨어질 수 있다Egress from EndpointIngress to Endpoint
    • Egress from Endpoint
    • Ingress to Endpoint
  • eBPF Maps - 링크
    • 모든 eBPF Map 은 상한 용량이 있으며, limit 관련 여러 옵션들이 있다.
    • kube-proxy 는 리눅스 코어에 따라 CT table 최대 수가 결정되며, Cilium 은 BPF Maps 이라는 자체 연결 추적 테이블을 가지고 메모리에 따라 최대 수가 결정됨
  • Iptables Usage - 링크
    • 커널 버전이 낮을 경우 iptables 동작으로 구현 될 수 있다. 혹은 cilium 미동작(장애 등 문제) 시, 트래픽 처리 보완 시.
    • 아래 그림은 cilium 과 iptables 을 같이 사용 시 다이어그램을 나타낸다.

 

2. Cilium 배포

 

[ 2.1 배포 ]

  • Cilium 설치 정보(w/Helm) 및 확인 - Docs
    # 모니터링
    watch -d kubectl get node,pod -A -owide
    
    #
    helm repo add cilium https://helm.cilium.io/
    helm repo update
    
    #
    helm install cilium cilium/cilium --version 1.16.3 --namespace kube-system \
    --set k8sServiceHost=192.168.10.10 --set k8sServicePort=6443 --set debug.enabled=true \
    --set rollOutCiliumPods=true --set routingMode=native --set autoDirectNodeRoutes=true \
    --set bpf.masquerade=true --set bpf.hostRouting=true --set endpointRoutes.enabled=true \
    --set ipam.mode=kubernetes --set k8s.requireIPv4PodCIDR=true --set kubeProxyReplacement=true \
    --set ipv4NativeRoutingCIDR=192.168.0.0/16 --set installNoConntrackIptablesRules=true \
    --set hubble.ui.enabled=true --set hubble.relay.enabled=true --set prometheus.enabled=true --set operator.prometheus.enabled=true --set hubble.metrics.enableOpenMetrics=true \
    --set hubble.metrics.enabled="{dns:query;ignoreAAAA,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 operator.replicas=1
    
    ## 주요 파라미터 설명
    --set debug.enabled=true # cilium 파드에 로그 레벨을 debug 설정
    --set autoDirectNodeRoutes=true # 동일 대역 내의 노드들 끼리는 상대 노드의 podCIDR 대역의 라우팅이 자동으로 설정
    --set endpointRoutes.enabled=true # 호스트에 endpoint(파드)별 개별 라우팅 설정
    --set hubble.relay.enabled=true --set hubble.ui.enabled=true # hubble 활성화
    --set ipam.mode=kubernetes --set k8s.requireIPv4PodCIDR=true # k8s IPAM 활용
    --set kubeProxyReplacement=true # kube-proxy 없이 (최대한) 대처할수 있수 있게
    --set ipv4NativeRoutingCIDR=192.168.0.0/16 # 해당 대역과 통신 시 IP Masq 하지 않음, 보통 사내망 대역을 지정
    --set operator.replicas=1 # cilium-operator 파드 기본 1개
    --set enableIPv4Masquerade=true --set bpf.masquerade=true # 파드를 위한 Masquerade , 추가로 Masquerade 을 BPF 로 처리 >> enableIPv4Masquerade=true 인 상태에서 추가로 bpf.masquerade=true 적용이 가능
    
    # 설정 및 확인
    ip -c addr
    kubectl get node,pod,svc -A -owide
    iptables -t nat -S
    iptables -t filter -S
    iptables -t raw -S
    iptables -t mangle -S
    conntrack -L
    
    kubectl get crd
    kubectl get ciliumnodes # cilium_host 인터페이스의 IP 확인 : CILIUMINTERNALIP
    kubectl get ciliumendpoints -A
    
    kubectl get cm -n kube-system cilium-config -o json | jq
    
    kubetail -n kube-system -l k8s-app=cilium --since 1h
    kubetail -n kube-system -l k8s-app=cilium-envoy --since 1h
    
    # Native XDP 지원 NIC 확인 : https://docs.cilium.io/en/stable/bpf/progtypes/#xdp-drivers
    ethtool -i ens5
    driver: ena
    version: 6.8.0-1015-aws
    ...
    
    # https://docs.cilium.io/en/stable/operations/performance/tuning/#bypass-iptables-connection-tracking
    watch -d kubectl get pod -A # 모니터링
    helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values --set installNoConntrackIptablesRules=true
    
    # 확인: 기존 raw 에 아래 rule 추가 확인
    iptables -t raw -S | grep notrack
    -A CILIUM_OUTPUT_raw -d 192.168.0.0/16 -m comment --comment "cilium: NOTRACK for pod traffic" -j CT --notrack
    -A CILIUM_OUTPUT_raw -s 192.168.0.0/16 -m comment --comment "cilium: NOTRACK for pod traffic" -j CT --notrack
    ...
    
    conntrack -F
    conntrack -L
    conntrack -L |grep -v 2379
     
  • Cilium CLI 설치 : inspect the state of a Cilium installation, and enable/disable various features (e.g. clustermesh, Hubble) - Link
    # Cilium CLI 설치
    CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
    CLI_ARCH=amd64
    if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
    curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
    sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
    sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
    rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
    
    # 확인
    cilium status --wait
    cilium config view
    
    # cilium 데몬셋 파드 내에서 cilium 명령어로 상태 확인
    export CILIUMPOD0=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-s  -o jsonpath='{.items[0].metadata.name}')
    alias c0="kubectl exec -it $CILIUMPOD0 -n kube-system -c cilium-agent -- cilium"
    c0 status --verbose
    ...
    KubeProxyReplacement:   True   [ens5   192.168.10.10 fe80::57:abff:fee3:da8d (Direct Routing)]
    ...
    IPAM:                   IPv4: 2/254 allocated from 172.16.0.0/24, 
    Allocated addresses:
      172.16.0.159 (router)
      172.16.0.171 (health)
    ...
    Routing:                Network: Native   Host: BPF
    ...
    Device Mode:            veth
    Masquerading:           BPF   [ens5]   192.168.0.0/16 [IPv4: Enabled, IPv6: Disabled]
    ...  
    Proxy Status:            OK, ip 172.16.0.159, 0 redirects active on ports 10000-20000, Envoy: external
    ...
    KubeProxyReplacement Details:
      Status:                 True
      Socket LB:              Enabled
      Socket LB Tracing:      Enabled
      Socket LB Coverage:     Full
      Devices:                ens5   192.168.10.10 fe80::57:abff:fee3:da8d (Direct Routing)
      Mode:                   SNAT
      Backend Selection:      Random
      Session Affinity:       Enabled
      Graceful Termination:   Enabled
      NAT46/64 Support:       Disabled
      XDP Acceleration:       Disabled
      Services:
      - ClusterIP:      Enabled
      - NodePort:       Enabled (Range: 30000-32767) 
      - LoadBalancer:   Enabled 
      - externalIPs:    Enabled 
      - HostPort:       Enabled
    BPF Maps:   dynamic sizing: on (ratio: 0.002500)
    ...
    
    # Native Routing 확인 : # 192.168.0.0/16 대역은 IP Masq 없이 라우팅
    c0 status | grep KubeProxyReplacement
    ubeProxyReplacement:    True   [ens5   192.168.10.10 fe80::57:abff:fee3:da8d (Direct Routing)]
    
    # enableIPv4Masquerade=true(기본값) , bpf.masquerade=true 확인
    cilium config view | egrep 'enable-ipv4-masquerade|enable-bpf-masquerade'
    enable-bpf-masquerade                          true
    enable-ipv4-masquerade                         true
    
    c0 status --verbose | grep Masquerading
    Masquerading:           BPF   [ens5]   192.168.0.0/16 [IPv4: Enabled, IPv6: Disabled]
    
    # Configure the eBPF-based ip-masq-agent
    # https://docs.cilium.io/en/stable/network/concepts/masquerading/
    helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values --set ipMasqAgent.enabled=true
    
    #
    cilium config view | grep -i masq
    enable-bpf-masquerade                             true
    enable-ip-masq-agent                              true
    ...
    
    export CILIUMPOD0=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-s  -o jsonpath='{.items[0].metadata.name}')
    alias c0="kubectl exec -it $CILIUMPOD0 -n kube-system -c cilium-agent -- cilium"
    c0 status --verbose | grep Masquerading
    Masquerading:           BPF (ip-masq-agent)   [ens5]   192.168.0.0/16 [IPv4: Enabled, IPv6: Disabled]
    
    kubectl get cm -n kube-system cilium-config -o yaml  | grep ip-masq
      enable-ip-masq-agent: "true"


[ 2.2 Cilium 기본 정보 확인 ]

  • 변수 & 단축키
    # cilium 파드 이름
    export CILIUMPOD0=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-s  -o jsonpath='{.items[0].metadata.name}')
    export CILIUMPOD1=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-w1 -o jsonpath='{.items[0].metadata.name}')
    export CILIUMPOD2=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-w2 -o jsonpath='{.items[0].metadata.name}')
    
    # 단축키(alias) 지정
    alias c0="kubectl exec -it $CILIUMPOD0 -n kube-system -c cilium-agent -- cilium"
    alias c1="kubectl exec -it $CILIUMPOD1 -n kube-system -c cilium-agent -- cilium"
    alias c2="kubectl exec -it $CILIUMPOD2 -n kube-system -c cilium-agent -- cilium"
    
    alias c0bpf="kubectl exec -it $CILIUMPOD0 -n kube-system -c cilium-agent -- bpftool"
    alias c1bpf="kubectl exec -it $CILIUMPOD1 -n kube-system -c cilium-agent -- bpftool"
    alias c2bpf="kubectl exec -it $CILIUMPOD2 -n kube-system -c cilium-agent -- bpftool"
    
    # Hubble UI 웹 접속
    kubectl patch -n kube-system svc hubble-ui -p '{"spec": {"type": "NodePort"}}'
    HubbleUiNodePort=$(kubectl get svc -n kube-system hubble-ui -o jsonpath={.spec.ports[0].nodePort})
    echo -e "Hubble UI URL = http://$(curl -s ipinfo.io/ip):$HubbleUiNodePort"
    
    # 자주 사용 명령
    helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values --set
    kubetail -n kube-system -l k8s-app=cilium --since 12h
    kubetail -n kube-system -l k8s-app=cilium-envoy --since 12h
  • 자주 쓰는 Cilium CLI 명령어
    # cilium 파드 확인
    kubectl get pod -n kube-system -l k8s-app=cilium -owide
    
    # cilium 파드 재시작
    kubectl -n kube-system rollout restart ds/cilium
    혹은
    kubectl delete pod -n kube-system -l k8s-app=cilium
    
    # cilium 설정 정보 확인
    cilium config view
    
    # cilium 파드의 cilium 상태 확인
    c0 status --verbose
    
    # cilium 엔드포인트 확인
    kubectl get ciliumendpoints -A
    c0 endpoint list
    c0 bpf endpoint list
    c0 map get cilium_lxc
    c0 ip list
    
    # Manage the IPCache mappings for IP/CIDR <-> Identity
    c0 bpf ipcache list
    
    # Service/NAT List 확인
    c0 service list
    c0 bpf lb list
    c0 bpf lb list --revnat
    c0 bpf nat list
    
    # List all open BPF maps
    c0 map list
    c0 map list --verbose
    
    # List contents of a policy BPF map : Dump all policy maps
    c0 bpf policy get --all
    c0 bpf policy get --all -n
    
    # cilium monitor
    c0 monitor -v
    c0 monitor -v --type l7

  • Cilium 기본 정보 확인 ← 스터디 시간에는 Skip~
    # cilium 버전 확인
    cilium version
    
    # cilium 상태 확인
    cilium status
    
    # kube-proxy 파드 확인 >> 없다!
    kubectl get pod -A
    
    # cilium 설정 정보 확인
    kubectl get cm -n kube-system cilium-config -o yaml
    cilium config view
    
    # ciliumnodes(cn) 정보 확인
    kubectl get cn
    kubectl get cn k8s-m -o yaml
    
    # 노드별 파드 대역 확인
    kubectl get ciliumnodes -o yaml | grep podCIDRs -A1
    
    # cilium 파드 확인
    kubectl get pod -n kube-system -l k8s-app=cilium -owide
    
    # cilium 엔드포인트 확인
    kubectl get ciliumendpoints.cilium.io -A
    
    --------------------------------------------
    # cilium cli 도움말
    c0 help
    
    # cilium 파드의 cilium 상태 확인
    c0 status
    c1 status
    c2 status
    c0 status --verbose
    
    # 각 노드에서 파드에 할당된 IP 확인
    c0 status --verbose | grep Allocated -A5
    c1 status --verbose | grep Allocated -A5
    c2 status --verbose | grep Allocated -A5
    
    # 엔드포인트 리스트 : ID, 정책, 라벨, IP 주소, 상태 확인
    c2 endpoint list
    
    # 노드 리스트
    c0 node list
    
    # BFP(Direct access to local BPF maps)
    # BFP 터널 리스트 확인 : Overlay Mode 사용 시 터널 정보 출력
    c0 bpf tunnel list
    	TUNNEL         VALUE
    	172.16.1.0:0   192.168.200.101:0
    	172.16.2.0:0   192.168.200.102:0
    c1 bpf tunnel list
    	TUNNEL         VALUE
    	172.16.2.0:0   192.168.200.102:0
    	172.16.0.0:0   192.168.200.10:0
    c2 bpf tunnel list
    	TUNNEL         VALUE
    	172.16.0.0:0   192.168.200.10:0
    	172.16.1.0:0   192.168.200.101:0
    
    # 해당 노드의 로컬 엔드포인트 리스트 : nodemac 은 해당 파드와 veth pair 인 인터페이스의 mac 주소이다!
    c0 bpf endpoint list
    
    # Connection tracking tables - List connection tracking entries
    c0 bpf ct list global
    
    # Flush all NAT mapping entries
    c0 bpf nat flush
    
    # List all NAT mapping entries
    c0 bpf nat list
    
    # service list 확인, Frontend 는 Service IP, Backend 는 Pod IP(endpoint IP)를 보여준다.
    c0 service list
    
    # List load-balancing configuration
    c0 bpf lb list
    
    # List reverse NAT entries
    c0 bpf lb list --revnat
    
    # List all open BPF maps
    c0 map list
    c0 map list --verbose
    c0 map get cilium_lxc
    c0 map get cilium_ipcache
    
    # cilium monitor
    c0 monitor -h
    c0 monitor -v
    c0 monitor -v --type l7
    
    # Cilium will automatically mount cgroup v2 filesystem required to attach BPF cgroup programs by default at the path /run/cilium/cgroupv2
    mount | grep cilium
    tree /run/cilium/cgroupv2/ -L 1
    
    # CNI Plugin 확인
    tree /etc/cni/net.d/
    cat /etc/cni/net.d/05-cilium.conf
    
    # Manage IP addresses and associated information - IP List
    c0 ip list
    
    # IDENTITY :  1(host), 2(world), 4(health), 6(remote), 파드마다 개별 ID를 가지는 것으로 보인다!
    c0 ip list -n
    
    # 엔드포인트 설정 확인 및 변경
    c0 endpoint config <엔트포인트ID>
    
    # 엔드포인트 상세 정보 확인
    c0 endpoint get <엔트포인트ID>
    
    # 엔드포인트 로그 확인
    c0 endpoint log <엔트포인트ID>
    
    # Show bpf filesystem mount details
    c0 bpf fs show
    
    # bfp 마운트 폴더 확인
    tree /sys/fs/bpf
    
    # List contents of a policy BPF map : Dump all policy maps
    c0 bpf policy get --all
    c0 bpf policy get --all -n
    
    # BPF datapath traffic metrics
    c0 bpf metrics list
    
    # Manage the IPCache mappings for IP/CIDR <-> Identity
    c0 bpf ipcache list
    
    # Manage compiled BPF template objects
    c0 bpf sha list
    
    # Get datapath SHA header
    c0 bpf sha get <Datapath SHA>
    
    # Retrieve information about an identity
    c0 identity list
    
    # 엔드포인트 기준 ID
    c0 identity list --endpoints
    
    # Access metric status
    c0 metrics list

  • 네트워크 기본 정보 확인 : k8s-w1/w2 에 SSH 접속 후 ip -c link/route 정보 확인
    # 네트워크 인터페이스 정보 확인
    ip -br -c link
    ip -br -c addr
    
    --------------------------------------------
    # cilium_net 과 cilium_host 는 veth peer 관계이며, cilium_host 는 파드의 GW IP 주소로 지정되며 32bit 이다
    ip -c addr show cilium_net ; ip -c addr show cilium_host
    	5: cilium_net@cilium_host: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    	    link/ether 36:88:bf:c9:5c:6c brd ff:ff:ff:ff:ff:ff
    	   ...
    	6: cilium_host@cilium_net: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    	    link/ether 4e:6a:8e:44:85:61 brd ff:ff:ff:ff:ff:ff
    	    inet 172.16.1.254/32 scope link cilium_host
       ...
    
    # proxy arp 는 disable(0) 상태이며, 파드와 연결된 lxc 도 모두 0 이다
    # 파드의 32bit ip의 gw 가 각각 연결된 veth 인터페이스의 mac 으로 cilium_host 의 IP/MAC 응답을 처리한다, 어떻게 동작이 되는걸까요? >> eBPF program!!!
    cat /proc/sys/net/ipv4/conf/cilium_net/proxy_arp
    0
    cat /proc/sys/net/ipv4/conf/cilium_host/proxy_arp
    0
    
    # lxc_health 인터페이스는 veth 로 cilium(NET NS 0, 호스트와 다름)과 veth pair 이다 - 링크
    # cilium 인터페이스에 파드 IP가 할당되어 있으며, cilium-health-responder 로 동작한다
    lsns -t net

    출처 : http://arthurchiao.art/blog/ctrip-network-arch-evolution/
  • Cilium Container Networking Control Flow - Link

2.3 Hubble UI & CLI  ]

  • Observability
    • Network Observability with Hubble - Link
      • Setting up Hubble Observability - Link
      • Inspecting Network Flows with the CLI - Link
      • Service Map & Hubble UI - Link
      • Configuring Hubble exporter - Link
      • Configure TLS with Hubble - Link
    • Running Prometheus & Grafana - Link
    • Monitoring & Metrics - Link
    • Layer 7 Protocol Visibility - Link
    • Hubble for Network Observability and Security (Part 3): Leveraging Hubble Data for Network Security - Link
    • Hubble for Network Observability and Security (Part 2): Utilizing Hubble for Network Observability - Link
    • Hubble for Network Observability and Security (Part 1): Introduction to Cilium and Hubble - Link
  • Hubble 소개 : 통신 및 서비스와 네트워킹 인프라의 동작에 대한 심층적인 가시성을 완전히 투명한 방식으로 제공하는 관찰성을 제공 - Blog
    • Hubble is a fully distributed networking and security observability platform. → 네트워크/보안 모니터링
    • It is built on top of Cilium and eBPF to enable deep visibility into the communication and behavior of services as well as the networking infrastructure in a completely transparent manner. without requiring the application to change in any way. → 애플리케이션의 코드 수정 등 추가 설정 없이 동작
    • containerized workloads as well as more traditional workloads such as virtual machines and standard Linux processes. → VM/서버도 모니터링 가능
    • By leveraging Linux eBPF, Cilium retains the ability to transparently insert security visibility + enforcement, but does so in a way that is based on service / pod / container identity (in contrast to IP address identification in traditional systems) and can filter on application-layer (e.g. HTTP). → 전통적인 IP 기반은 모니터링/통제가 아니라 서비스/파드/ID 기반으로 모니터링/통제를 제공
    • 기본적으로 Hubble API는 Cilium 에이전트가 실행되는 개별 노드의 범위 내에서 작동합니다. 이는 네트워크 통찰력을 로컬 Cilium 에이전트가 관찰한 트래픽으로 제한합니다. Hubble CLI( hubble)를 사용하여 로컬 Unix Domain Socket을 통해 제공된 Hubble API를 쿼리할 수 있습니다. Hubble CLI 바이너리는 기본적으로 Cilium 에이전트 포드에 설치됩니다.
    • Hubble Relay를 배포하면 전체 클러스터 또는 ClusterMesh 시나리오의 여러 클러스터에 대한 네트워크 가시성이 제공됩니다. 이 모드에서 Hubble 데이터는 Hubble CLI( hubble)를 Hubble Relay 서비스로 지정하거나 Hubble UI를 통해 액세스할 수 있습니다. Hubble UI는 L3/L4 및 L7 계층에서 서비스 종속성 그래프를 자동으로 검색할 수 있는 웹 인터페이스로, 사용자 친화적인 시각화 및 서비스 맵으로서의 데이터 흐름 필터링을 허용합니다.
    • Metrics export via Prometheus: Key metrics are exported via Prometheus for integration with your existing dashboards.
      출처 : https://cilium.io/blog/2019/11/19/announcing-hubble
    • Cluster-wide observability with Hubble Relay
    • 통제 예시
      • Allow all HTTP requests with method GET and path /public/.*. Deny all other requests.
      • Allow service1 to produce on Kafka topic topic1 and service2 to consume on topic1. Reject all other Kafka messages.
      • Require the HTTP header X-Token: [0-9]+ to be present in all REST calls.
  • Hubble UI/CLI 접근 및 확인 - Docs
    # 확인
    cilium status
    
    # UI 파드 정보 확인
    kubectl get pod -n kube-system -l k8s-app=hubble-ui -o wide
    
    # Hubble UI 웹 접속
    kubectl patch -n kube-system svc hubble-ui -p '{"spec": {"type": "NodePort"}}'
    HubbleUiNodePort=$(kubectl get svc -n kube-system hubble-ui -o jsonpath={.spec.ports[0].nodePort})
    echo -e "Hubble UI URL = http://$(curl -s ipinfo.io/ip):$HubbleUiNodePort"
    
    ## Service NodePort 생성 후 아래 정보 확인!
    iptables -t nat -S
    conntrack -L
    conntrack -L |grep -v 2379
    
    # Install Hubble Client
    HUBBLE_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/hubble/master/stable.txt)
    HUBBLE_ARCH=amd64
    if [ "$(uname -m)" = "aarch64" ]; then HUBBLE_ARCH=arm64; fi
    curl -L --fail --remote-name-all https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-${HUBBLE_ARCH}.tar.gz{,.sha256sum}
    sha256sum --check hubble-linux-${HUBBLE_ARCH}.tar.gz.sha256sum
    sudo tar xzvfC hubble-linux-${HUBBLE_ARCH}.tar.gz /usr/local/bin
    rm hubble-linux-${HUBBLE_ARCH}.tar.gz{,.sha256sum}
    
    # Hubble API Access : localhost TCP 4245 Relay 를 통해 접근, observe 를 통해서 flow 쿼리 확인 가능!
    cilium hubble port-forward &
    
    # CLI 로 Hubble API 상태 확인
    hubble status
    
    # query the flow API and look for flows
    hubble observe
    # hubble observe --pod netpod
    # hubble observe --namespace galaxy --http-method POST --http-path /v1/request-landing
    # hubble observe --pod deathstar --protocol http
    # hubble observe --pod deathstar --verdict DROPPED

    • 자가 테스트 cilium connectivity test → Hubble UI 접속 후 cilium-test-Y 네임스페이스 선택 ⇒ 30분 소요, 여유 시간에 실행 해볼것!
    • 테스트 완료 후 테스트 환경 삭제 kubectl delete ns cilium-test-Y
노드 간 파드 통신 확인
  • eBPF Datapath - Link
  • 파드 생성 및 확인
    cat <<EOF | kubectl create -f -
    apiVersion: v1
    kind: Pod
    metadata:
      name: netpod
      labels:
        app: netpod
    spec:
      nodeName: k8s-s
      containers:
      - name: netshoot-pod
        image: nicolaka/netshoot
        command: ["tail"]
        args: ["-f", "/dev/null"]
      terminationGracePeriodSeconds: 0
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: webpod1
      labels:
        app: webpod
    spec:
      nodeName: k8s-w1
      containers:
      - name: container
        image: traefik/whoami
      terminationGracePeriodSeconds: 0
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: webpod2
      labels:
        app: webpod
    spec:
      nodeName: k8s-w2
      containers:
      - name: container
        image: traefik/whoami
      terminationGracePeriodSeconds: 0
    EOF
    
    ---------------------
    # 확인
    kubectl get pod -o wide
    c0 status --verbose | grep Allocated -A5
    c1 status --verbose | grep Allocated -A5
    c2 status --verbose | grep Allocated -A5
    
    kubectl get ciliumendpoints
    kubectl get ciliumendpoints -A
    c0 endpoint list
    c0 bpf endpoint list
    c0 map get cilium_lxc
    c0 ip list
  •  파드 변수 지정
    # 테스트 파드들 IP
    NETPODIP=$(kubectl get pods netpod -o jsonpath='{.status.podIP}')
    WEBPOD1IP=$(kubectl get pods webpod1 -o jsonpath='{.status.podIP}')
    WEBPOD2IP=$(kubectl get pods webpod2 -o jsonpath='{.status.podIP}')
    
    # 단축키(alias) 지정
    alias p0="kubectl exec -it netpod  -- "
    alias p1="kubectl exec -it webpod1 -- "
    alias p2="kubectl exec -it webpod2 -- "
  • 파드의 ARP 동작 확인 ← Hubble Web UI 모니터링
    # netpod 네트워크 정보 확인
    p0 ip -c -4 addr
    p0 route -n
    p0 ping -c 1 $WEBPOD1IP && p0 ping -c 1 $WEBPOD2IP
    p0 curl -s $WEBPOD1IP && p0 curl -s $WEBPOD2IP
    p0 curl -s $WEBPOD1IP:8080 ; p0 curl -s $WEBPOD2IP:8080
    p0 ping -c 1 8.8.8.8 && p0 curl -s wttr.in/seoul
    p0 ip -c neigh
    
    # hubble cli 확인
    hubble observe --pod netpod
    hubble observe --pod webpod1
    hubble observe --pod webpod2
    
    # BPF maps : 목적지 파드와 통신 시 어느곳으로 보내야 될지 확인할 수 있다
    c0 map get cilium_ipcache
    c0 map get cilium_ipcache | grep $WEBPOD1IP
    
    # netpod 의 LXC 변수 지정
    LXC=<k8s-s의 가장 나중에 lxc 이름>
    LXC=lxc335e04832afa
    
    # 파드와 veth pair 에 IP가 없다! proxy_arp 도 없다! 하지만 GW MAC 요청 시 lxc(veth)의 MAC 으로 응답이 온다! >> eBPF Magic!
    # Cilium hijacks ARP table of POD1, forces the next hop to be the peer end (host side) of the veth pair.
    ip -c addr show dev $LXC
     
    • Node’s eBPF programs
      # list of eBPF programs
      c0bpf net show
      c0bpf net show | grep $LXC
      lxc335e04832afa(12) tcx/ingress cil_from_container prog_id 1529 link_id 26 
      lxc335e04832afa(12) tcx/egress cil_to_container prog_id 1531 link_id 27 
      
      # Use bpftool prog show id to view additional information about a program, including a list of attached eBPF maps:
      c0bpf prog show id <출력된 prog id 입력>
      c0bpf prog show id 1529
      1531: sched_cls  name cil_to_container  tag 3f1e92871a2c4013  gpl
      	loaded_at 2024-10-20T07:47:27+0000  uid 0
      	xlated 1712B  jited 1015B  memlock 4096B  map_ids 66,239
      	btf_id 474
      
      c0bpf map list
      ...
      66: percpu_hash  name cilium_metrics  flags 0x1
      	key 8B  value 16B  max_entries 1024  memlock 19384B
      ...
      239: prog_array  name cilium_calls_00  flags 0x0
      	key 4B  value 4B  max_entries 50  memlock 720B
      	owner_prog_type sched_cls  owner jited
      ...


    • (심화 옵션) VXLAN 기반 Tunneling 통신 (한글) - 링크
    • (심화 옵션) 노드 내에서 파드와 veth 로 통신 시 bpf_redirect_peer , bpf_redirect_neigh 를 통한 통신 (한글) - 링크
4. 서비스 통신 확인
  • Socket-Based LoadBalancing 소개 (한글) - 링크
    • 그림 왼쪽(네트워크 기반 로드밸런싱) vs 오른쪽(소켓 기반 로드밸런싱)
    • Pod1 안에서 동작하는 앱이 connect() 시스템콜을 이용하여 소켓을 연결할 때 목적지 주소가 서비스 주소(10.10.8.55)이면 소켓의 목적지 주소를 바로 백엔드 주소(10.0.0.31)로 설정한다. 이후 앱에서 해당 소켓을 통해 보내는 모든 패킷의 목적지 주소는 이미 백엔드 주소(10.0.0.31)로 설정되어 있기 때문에 중간에 DNAT 변환 및 역변환 과정이 필요없어진다.
      • destination NAT translation happens at the syscall level, before the packet is even built by the kernel.
        출처 : https://velog.io/@haruband/K8SCilium-Socket-Based-LoadBalancing-기법
      • Socket operations : BPF socket operations programroot cgroup 에 연결되며 TCP event(ESTABLISHED) 에서 실행한다.
      • Socket send/recv : The socket send/recv hook 은 TCP socket 의 모든 송수신 작업에서 실행, hook 에서 검사/삭제/리다이렉션을 할 수 있다
        출처 : https://cilium.io/blog/2020/11/10/ebpf-future-of-networking/
      • connect() 와 sendto() 소켓 함수에 연결된 프로그램(connect4, sendmsg4)에서는 소켓의 목적지 주소를 백엔드 주소와 포트로 변환하고, cilium_lb4_backends 맵에 백엔드 주소와 포트를 등록해놓는다. 이후 recvmsg() 소켓 함수에 연결된 프로그램(recvmsg4)에서는 cilium_lb4_reverse_nat 맵을 이용해서 목적지 주소와 포트를 다시 서비스 주소와 포트로 변환함.
        출처 : https://k8s.networkop.co.uk/services/clusterip/dataplane/ebpf/
  • 서비스 생성 및 접속 확인 : 파드 내에서 바로 DNAT! Magic!
    • 서비스 생성
    cat <<EOF | kubectl create -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: svc
    spec:
      ports:
        - name: svc-webport
          port: 80
          targetPort: 80
      selector:
        app: webpod
      type: ClusterIP
    EOF
    
    • 서비스 접속 확인
    # 서비스 생성 확인
    kubectl get svc,ep svc
    
    # 노드에 iptables 더이상 KUBE-SVC rule 이 생성되지 않는다!
    iptables-save | grep KUBE-SVC
    iptables-save | grep CILIUM
    
    # 서비스IP를 변수에 지정
    SVCIP=$(kubectl get svc svc -o jsonpath='{.spec.clusterIP}')
    
    # Pod1 에서 Service(ClusterIP) 접속 트래픽 발생
    kubectl exec netpod -- curl -s $SVCIP
    kubectl exec netpod -- curl -s $SVCIP | grep Hostname
    
    # 지속적으로 접속 트래픽 발생
    SVCIP=$(kubectl get svc svc -o jsonpath='{.spec.clusterIP}')
    while true; do kubectl exec netpod -- curl -s $SVCIP | grep Hostname;echo "-----";sleep 1;done
    
    # 파드에서 SVC(ClusterIP) 접속 시 tcpdump 로 확인 >> 파드 내부 캡쳐인데, SVC(10.108.12.195)는 보이지 않고, DNAT 된 web-pod 의 IP가 확인! Magic!
    kubectl exec netpod -- tcpdump -enni any -q
    	08:54:55.454271 eth0  Out ifindex 14 92:1a:b9:94:94:37 172.16.0.162.44718 > 172.16.1.234.80: tcp 0
    	08:54:55.454798 eth0  In  ifindex 14 8a:0c:cc:a9:21:1a 172.16.1.234.80 > 172.16.0.162.44718: tcp 0
    	08:54:55.455030 eth0  Out ifindex 14 92:1a:b9:94:94:37 172.16.0.162.44718 > 172.16.1.234.80: tcp 77
    ...
    
    kubectl exec netpod -- sh -c "ngrep -tW byline -d eth0 '' 'tcp port 80'"
    T 2024/10/20 08:07:36.663329 172.16.0.132:59964 -> 172.16.1.53:80 [AP] #34
    GET / HTTP/1.1.
    Host: 10.10.124.15.
    User-Agent: curl/8.7.1.
    Accept: */*.
    
    
    # 서비스 정보 확인
    c0 service list
    ID   Frontend              Service Type   Backend
    16   10.108.12.195:80      ClusterIP      1 => 172.16.2.157:80
                                              2 => 172.16.1.234:80
    c0 bpf lb list
    SERVICE ADDRESS       BACKEND ADDRESS
    10.108.12.195:80      0.0.0.0:0 (16) [ClusterIP, non-routable]
                          172.16.1.234:80 (16)
                          172.16.2.157:80 (16)
    # BPF maps
    c0 map list --verbose
    c0 map list --verbose | grep lb
    c0 map get cilium_lb4_services_v2
    c0 map get cilium_lb4_backends_v3
    c0 map get cilium_lb4_reverse_nat
    c0 map get cilium_lb4_reverse_sk
    c0 map get cilium_lxc
    c0 map get cilium_ipcache
  • (old) BPF program 을 통한 분석 : bpf_sock.c - syscall 을 invoke 하고, 여기에 eBPF program 이 attach
    👉🏻👉🏻 curl 접속 시도 시, connect() syscall 을 invoke 하고, 여기에 eBPF program 이 attach 되어 있음
    __section("cgroup/connect4")
    int sock4_connect(struct bpf_sock_addr *ctx)
    {
    	if (sock_is_health_check(ctx))
    		return __sock4_health_fwd(ctx);
    
    	__sock4_xlate_fwd(ctx, ctx, false);
    	return SYS_PROCEED;
    }
    #ifdef ENABLE_NODEPORT
    
    👉🏻👉🏻 대부분의 처리를 __sock4_xlate_fwd 함수에서 진행된다
    /* BPF_HAVE_SOCKET_LOOKUP */
    	return false;
    }
    static __always_inline int __sock4_xlate_fwd(struct bpf_sock_addr *ctx,
    					     struct bpf_sock_addr *ctx_full,
    					     const bool udp_only)
    {
    	union lb4_affinity_client_id id;
    	const bool in_hostns = ctx_in_hostns(ctx_full, &id.client_cookie);
    	struct lb4_backend *backend;
    	struct lb4_service *svc;
    	struct lb4_key key = {
    		.address	= ctx->user_ip4,
    		.dport		= ctx_dst_port(ctx),
    	}, orig_key = key;
    	struct lb4_service *backend_slot;
    	bool backend_from_affinity = false;
    	__u32 backend_id = 0;
    ...
    
    👉🏻👉🏻 위 함수는 항상 SYS_PROCEED 를 리턴하여 커널로 돌려보냄
    __section("cgroup/connect4")
    int sock4_connect(struct bpf_sock_addr *ctx)
    {
    	if (sock_is_health_check(ctx))
    		return __sock4_health_fwd(ctx);
    
    	__sock4_xlate_fwd(ctx, ctx, false);
    	return SYS_PROCEED;
    }
    
    👉🏻👉🏻 마지막으로 eBPF 프로그램은 the socket-based NAT translation을 수행(Eariler 조회로부터 반환된 백엔드 파드의 IP 및 포트를 변환)
    Finally, the eBPF program does the socket-based NAT translation, i.e. re-writing of the destination IP and port with the values returned from the eariler lookup:
    	ctx->user_ip4 = backend->address;
    	ctx_set_port(ctx, backend->port);


    # Socket-Based LoadBalancing 관련 설정들 확인
    c0 status --verbose
    ...
    KubeProxyReplacement Details:
      Status:                 True
      Socket LB:              Enabled
      Socket LB Tracing:      Enabled
      Socket LB Coverage:     Full
      Devices:                ens5   192.168.10.10 fe80::57:abff:fee3:da8d (Direct Routing)
      Mode:                   SNAT
      Backend Selection:      Random
      Session Affinity:       Enabled
      Graceful Termination:   Enabled
      NAT46/64 Support:       Disabled
      XDP Acceleration:       Disabled
      Services:
      - ClusterIP:      Enabled
      - NodePort:       Enabled (Range: 30000-32767) 
      - LoadBalancer:   Enabled 
      - externalIPs:    Enabled 
      - HostPort:       Enabled
    
    # cgroup root 경로 확인
    tree /run/cilium/cgroupv2 -L 1
    tree /run/cilium/cgroupv2 -L 2
    cilium config view | grep cgroup
    cgroup-root                                    /run/cilium/cgroupv2
    
    # eBPF cgroup 확인 : Socket based LB 와 관련
    c0bpf cgroup tree
    CgroupPath
    ID       AttachType      AttachFlags     Name           
    /sys/fs/cgroup
    1081     cgroup_device   multi                                          
    1498     tcx_ingress                     cil_to_host                    
    1501     tcx_egress                      cil_from_host  
    
    # cilium 파드의 Init Containers 에서 cgroup 마운트!
    Init Containers:
      mount-cgroup:
        Container ID:  containerd://72e9d2ee9731e3536c893f9daaa7674809638e3d137f9eb0f46fe916c2aa2839
        Image:         quay.io/cilium/cilium:v1.16.3@sha256:62d2a09bbef840a46099ac4c69421c90f84f28d018d479749049011329aa7f28
        Image ID:      quay.io/cilium/cilium@sha256:62d2a09bbef840a46099ac4c69421c90f84f28d018d479749049011329aa7f28
        Port:          <none>
        Host Port:     <none>
        Command:
          sh
          -ec
          cp /usr/bin/cilium-mount /hostbin/cilium-mount;
          nsenter --cgroup=/hostproc/1/ns/cgroup --mount=/hostproc/1/ns/mnt "${BIN_PATH}/cilium-mount" $CGROUP_ROOT;
          rm /hostbin/cilium-mount
          
        State:          Terminated
          Reason:       Completed
          Exit Code:    0
          Started:      Sun, 20 Oct 2024 15:45:34 +0900
          Finished:     Sun, 20 Oct 2024 15:45:34 +0900
        Ready:          True
        Restart Count:  0
        Environment:
          CGROUP_ROOT:  /run/cilium/cgroupv2
          BIN_PATH:     /opt/cni/bin
        Mounts:
          /hostbin from cni-path (rw)
          /hostproc from hostproc (rw)
          /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-p6bcr (ro)
    
    # mount-cgroup 로그 확인
    kubetail -n kube-system -c mount-cgroup --since 12h
    ...
    [cilium-lnwcr] time="2024-10-20T15:45:52+09:00" level=info msg="Mounted cgroupv2 filesystem at /run/cilium/cgroupv2" subsys=cgroups 
    [cilium-jmr7d] time="2024-10-20T15:45:33+09:00" level=info msg="Mounted cgroupv2 filesystem at /run/cilium/cgroupv2" subsys=cgroups 
    ...


  • strace 시스템 콜 트레이싱 도구를 통해 파드 내에서 동작 확인*
    # syacall 호출 확인
    kubectl exec netpod -- strace -c curl -s $SVCIP
    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
     28.74    0.000971          12        79           mmap
     16.37    0.000553           9        56        32 open
     10.33    0.000349          29        12           fstat
      5.83    0.000197           6        31           rt_sigaction
      5.62    0.000190           7        27           munmap
      5.33    0.000180           6        27           close
      3.17    0.000107           3        27           read
      2.81    0.000095          15         6           poll
      2.69    0.000091           3        23           fcntl
      2.66    0.000090           2        31           lseek
      2.63    0.000089           8        10           readv
      2.34    0.000079           5        14           mprotect
      2.31    0.000078          78         1         1 connect
      2.25    0.000076           6        12           rt_sigprocmask
      1.30    0.000044          44         1           sendto
      1.12    0.000038           9         4           getsockname
      0.89    0.000030           7         4           setsockopt
      0.50    0.000017           3         5           getrandom
      0.50    0.000017          17         1           socket
      0.44    0.000015           5         3           brk
      0.44    0.000015          15         1           writev
      0.41    0.000014           4         3         3 ioctl
      0.38    0.000013          13         1           getsockopt
      0.27    0.000009           9         1           recvfrom
      0.27    0.000009           9         1           arch_prctl
      0.21    0.000007           7         1           pipe
      0.18    0.000006           6         1           set_tid_address
      0.00    0.000000           0         1           execve
      0.00    0.000000           0         1           getuid
      0.00    0.000000           0         1           getgid
      0.00    0.000000           0         2           geteuid
      0.00    0.000000           0         1           getegid
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.003379           8       389        36 total
    
    
    # 출력 내용을 편집기에서 확인(검색)
    kubectl exec netpod -- strace -s 65535 -f -tt curl -s $SVCIP
    ------------------------------------------------------------
    08:19:14.846995 connect(5, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("10.10.124.15")}, 16) = -1 EINPROGRESS (Operation in progress) # 소켓 연결 시도
    08:19:14.847653 getsockname(5, {sa_family=AF_INET, sin_port=htons(41312), sin_addr=inet_addr("172.16.0.132")}, [128 => 16]) = 0 # 소켓 주소 가져오기
    ...
    08:19:14.852497 getsockopt(5, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 # 소켓 연결 성공
    08:19:14.852940 getsockname(5, {sa_family=AF_INET, sin_port=htons(41312), sin_addr=inet_addr("172.16.0.132")}, [128 => 16]) = 0 # 소켓 주소 한번더 확인
    ...
    
    # 특정 이벤트 : -e
    kubectl exec netpod -- strace -e trace=connect curl -s $SVCIP
    kubectl exec netpod -- strace -e trace=getsockname curl -s $SVCIP

    • (심화) strace : 시스템 콜 트레이싱 도구(디버거) , 시스템 콜 상태(커널 모드로 실행 중이거나 대기 상태)
      # 중단점 트레이싱 : -ttt(첫 열에 기준시간으로부터 흐른 시간 표시) , -T(마지막 필드 time에 시스템 콜에 걸린 시간을 표시) , -p PID(프로세스 ID가 PID 인 프로세스를 트레이싱)
      strace -ttt -T -p 1884
      
      # 시스템 콜별 통계
      strace -c -p 1884
      
      # 그냥 사용해보기
      strace ls
      
      # 옵션 사용해보기 : -s(출력 string 결과 최댓값 지정), -tt(첫 열에 기준시간으로부터 흐른 시간 표시, ms단위), -f(멀티 스레드,멀티 프로레스의 자식 프로세스의 시스템 콜 추적)
      strace -s 65535 -f -T -tt -o <파일명> -p <pid>
      
      # hostname 명령 분석하기 : -o <파일명> 출력 결과를 파일로 떨구기
      strace -s 65535 -f -T -tt -o hostname_f_trace hostname -f
      
      # 특정 이벤트 : -e
      strace -e trace=connect curl ipinfo.io
  • (old 심화 옵션) 소켓 기반 로드밸런싱 사용 시 Istio(EnvoyProxy)와 같은 사이드카 우회 문제 - 링크
    • 해결 방안 : 파드 네임스페이스에서는 소켓 기반 로드밸런싱을 사용하지 않는다 → 호스트 네임스페이스만 사용하게 설정!
      • 단, HTTP 경우 Envoy 의 HTTP 필터가 HTTP 패킷의 host 헤더로 필터링하여 패킷의 목적지 주소가 서비스 IP에서 백엔드 IP로 변환이 잘된다
      • 하지만, HTTP가 아닌 TCP 서비스(예. Telnet 등)은 위 환경에서 문제가 발생한다.
    # 설정
    VERSION=1.11.2
    helm upgrade cilium cilium/cilium --version $VERSION --namespace kube-system --reuse-values --set hostServices.hostNamespaceOnly=true
    kubectl -n kube-system rollout restart ds/cilium
    
    cilium config view | grep bpf-lb-sock-hostns-only
    bpf-lb-sock-hostns-only                        **true**
    
    # 확인
    # 지속적으로 접속 트래픽 발생
    while true; do kubectl exec netpod -- curl -s $SVCIP | grep Hostname;echo "-----";sleep 1;done
    
    # 파드에서 SVC(ClusterIP) 접속 시 tcpdump 로 확인 >> **파드 내부 캡쳐**인데, SVC(10.108.12.195) **트래픽이 보인다**!
    **kubectl exec netpod -- tcpdump -enni any -q**
    	21:51:45.615174 eth0  Out ifindex 17 fe:9b:8a:a8:6e:83 172.16.0.245.41880 > **10.98.168.249**.80: tcp 0
    	21:51:45.615613 eth0  In  ifindex 17 7a:f4:08:6b:50:e5 10.98.168.249.80 > 172.16.0.245.41880: tcp 0
    ...
    
  • (old) Service(NodePort) Cilium eBPF 분석 - 링크 / haruband(한글) - 링크
  • 삭제 kubectl delete pod --all && kubectl delete svc svc
  • [도전과제1] 공식문서 Kubernetes Without kube-proxy 에 다양한 가속? 동작들을 테스트 후 정리 - Docs

 

5. Running Prometheus & Grafana
# 배포
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.16.3/examples/kubernetes/addons/prometheus/monitoring-example.yaml
kubectl get all -n cilium-monitoring

# 파드와 서비스 확인
kubectl get pod,svc,ep -o wide -n cilium-monitoring

# NodePort 설정
kubectl patch svc grafana -n cilium-monitoring -p '{"spec": {"type": "NodePort"}}'
kubectl patch svc prometheus -n cilium-monitoring -p '{"spec": {"type": "NodePort"}}'

# Grafana 웹 접속
GPT=$(kubectl get svc -n cilium-monitoring grafana -o jsonpath={.spec.ports[0].nodePort})
echo -e "Grafana URL = http://$(curl -s ipinfo.io/ip):$GPT"

# Prometheus 웹 접속 정보 확인
PPT=$(kubectl get svc -n cilium-monitoring prometheus -o jsonpath={.spec.ports[0].nodePort})
echo -e "Prometheus URL = http://$(curl -s ipinfo.io/ip):$PPT"

 

  • grafana , prometheus NodePort 로 웹 접속 후 확인