개요
Cilium 이론에서 학습한 개념들을 직접 실습
환경 준비
조금 많이 과금 될 수 있으므로 금액에 유의하여 배포하며, Cilium 이용 예정임에 따라 eBPF 때문에 kube-proxy를 스킵하도록 템플릿 파일이 구성되어 있음
•
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 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 통신 확인
리소스 생성
# 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_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로 통신 확인
리소스 생성
# 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 주소와 포트를 변환)
소켓 기반 LB 확인
# 소켓 기반 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
복사
# 버전 변수 지정
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
복사