Cillium의 장점을 몸소 느껴보고 eBPF 기반 네트워킹의 장점과 동작원리를 알아봅니다.
Iptables의 단점을 확인하고, eBPF의 장점을 비교해봅니다.
2. BPF 란?
리눅스 네트워크 스택은 복잡하고, 변경에 대한 시간이 많이 걸리고 레이어를 건너뛰기 어렵다는 단점이 존재 -> 이를 위해서 BPF 가 극복하기 위한 수단으로 등장함
BPF (Berkley Packet Filter)는 커널 수준의 패킷 캡처 및 필터링을 위해 만들어 졌으며, 다양한 훅을 통해 네트워크 스택에 쉽게 접근이 가능합니다.
2.b eBPF란?
기존의 BPF의 확장버전으로, 커널의 거의 모든 부분을 관찰 할 수 있습니다.
eBPF의 특정 영역에서 다음과 같은 영역들에서 활용할 수 있습니다.
Networking: 네트워크 트래픽의 필터링 혹은 라우팅을 할 수 있습니다.
Observabililty: eBPF가 데이터를 수집하고, 분석할 수 있게 합니다.
Tracing: 커널과 사용자 공간의 프로세스의 Stack Traces를 기로가할 수 있습니다.
Security: 커널 시스템 호출을 가로채서 모니터링 할 수 있습니다. 보안 위협을 방지할 수 있습니다.
2.c Iptables의 한계점
k8s의 kube-proxy는 Iptables Rules를 통해 서비스와 로드 밸런싱을 구현한다.
대부분의 CNI 플러그인 - 네트워크 정책을 위해 iptables를 사용
업데이트시 모든 규칙을 다시 생성 및 업데이트
규칙을 사용하는데에서도 모든 규칙을 확인하게 됩니다.
새 ip에 대해서 사용할 때, 규칙을 추가해야합니다.
iptable의 기하급수적 증가를 경험할 수 밖에 없습니다.
이에 따라, eBPF가 필연적으로 등장하게 됩니다.
2.d eBPF 구동 원리
eBPF 프로그램들의 상태값을 저장하는 Maps 를 가지고, 사용자 공간의 프로그램을 커널의 동적으로 로드하고 사용합니다.
3. Cillium CNI 란?
Cillium CNI는 eBPF를 활용해서 k8s 환경에서 많은 레이어를 통한 통신보다는 하나의 계층만 거치면서 통신을 수행하게 됩니다.
기존의 iptables 기반의 동작에 대해 성능을 유의미 하게 향상시킵니다.
네트워크 정책 관리 및 세부적인 정책을 정의할 수 있습니다.
호스트간 라우팅 + pod에서의 라우팅을 동작할 때 생기는 많은 iptables에 대한 오버헤드없이 통신을 수행하면서 성능에 이점이 생깁니다.\
3.a Cillium 아키텍처
Cilium Agent : 데몬셋으로 실행, K8S API 설정으로 부터 '네트워크 설정, 네트워크 정책, 서비스 부하분산, 모니터링' 등을 수행하며, eBPF 프로그램을 관리한다.
Cilium Client (CLI) : Cilium 커멘드툴, eBPF maps 에 직접 접속하여 상태를 확인할 수 있다.
Cilium Operator : K8S 클러스터에 대한 한 번씩 처리해야 하는 작업을 관리.
4. Cillium 배포
// Cloud stack 배포 yaml 파일
# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/kans/kans-8w.yaml
// 실습환경 배포 확인
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text
// KUBE PROXY 없는것을 확인
// kc get pod -A
#
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
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
Iptables에 entry가 거의 없는것을 확인할 수 있습니다.
Cillium 설치를 확인합니다.
# 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
# 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
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
Cillium을 설치한 이후에 CLI로 Daemon들을 확인합니다.
5. Cillium 기본 정보
# 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 파드 확인
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