Search

Cilium 실습

Tags
k8s
cni
cilium
Created
2024/10/22 20:48
Created time
2024/10/22 11:48
category
kubernetes

개요

Cilium 이론에서 학습한 개념들을 직접 실습

환경 준비

조금 많이 과금 될 수 있으므로 금액에 유의하여 배포하며, Cilium 이용 예정임에 따라 eBPF 때문에 kube-proxy를 스킵하도록 템플릿 파일이 구성되어 있음
구성 환경은 아래와 같으며, IAM 사용자 설정AWS CLI 설정 그리고 CloudFormation 관련 명령어를 참고
VPC 1개 (퍼블릭 서브넷 2개)
Ubuntu 22.04 LTS, t3.xlarge 3대
Ubuntu 22.04 LTS, t3.small 1대

클러스터 생성

# CloudFormation 템플릿 파일 다운로드 # https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/kans/kans-8w.yaml curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/kans/kans-8w.yaml # EC2 인스턴스 생성 aws cloudformation deploy --template-file kans-8w.yaml --stack-name mylab --parameter-overrides KeyName=jseo.d --region ap-northeast-2 # 생성된 EC2 인스턴스 IP 주소 확인 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 # CloudFormation 스택 상태 확인 while true; do date AWS_PAGER="" aws cloudformation list-stacks \ --stack-status-filter CREATE_IN_PROGRESS CREATE_COMPLETE CREATE_FAILED DELETE_IN_PROGRESS DELETE_FAILED \ --query "StackSummaries[*].{StackName:StackName, StackStatus:StackStatus}" \ --output table sleep 1 done
Shell
복사

클러스터 확인

kc cluster-info kc get no -o wide kc get po -A
Shell
복사

Cilium 설치

# Helm Repo 추가 및 업데이트 helm repo add cilium https://helm.cilium.io/ helm repo update # 설치 # https://docs.cilium.io/en/stable/helm-reference/ 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
Shell
복사
Cilium은 정말 많은 옵션들이 존재하고, 이들의 값에 따라 동작이 매우 크게 바뀌므로 제대로 적용하려면 많은 실험들이 필요
위 설치에 사용된 옵션 풀이

iptables 및 CT 확인

ip -c addr iptables -t nat -S iptables -t filter -S iptables -t raw -S iptables -t mangle -S conntrack -L # iptables -t raw -S | grep notrack # 위 명령어로 확인 시 iptables의 CT가 활성화된 상태라면 아래 내용을 적용 # iptables의 Connection Tracking이 아니라 eBPF의 Connection Tracking을 사용하므로 비활성화 # # https://docs.cilium.io/en/stable/operations/performance/tuning/#bypass-iptables-connection-tracking helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values --set installNoConntrackIptablesRules=true
Shell
복사

k8s 리소스 확인

# Cilium을 위한 Pod와 Service 확인 kubectl get no,po,svc -A -o wide # Cilium 관련 리소스 확인 kubectl get crd # cilium_host 인터페이스의 IP인 CILIUMINTERNALIP를 확인 kubectl get ciliumnodes # Cilium 엔드포인트 확인 kubectl get ciliumendpoints -A # Cilium 설정 확인 kubectl get cm -n kube-system cilium-config -o json | jq
Shell
복사

XDP 확인

# Native XDP 지원 NIC 확인 # https://docs.cilium.io/en/stable/bpf/progtypes/#xdp-drivers # driver: ena이고 version: 6.8.0-1015-aws이므로, 위 링크에 따르면 Native XDP를 지원 ethtool -i ens5
Shell
복사

Cilium CLI 설치

# Cilium CLI 설치 # https://docs.cilium.io/en/stable/installation/k8s-install-helm/#validate-the-installation 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}
Shell
복사

Cilium CLI 확인

# Cilium CLI를 이용하여 Cilium 상태와 설정 확인 cilium status --wait cilium config view
Bash
복사

Cilium 정보 확인

변수 지정

아래 실습을 수행하면서 배포되는 Cilium Pod들의 삭제와 생성이 많아서 초기화 되므로 미리 복사를 잘 해두어 언제든지 붙여넣기 할 수 있도록 준비
# Cilium Pod를 변수에 지정 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}') # Cilium 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" # eBPF Alias 지정 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"
Shell
복사

자주 이용하는 명령어

# 도움말 c0 help # Cilium Pod의 Cilium 상태 확인 c0 status --verbose # 노드에서 Pod에 할당된 IP 확인 c0 status --verbose | grep Allocated -A5 # 노드 리스트 c0 node list # Cilium 엔드포인트 확인 c0 endpoint list c0 bpf endpoint list c0 map get cilium_lxc c0 ip list # IP CIDR 관리를 위한 IP Cache c0 bpf ipcache list # Service 및 NAT List 확인 c0 service list c0 bpf lb list c0 bpf lb list --revnat c0 bpf nat list # NAT의 모든 엔트리 플러시 c0 bpf nat flush # Connection Tracking 테이블 목록 c0 bpf ct list global # BPF 파일 시스템 확인 c0 bpf fs show # BPF Maps 확인 c0 map list c0 map list --verbose # BPF Maps의 Policy들을 확인 c0 bpf policy get --all c0 bpf policy get --all -n # BPF 데이터 경로 트래픽 지표 c0 bpf metrics list # Cilium 모니터 c0 monitor -v c0 monitor -v --type l7 # 지표 확인 c0 metrics list # 엔드포인트 ID 확인 c0 identity list --endpoints # 엔드포인트 설정 확인 및 변경 c0 endpoint config <Endpoint ID> # 엔드포인트 상세 정보 c0 endpoint get <Endpoint ID> # 엔드포인트 로그 확인 c0 endpoint log <Endpoint ID> # 컴파일 된 BPF 템플릿들을 관리 c0 bpf sha list # 데이터 경로의 SHA 헤더를 확인 c0 bpf sha get <Datapath SHA>
Shell
복사

Hubble UICLI 접근 및 확인

# Hubble UI Service를 NodePort로 변경 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
Shell
복사
# Hubble CLI 설치 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}
Shell
복사
# Hubble API 접근 # 로컬 호스트의 TCP 4245 Relay를 통해 접근 cilium hubble port-forward & # Hubble API 상태 확인 hubble status # Hubble API로 쿼리 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
Shell
복사

통신 확인

노드 간의 Pod 통신 확인

VXLAN 기반 Tunneling 통신은 여기를 참고
veth 통신 시 bpf_redirect_peer, bpf_redirect_neigh를 이용한 통신은 여기를 참고

리소스 생성

# Pod 생성 cat << EOT | 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 EOT
Shell
복사
# 생성된 Pod를 확인 kubectl get pod -o wide # Cilium 상태 확인 c0 status --verbose | grep Allocated -A5 c1 status --verbose | grep Allocated -A5 c2 status --verbose | grep Allocated -A5 # Cilium 엔드포인트 조회하여 Cilium 상태에서 본 주소와 Pod의 주소 일치 확인 kubectl get ciliumendpoints
Shell
복사

변수 지정

# 테스트 Pod 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}') # Pod에서 명령어 실행을 위해 Alias 지정 alias p0="kubectl exec -it netpod -- " alias p1="kubectl exec -it webpod1 -- " alias p2="kubectl exec -it webpod2 -- "
Shell
복사

통신 원리 확인

# netpod 동작 확인 # ping, curl, 외부 통신 가능 확인 p0 ping -c 1 $WEBPOD1IP && p0 ping -c 1 $WEBPOD2IP p0 curl -s $WEBPOD1IP && p0 curl -s $WEBPOD2IP p0 ping -c 1 8.8.8.8 && p0 curl -s wttr.in/seoul
Shell
복사
# Cilium으로 확인한 상태와 netpod 정보를 비교 p0 ip -c neigh p0 route -n p0 ip -c -4 addr
Shell
복사
# 컨트롤 플레인의 BPF Maps를 확인 # 목적지와 통신 시 Pod가 어느 곳으로 향해야 하는지 확인 가능 c0 map get cilium_ipcache # 예를 들어 webpod1로 보낼 때는 아래 명령어를 이용 # webpod1이 위치한 k8s 노드 주소를 확인 가능 c0 map get cilium_ipcache | grep $WEBPOD1IP
Shell
복사
# 컨트롤 플레인 lxc 인터페이스 확인 c0bpf net show # 변수 지정 LXC=$(c0bpf net show | grep lxc | tail -n 1 | awk '{print $1}' | awk -F'(' {'print $1}') echo $LXC # Pod와 veth pari에 IP가 없고, proxy_arp도 없는 것을 확인 가능 # 그럼에도 불구하고 eBPF 덕에 Gateway MAC으로 요청 시 lxc의 MAC으로 응답 받음 # Cilium이 Pod의 ARP 테이블을 Hijakcing하여 veth pair의 호스트 쪽 Peer로 Next Hop을 지정 # veth에 대해선 아래 링크를 통해 컨테이너를 만들어보며 참고 # https://www.jseo.cc/b711e6ed-795b-4e77-8217-2b603fb9771f ip -c addr show dev $LXC
Shell
복사

노드의 eBPF 프로그램 확인

# lxc 인터페이스가 이용하는 프로그램 ID를 확인 c0bpf net show | grep $LXC # bpftool의 prog라는 명령어를 통해 제공된 프로그램 ID의 eBPF Maps 등의 상세 정보를 확인 가능 c0bpf prog show id <prod-id> # eBPF Maps를 확인 c0bpf map list | grep "<maps-id>:"
Bash
복사

내부 동작

1.
이더넷 프로토콜이 ARP 일 경우(ETH_P_ARP)에는 CILIUM_CALL_ARP tail을 호출
2.
노드의 IPV4_GATEWAY 의 NODE_MAC 주소로 arp_respond을 보냄
3.
arp.h 에서 arp 응답을 준비하고 리다이렉션하여 수신 인터페이스를 통해 전송
4.
ARP 응답 시 출발지의 MAC이나 패딩 등의 일부 필드는 수정
BPF 프로그램에 사용되는 bpf_lxc.c / bpf_host.c / arp.h 소스 코드를 참고
bpf_lxc.c의 주요 동작은 아래와 같음
1.
네트워크 패킷 검사(SKB, skb 구조체 할당) 후 L3 프로토콜인지 확인
2.
IPv4 L3 일 경우 tail_handle_ipv4() 호출
3.
tail_handle_ipv4()는 내부적으로 handle_ipv4_from_lxc() 호출하여 아래 기능을 수행
Service 부하 분산
CT 생성 혹은 갱신
dNAT 처리
Egress 네트워크 정책 확인
Direct Routing 모드일 때 커널 스택으로 패킷을 전달 / Tunneling 모드일 때 캡슐화
4.
IP Cache eBPF Maps를 사용하여 상대 엔드포인트에 대한 정보를 조회

Service로 통신 확인

노드 간의 Pod 통신 확인에서 사용했던 변수 지정을 그대로 이용

리소스 생성

# Service 생성 확인 cat << EOT | kubectl create -f - apiVersion: v1 kind: Service metadata: name: svc spec: ports: - name: svc-webport port: 80 targetPort: 80 selector: app: webpod type: ClusterIP EOT #
Shell
복사

iptables 조회

# 노드에 있는 iptables에 더 이상 KUBE-SVC 관련 규칙이 생성되지 않음을 확인 iptables-save | grep KUBE-SVC # 대신 CILIUM 관련 규칙들을 이용함을 알 수 있음 iptables-save | grep CILIUM
Shell
복사

통신 원리 확인

netpod에서 strace 이용하여 시스템 콜 호출을 추적 및 디버깅 가능하고, 특정 이벤트에 대해서 필터링도 가능
예시
# 좌측) 컨트롤 플레인 # Service IP를 변수에 지정 SVCIP=$(kubectl get svc svc -o jsonpath='{.spec.clusterIP}') # netpod에서 Service 접속 while true; do kubectl exec netpod -- curl -s $SVCIP | grep Hostname;echo "-----";sleep 1;done
Bash
복사
# 우측) 동일하게 변수 지정한컨트롤 플레인 # tcpdump 수행하여 netpod를 캡쳐 시 Service의 IP 주소는 보이지 않고, dNAT된 webpod의 IP 주소 확인 kubectl exec netpod -- tcpdump -enni any -q
Shell
복사
# 우측) 동일하게 변수 지정한컨트롤 플레인 # 위에서 수행했던 통신에 대해서 tcpdump로 내용 확인 kubectl exec netpod -- tcpdump -enni any -q
Shell
복사

내부 동작

1.
curl 접속 시도 시, connect() 시스템 콜을 호출하고, 여기에 eBPF 프로그램이 붙어서 동작
2.
대부분의 처리를 __sock4_xlate_fwd 함수에서 진행
3.
sock4_connect() 함수는 항상 SYS_PROCEED 를 리턴하여 커널로 반환
4.
eBPF 프로그램은 소켓 기반 NAT를 수행 (먼저 조회되었던 백엔드 IP 주소와 포트를 변환)
BPF 프로그램에 사용되는 bpf_sock.c 소스 코드를 참고

소켓 기반 LB 확인

소켓 기반 LB 이용 시 Istio와 같은 SideCar 우회 문제 발생
# 소켓 기반 LB 관련 설정 확인 c0 status --verbose | grep "Socket LB" # cgroup root 경로 확인 tree /run/cilium/cgroupv2 -L 1 tree /run/cilium/cgroupv2 -L 2 cilium config view | grep cgroup # eBPF cgroup 확인 c0bpf cgroup tree
Shell
복사
# 임의의 Cilium Pod 이름을 확인 kubectl get po -A | grep cilium # Cilium Pod의 Init 컨테이너에서 cgroup 마운트 됨을 확인 kubectl describe -n kube-system po cilium-<random-id> | grep -i cgroup # mount-cgroup에 대한 로그 확인 kubetail -n kube-system -c mount-cgroup --since 12h
Shell
복사

기타

# Service 정보 확인 c0 service list # BPF LB 목록 확인 c0 bpf lb list # LB 관련 BPF Maps 조회 c0 map list --verbose c0 map list --verbose | grep lb # 각 인터페이스에서 사용하는 Maps 목록 확인 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
Shell
복사

리소스 삭제

kubectl delete po --all && kubectl delete svc svc
Shell
복사
# Prometheus Stack을 배포 # https://raw.githubusercontent.com/cilium/cilium/1.16.3/examples/kubernetes/addons/prometheus/monitoring-example.yaml kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.16.3/examples/kubernetes/addons/prometheus/monitoring-example.yaml # Cilium Monitoring 네임스페이스의 리소스를 확인 kubectl get all -n cilium-monitoring # Pod 및 Service 확인 kubectl get po,svc,ep -o wide -n cilium-monitoring
Shell
복사
# Prometheus와 Grafana 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"
Shell
복사
# LB 모드를 DSR로 설정 helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values --set loadBalancer.mode=dsr # Cilium DaemonSet을 재시작 # 재시작 후엔 반드시 아래 링크에서 수행되는 변수 지정을 다시 수행 # https://www.jseo.cc/12753dc7-65b0-8076-8322-c9604ca7d3d0#12753dc7-65b0-8017-8789-e5de0076de2a kubectl -n kube-system rollout restart ds/cilium
Shell
복사
# DSR 모드 확인 cilium config view | grep dsr c0 status --verbose | grep 'KubeProxyReplacement Details:' -A7
Shell
복사

리소스 생성

# Pod 및 Service 생성 cat << EOT | 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: Service metadata: name: svc1 spec: ports: - name: svc1-webport port: 80 targetPort: 80 selector: app: webpod type: NodePort EOT
Shell
복사
# Pod 및 Service 정보 kubectl get po -o wide kubectl get svc svc1 # Maps 목록 확인 c0 map list --verbose c1 map list --verbose
Shell
복사

접속 조회

# 좌측) Service NodePort 변수 지정 SVCNPORT=$(kubectl get svc svc1 -o jsonpath='{.spec.ports[0].nodePort}') # 좌측) 접속 트래픽 생성 while true; do curl -s k8s-m:$SVCNPORT | grep Hostname;echo "-----";sleep 1;done # 우측) IPv4Option을 맨 뒤에서부터 읽음 c1 monitor -vv
Shell
복사

리소스 삭제

# 리소스 삭제 kubectl delete svc svc1 && kubectl delete po webpod1 netpod
Shell
복사
Cilium의 네트워크 정책에 대해선 엔드포인트 정책에 따라 패킷을 전달하거나 차단하고, 전달 시엔 Service 혹은 L7을 대상으로 할 수 있음
이와 같은 네트워크 정책을 아래와 같은 구조의 예시에서 확인
# 리소스 생성 # https://raw.githubusercontent.com/cilium/cilium/1.16.3/examples/minikube/http-sw-app.yaml kubectl create -f https://raw.githubusercontent.com/cilium/cilium/1.16.3/examples/minikube/http-sw-app.yaml # Pod 레이블 확인 kubectl get pod --show-labels # 데스스타 Service로 접속하여 연결 확인 # 아무런 정책 적용이 되어 있지 않으므로 모두 정상 접속 kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing # Hubble UI 확인 hubble observe
Shell
복사
Cilium에서는 엔드포인트 IP 대신 Pod의 레이블을 이용하여 보안 정책을 적용
IP/Port 필터링을 L3/L4 정책이라하고, Cilium은 Stateful CT를 지원하므로 응답 트래픽은 자동 허용
# L3 & L4 정책 생성 cat << EOT | kubectl apply -f - apiVersion: "cilium.io/v2" kind: CiliumNetworkPolicy metadata: name: "rule1" spec: description: "L3-L4 policy to restrict deathstar access to empire ships only" endpointSelector: matchLabels: org: empire class: deathstar ingress: - fromEndpoints: - matchLabels: org: empire toPorts: - ports: - port: "80" protocol: TCP EOT
Shell
복사
# 정책 확인 kubectl get cnp # 접속 시도 # org=empire 레이블이 붙은 Pod만 허용 하는 정책이므로 org=alliance는 실패 kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing kubectl exec xwing -- curl -s --connect-timeout 3 -XPOST deathstar.default.svc.cluster.local/v1/request-landing
Shell
복사
HTTP L7 필터링을 적용하여 [PUT] /v1/exhaust-port 요청을 차단
# L7 정책 생성 cat << EOT | kubectl apply -f - apiVersion: "cilium.io/v2" kind: CiliumNetworkPolicy metadata: name: "rule1" spec: description: "L7 policy to restrict access to specific HTTP call" endpointSelector: matchLabels: org: empire class: deathstar ingress: - fromEndpoints: - matchLabels: org: empire toPorts: - ports: - port: "80" protocol: TCP rules: http: - method: "POST" path: "/v1/request-landing" EOT
Shell
복사
# 정책 확인 kubectl get cnp # 접속 시도 # [PUT] /v1/exhaust-port 요청을 차단하므로 실패되는 것을 볼 수 있음 kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing kubectl exec tiefighter -- curl -s --connect-timeout 3 -XPUT deathstar.default.svc.cluster.local/v1/exhaust-port
Shell
복사

리소스 삭제

kubectl delete -f https://raw.githubusercontent.com/cilium/cilium/1.16.3/examples/minikube/http-sw-app.yaml kubectl delete cnp rule1
Shell
복사

인터페이스 확인 및 설정

# 인터페이스 확인 tc qdisc show dev ens5
Shell
복사
# Bandwidth Manager 이용을 설정 helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values --set bandwidthManager.enabled=true
Shell
복사
# Cilium 설정에서 적용됨을 확인 cilium config view | grep bandwidth # Egress Bandwidth 제한이 동작하는 인터페이스를 확인 c0 status | grep BandwidthManager # 인터페이스 재확인 시 옵션이 상당히 추가 tc qdisc show dev ens5
Shell
복사

동작 확인

# 테스트를 위한 서버와 클라이언트 Pod를 생성 cat << EOT | kubectl apply -f - --- apiVersion: v1 kind: Pod metadata: annotations: # Limits egress bandwidth to 10Mbit/s. kubernetes.io/egress-bandwidth: "10M" labels: # This pod will act as server. app.kubernetes.io/name: netperf-server name: netperf-server spec: containers: - name: netperf image: cilium/netperf ports: - containerPort: 12865 --- apiVersion: v1 kind: Pod metadata: # This Pod will act as client. name: netperf-client spec: affinity: # Prevents the client from being scheduled to the # same node as the server. podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app.kubernetes.io/name operator: In values: - netperf-server topologyKey: kubernetes.io/hostname containers: - name: netperf args: - sleep - infinity image: cilium/netperf EOT
Shell
복사
# Egress Bandwidth 제한 정보 확인 kubectl describe pod netperf-server | grep Annotations: # Egress Bandwidth 제한이 설정된 Pod가 위치한 Cilium Pod에서 제한 정보 확인 시 동일 c1 bpf bandwidth list c2 bpf bandwidth list
Shell
복사
# netperf-server Pod의 Egress Traffic이 10Mbps로 설정됨을 확인 NETPERF_SERVER_IP=$(kubectl get pod netperf-server -o jsonpath='{.status.podIP}') kubectl exec netperf-client -- netperf -t TCP_MAERTS -H "${NETPERF_SERVER_IP}"
Shell
복사
# Bandwidth를 5Mbps로 설정 후 확인 kubectl get pod netperf-server -o json | sed -e 's|10M|5M|g' | kubectl apply -f - kubectl exec netperf-client -- netperf -t TCP_MAERTS -H "${NETPERF_SERVER_IP}"
Shell
복사
# Bandwidth를 20Mbps로 설정 후 확인 kubectl get pod netperf-server -o json | sed -e 's|5M|20M|g' | kubectl apply -f - kubectl exec netperf-client -- netperf -t TCP_MAERTS -H "${NETPERF_SERVER_IP}"
Shell
복사

리소스 삭제

kubectl delete po netperf-client netperf-server
Shell
복사
# L2 Announcements와 L2 Aware LB를 설정 helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \ --set l2announcements.enabled=true --set externalIPs.enabled=true \ --set l2announcements.leaseDuration=3s --set l2announcements.leaseRenewDeadline=1s --set l2announcements.leaseRetryPeriod=200ms # 설정됨을 확인 c0 config --all | grep L2
Shell
복사
# L2 Announcements Policy 생성 cat << EOT | kubectl apply -f - apiVersion: "cilium.io/v2alpha1" kind: CiliumL2AnnouncementPolicy metadata: name: policy1 spec: serviceSelector: matchLabels: color: blue nodeSelector: matchExpressions: - key: node-role.kubernetes.io/control-plane operator: DoesNotExist interfaces: - ^ens[0-9]+ externalIPs: true loadBalancerIPs: true EOT # 생성됨을 확인 kubectl get ciliuml2announcementpolicy
Shell
복사
# Cilium LB IP Pool 생성 cat << EOT | kubectl apply -f - apiVersion: "cilium.io/v2alpha1" kind: CiliumLoadBalancerIPPool metadata: name: "cilium-pool" spec: allowFirstLastIPs: "No" blocks: - cidr: "10.10.200.0/29" EOT # Cilium LB IP Pool 조회 kubectl get CiliumLoadBalancerIPPool
Shell
복사

BGP 설정

# BGP 설정 cat << EOT | kubectl create -f - apiVersion: v1 kind: ConfigMap metadata: name: bgp-config namespace: kube-system data: config.yaml: | peers: - peer-address: 192.168.10.254 peer-asn: 64513 my-asn: 64512 address-pools: - name: default protocol: bgp avoid-buggy-ips: true addresses: - 172.20.1.0/24 EOT
Shell
복사
# 버전 변수 지정 VERSION=1.16.3 # BGP 활성화 helm upgrade cilium cilium/cilium --version $VERSION --namespace kube-system --reuse-values --set bgp.enabled=true --set bgp.announce.loadbalancerIP=true # 배포 kubectl -n kube-system rollout restart ds/cilium
Shell
복사
# BGP 설정됨을 확인 cilium config view | grep bgp
Shell
복사

리소스 생성

# Pod 및 Service 생성 cat << EOT | kubectl create -f - apiVersion: v1 kind: Service metadata: name: test-lb spec: type: LoadBalancer ports: - port: 80 targetPort: 80 protocol: TCP name: http selector: svc: test-lb --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: selector: matchLabels: svc: test-lb template: metadata: labels: svc: test-lb spec: containers: - name: web image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 readinessProbe: httpGet: path: / port: 80 EOT
Shell
복사

접속 조회

# Service 확인 kubectl get svc,ep test-lb # externalTrafficPolicy: Local 설정 kubectl patch svc test-lb -p '{"spec":{"externalTrafficPolicy": "Local"}}' # Service LB IP로 접속 확인 curl -s 172.16.2.115 | grep -o "<title>.*</title>"
Shell
복사

설정 원복

kubectl delete svc test-lb && kubectl delete deploy nginx helm upgrade cilium cilium/cilium --version $VERSION --namespace kube-system --reuse-values --set bgp.enabled=false --set bgp.announce.loadbalancerIP=false kubectl -n kube-system rollout restart ds/cilium
Shell
복사

설정 및 확인

# L7 Proxy 확인 cilium config view | grep l7
Shell
복사
# 버전 변수 지정 VERSION=1.16.3 # L7 Proxy를 비활성화하고, 암호화를 활성화 helm upgrade cilium cilium/cilium --version $VERSION --namespace kube-system --reuse-values --set l7Proxy=false --set encryption.enabled=true --set encryption.type=wireguard # 배포 kubectl -n kube-system rollout restart ds/cilium
Shell
복사
# 모드 변경 확인 cilium config view | egrep 'l7|wireguard' # 퍼블릭 키 확인 kubectl get cn -o yaml | grep annotations -A1 # WireGuard 확인 wg version wg show wg show all public-key wg show all private-key wg show all preshared-keys wg show all endpoints # WireGuard NIC 확인 ip -d -c addr show cilium_wg0 # Routing 규칙 추가 확인 ip rule show ip route show table <lookup>
Shell
복사

리소스 생성

# 리소스 생성 cat << EOT | kubectl create -f - apiVersion: v1 kind: Pod metadata: name: netpod1 labels: app: netpod spec: nodeName: k8s-w1 containers: - name: netshoot-pod image: nicolaka/netshoot command: ["tail"] args: ["-f", "/dev/null"] terminationGracePeriodSeconds: 0 --- apiVersion: v1 kind: Pod metadata: name: netpod2 labels: app: netpod spec: nodeName: k8s-w2 containers: - name: netshoot-pod image: nicolaka/netshoot command: ["tail"] args: ["-f", "/dev/null"] terminationGracePeriodSeconds: 0 EOT
Shell
복사

접속 조회

# 컨트롤 플레인 # Pod IP를 변수에 지정 POD1IP=$(kubectl get pods netpod1 -o jsonpath='{.status.podIP}') POD2IP=$(kubectl get pods netpod2 -o jsonpath='{.status.podIP}')
Shell
복사
# 워커 노드 # 패킷 덤프를 위한 설정 추가 cat /proc/sys/net/ipv4/conf/cilium_wg0/rp_filter echo 0 > /proc/sys/net/ipv4/conf/cilium_wg0/rp_filter # 아래 중 하나로 패킷 덤프 수행하여 확인 tcpdump -n -i cilium_wg0 tcpdump -eni any udp port 51871 or icmp -q tcpdump -eni any udp port 51871 or icmp -q -v
Shell
복사
아래와 같이 Cilium 및 Hubble CLI를 이용해서도 확인
# Cilium Monitor c1 monitor -vv c2 monitor -vv # Flow API 쿼리 hubble observe --pod netpod1 hubble observe --pod netpod2 --protocol icmp
Shell
복사
# 컨트롤 플레인 # Ping 테스트 kubectl exec -it netpod1 -- ping -c 1 $POD2IP kubectl exec -it netpod2 -- ping -c 1 $POD1IP
Shell
복사

리소스 삭제

kubectl delete pod netpod1 netpod2
Shell
복사

설정 원복

helm upgrade cilium cilium/cilium --version $VERSION --namespace kube-system --reuse-values --set l7Proxy=true --set encryption.enabled=false kubectl -n kube-system rollout restart ds/cilium cilium config view | egrep 'l7|wireguard'
Shell
복사
최신 네트워크 LB 및 Proxy 소개와 일관성 있는 해싱 지원을 통해 장애 수용성을 높인 사례들을 참고
Kakao도 있는데 ㅠ 링크 사라짐
# 버전 변수 지정 VERSION=1.16.3 # LB 알고리즘을 Maglev로 설정 helm upgrade cilium cilium/cilium --version $VERSION --namespace kube-system --reuse-values --set loadBalancer.algorithm=maglev # 배포 kubectl -n kube-system rollout restart ds/cilium
Shell
복사
# 설정 확인 cilium config view | egrep 'maglev'
Shell
복사

환경 삭제

# CloudFormation 스택 삭제 aws cloudformation delete-stack --stack-name mylab
Shell
복사