스터디 목차
- 1주차
- 컨테이너 격리 - https://malwareanalysis.tistory.com/248
- 네트워크 네임스페이스 - https://malwareanalysis.tistory.com/249
- 2주차
- Flannel CNI: https://malwareanalysis.tistory.com/254
- pause 컨테이너: https://malwareanalysis.tistory.com/255
- 3주차
- calico 기본 통신과정: https://malwareanalysis.tistory.com/256
- ccalico 모드: https://malwareanalysis.tistory.com/264
- 4주차
- service와 kube-proxy iptables모드: https://malwareanalysis.tistory.com/265
- 5주차
- coredns 동작이해: https://malwareanalysis.tistory.com/267
- MetalLB L2동작 이해: https://malwareanalysis.tistory.com/271
- MetalLB BGP동작 이해: https://malwareanalysis.tistory.com/272
- 6주차
- Ingress 컨셉 이해: https://malwareanalysis.tistory.com/277
- Ingress 동작 이해: https://malwareanalysis.tistory.com/278
- Ingress https 적용: https://malwareanalysis.tistory.com/283
- 7주차
- Cilium CNI 등장배경: https://malwareanalysis.tistory.com/288
- Cilium CNI 살펴보기: https://malwareanalysis.tistory.com/289
- Cilium CNI pod 통신: https://malwareanalysis.tistory.com/290
- Cilium CNI service 통신: https://malwareanalysis.tistory.com/292
- 7주차 과제: https://malwareanalysis.tistory.com/294
안녕하세요. 이 글은 facebook 쿠버네티스 그룹에서 올라온 "쿠버네티스 네트워크 스터디" 5주차 내용을 정리했습니다.
스터디 모집글: https://www.facebook.com/groups/k8skr/posts/3202691746679143
1. 주제
7주차 과제를 수행한 내용을 정리했습니다. 이 글을 읽기 위해서 cillium 선수지식이 필요합니다. 각 과정의 상세내용은 설명하지 않습니다.
- 서비스 통신 디버깅
- DSR 확인
- Egress gateway
- BGP for LoadBalancer VIP
- Bandwith Manager
2. 공통설정
2.1 인프라
스터디에서 제공하는 vagrantfile로 환경을 구축했습니다. 쿠버네티스 클러스터는 cilium CNI가 설치되어 있습니다. 쿠버네티스 외부 PC, 외부 라우터 서버가 있습니다.
2.2 alias설정
자주 사용하는 명령어는 alias로 설정했습니다.
# CILIUMPOD 이름 조회
CILIUMPOD0=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-m -o jsonpath='{.items[0].metadata.name}')
CILIUMPOD2=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-w2 -o jsonpath='{.items[0].metadata.name}')
# cilium client alias
alias c0="kubectl exec -it $CILIUMPOD0 -n kube-system -- cilium"
alias c2="kubectl exec -it $CILIUMPOD2 -n kube-system -- cilium"
# btftool alias
alias c0bpf="kubectl exec -it $CILIUMPOD0 -n kube-system -- bpftool"
alias c2bpf="kubectl exec -it $CILIUMPOD2 -n kube-system -- bpftool"
# 실습에 사용하는 pod kubectl alias
alias p0="kubectl exec -it netpod -- "
alias p2="kubectl exec -it webpod2 -- "
# 실습에 사용하는 파드 IP
NETPODIP=$(kubectl get pods netpod -o jsonpath='{.status.podIP}')
WEBPOD2IP=$(kubectl get pods webpod2 -o jsonpath='{.status.podIP}')
3. 서비스 통신 디버깅
strace를 이용하여 eBPF동작을 추측합니다.
자세한 과정은 Cilium CNI service 통신 글(https://malwareanalysis.tistory.com/292)을 참고하시길 바랍니다.
3.1 deployment, 서비스 배포
deployment와 서비스를 배포합니다.
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: mario
labels:
app: mario
spec:
replicas: 1
selector:
matchLabels:
app: mario
template:
metadata:
labels:
app: mario
spec:
containers:
- name: mario
image: pengbai/docker-supermario
---
apiVersion: v1
kind: Service
metadata:
name: mario
spec:
selector:
app: mario
ports:
- port: 80
protocol: TCP
targetPort: 8080
type: NodePort
externalTrafficPolicy: Local
EOF
배포가 성공했는지 확인합니다.
kubectl get deploy,svc mario
3.2 외부에서 서비스 접속
<노드>:<nodeport>로 접속하면 마리오게임이 보입니다.
3.3 cilium 서비스 라우팅 정보 확인
워커노드에서 cilium 클라이언트 명령어로 서비스 목록을 확인했습니다.
c2 service list
3.4 strace 디버깅
192.168.10.102IP를 갖는 호스트에서 strace 디버깅을 수행했습니다. sendto -> recvfrom 중간단계에서 eBPF가 실행되어 도착지 IP가 변경됩니다.
strace -c curl -s 192.168.10.102:30784
3.5 hubble 대시보드 확인
hubble 대시보드에서 통신과정 시각화 결과를 확인할 수 있었습니다. netpod는 테스트용도 입니다.
4. DSR(Direct Server Return)확인
4.1 cilium 모드 확인
DSR이 활성화 되어 있는지 확인합니다. cilium config view 또는 status로 확인할 수 있습니다.
- cilium config view 확인방법
cilium config view | grep dsr
- cilium 클라이언트 status 확인방법
c0 status --verbose | grep 'KubeProxyReplacement Details:' -A7
4.2 파드, 서비스 배포
apache 도커 이미지(버전 2.4.52)를 이용하여 파드와 서비스를 배포합니다. 서비스는 외부에서 접속할 수 있도록 nodeport타입입니다.
apiVersion: v1
kind: Pod
metadata:
name: demo-apache
labels:
app: demo-apache
spec:
containers:
- name: demo-apache
image: httpd:2.4.52
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: demo-apache
spec:
type: NodePort
selector:
app: demo-apache
ports:
- port: 80
targetPort: 80
파드와 서비스가 잘 실행되는지 확인합니다. 쿠버네티스 클러스터 외부 k8s-pc호스트에서 테스트했습니다.
CLUSTERNODE=192.168.10.10
NODEPORT=$(kubectl get svc demo-apache -o jsonpath='{.spec.ports[0].nodePort}')
echo $NODEPORT
curl $CLUSTERNODE:$NODEPORT
4.3 DSR확인
DSR을 쉽게 확인하기 위해 k8s-pc에서 1초마다 http GET요청을 수행합니다.
while true; do curl -s $CLUSTERNODE:$NODEPORT;echo "-----";sleep 1;done
cilium 통신을 모니터링 하면, orig-ip가 k8s-pc ip입니다. 즉, DSR이 잘적용되고 있습니다.
# apache 파드가 워커노드2번에서 실행 중
c2 monitor -vv
4.4 패킷 덤프
패킷을 덤프하기 위해 apache 파드가 실행 중인 노드로 이동합니다. 그리고 tcpdump로 패킷덤프를 수행합니다.
NODEPORT=$(kubectl get svc demo-apache -o jsonpath='{.spec.ports[0].nodePort}')
tcpdump -eni any tcp port 80 or tcp port $NODEPORT -q -v -w /tmp/subject.pcap
와이어샤크로 패킷파일을 열면 ip헤더 options필드에 8byte가 있습니다.
8바이트 일부를 추출하면 클라이언트가 최초 접근한 노드 IP를 얻을 수 있습니다. (그런데 ... 왜 클라이언트 IP가 options에 없지!?..)
5. Egress gateway
5.1 클라이언트 파드 생성
공식문서(https://docs.cilium.io/en/stable/gettingstarted/egress-gateway/#create-client-pods)에서 제공하는 mediabot 파드를 생성합니다.
kubectl create -f https://raw.githubusercontent.com/cilium/cilium/1.11.2/examples/kubernetes-dns/dns-sw-app.yaml
음... mediabot으로 실습이 잘 진행이 안되어 netshoot 도커이미지를 사용하여 파드를 생성했습니다.
5.2 외부 웹서버 설치
쿠버네티스 클러스터 외부에 웹 서버를 설치합니다. 저는 apache를 설치했습니다. 웹서버 IP는 192.168.20.100입니다.
5.3 클라이언트 파드에서 웹서버 호출
egress gateway를 설정하기 전 클라이언트 파드에서 웹서버로 HTTP GET요청을 수행합니다.
kubectl exec netpod -- curl 192.168.20.100
apache로그를 확인하면 파드 IP가 보입니다.
5.4 egress IP설정
공식문서(https://docs.cilium.io/en/stable/gettingstarted/egress-gateway/#configure-egress-ips)를 참고하여 egress IP를 설정합니다.
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: "egress-ip-assign"
labels:
name: "egress-ip-assign"
spec:
replicas: 1
selector:
matchLabels:
name: "egress-ip-assign"
template:
metadata:
labels:
name: "egress-ip-assign"
spec:
affinity:
# the following pod affinity ensures that the "egress-ip-assign" pod
# runs on the same node as the mediabot pod
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: class
operator: In
values:
- mediabot
- key: org
operator: In
values:
- empire
topologyKey: "kubernetes.io/hostname"
hostNetwork: true
containers:
- name: egress-ip
image: docker.io/library/busybox:1.31.1
command: ["/bin/sh","-c"]
securityContext:
privileged: true
env:
- name: EGRESS_IPS
value: "192.168.10.240/24 192.168.10.241/24"
args:
- "for i in \$EGRESS_IPS; do ip address add \$i dev enp0s8; done; sleep 10000000"
lifecycle:
preStop:
exec:
command:
- "/bin/sh"
- "-c"
- "for i in \$EGRESS_IPS; do ip address del \$i dev enp0s8; done"
EOF
파드가 설치된 노드의 인터페이스를 확인하면 설정한 egress ip목록이 보입니다.
5.5 egress policy 설정
egress 정책을 설정합니다. 192.168.20.100이 목적지이고 파드 라벨이 일치하다면 정책이 활성화됩니다.
cat <<EOF | kubectl apply -f -
apiVersion: cilium.io/v2alpha1
kind: CiliumEgressNATPolicy
metadata:
name: egress-sample
spec:
egress:
- podSelector:
matchLabels:
org: empire
class: mediabot
io.kubernetes.pod.namespace: default
destinationCIDRs:
- 192.168.20.100/32
egressSourceIP: "192.168.10.240"
EOF
5.6 egress gateway 테스트
[챕터 5.3]에서 했던 http 요청을 똑같이 실행합니다. [챕터 5.3]결과와 다르게 apache로그에서는 egress gateway IP가 출력됩니다.
kubectl exec netpod -- curl 192.168.20.100
6. BGP for LoadBalancer VIP
6.1 BGP 설정
공식문서(https://cilium.io/blog/2021/05/20/cilium-110)를 참고하여 BGP를 설정합니다.
cat <<EOF | 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
EOF
kubectl get cm -n kube-system bgp-config
helm upgrade를 수행하여 loadbalancer 옵션을 활성화합니다.
VERSION=1.11.2
helm upgrade cilium cilium/cilium --version $VERSION --namespace kube-system --reuse-values --set bgp.enabled=true --set bgp.announce.loadbalancerIP=true
그리고, cilium 파드를 재실행합니다.
kubectl -n kube-system rollout restart ds/cilium
bgp설정이 잘 되었는지 확인합니다.(podCIDR도 표시되어야 하는데 아마도? 버그로 설정X)
cilium config view | grep bgp
179 포트에서 loadbalancer광고 패킷을 캡처할 수 있습니다.
tcpdump -i enp0s8 -nn tcp port 179 -q
6.2 파드와 로드밸런서타입 서비스 생성
nginx파드와 로드배런서타입 서비스를 생성합니다.
cat <<EOF | 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
EOF
6.3 External IP확인
로드밸런서타입 서비스를 확인하면 External IP가 할당되었습니다.
kubectl get svc test-lb
외부 라우터에서도 neigthbor가 추가되었습니다.
vtysh -c 'show ip route bgp'
6.4 External IP접근
쿠버네티스 클러스터에서 접근이 되는지 확인합니다.
curl 172.20.1.1
그리고 쿠버네티스 클러스터가 아닌 외부에서도 접속이 되는지 확인합니다.
6.6 externalTrafficPolicy 설정
로드밸런서타입 서비스에 externalTrafficPolicy를 설정합니다.
kubectl patch svc test-lb -p '{"spec":{"externalTrafficPolicy": "Local"}}'
외부 라우터에서 라우팅 정보를 확인하면, [챕터 6.3]와 다르게 External IP가 한 노드로 1:1 매칭되었습니다.
ip -c route | grep 172.20.1.1
7. Bandwidth Manager
7.1 Bandwidth 설정 확인
cilium config view | grep bandwidth
c0 status | grep BandwidthManager
7.2 파드 생성
서버와 클라이언트 역할하는 파드 2개를 생성합니다. netperf-server는 bandwidth가 10M로 설정됩니다.
cat <<EOF | kubectl create -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
EOF
7.3 bandwidth설정 확인
netperf-server파드가 bandwidth가 잘 설정되었는지 확인합니다.
kubectl describe pod netperf-server | grep Annotations:
netperf-server파드를 실행 중인 노드에서 cilium agent(데몬셋) bandwith 목록을 출력합니다.
c2 bpf bandwidth list
7.4 bandwidth 테스트
netperf-server파드 IP를 변수로 설정합니다.
NETPERF_SERVER_IP=$(kubectl get pod netperf-server -o jsonpath='{.status.podIP}')
bandwidth 10M설정이 잘되는지 확인합니다.
kubectl exec netperf-client -- netperf -t TCP_MAERTS -H "${NETPERF_SERVER_IP}"
bandwidth를 5M으로 변경 후 테스트합니다.
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}"
bandwidth를 20M으로 변경 후 테스트합니다.
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}"
'연재 시리즈' 카테고리의 다른 글
쿠버네티스 오퍼레이터 스터디 1주차 - 실습 (0) | 2022.05.24 |
---|---|
쿠버네티스 오퍼레이터 스터디 1주차 - statefulset이란 (0) | 2022.05.23 |
쿠버네티스 네트워크 스터디 부록: jsonpath로 clusterIP 조회 (0) | 2022.03.02 |
쿠버네티스 네트워크 스터디 7주차 - Cilium CNI service 통신 (0) | 2022.03.02 |
쿠버네티스 네트워크 스터디 7주차 - Cilium CNI pod 통신 (0) | 2022.03.01 |