연재 시리즈

쿠버네티스 네트워크 스터디 7주차 - Cilium CNI pod 통신

악분 2022. 3. 1. 18:21
반응형

스터디 목차

 

 

안녕하세요. 이 글은 facebook 쿠버네티스 그룹에서 올라온 "쿠버네티스 네트워크 스터디" 5주차 내용을 정리했습니다.

스터디 모집글: https://www.facebook.com/groups/k8skr/posts/3202691746679143

 

1. 7주차 세번째 주제

7주차 세번째 주제는 Cilium CNI의 pod 통신입니다.

 

2. pod 통신

2.1 하이레벨

하이레벨 수준은 외국인 블로그(https://arthurchiao.art/blog/cilium-life-of-a-packet-pod-to-service/)에 자세히 설명되어 있습니다. 저는, 네트워크 엔지니어가 아니여서 필요한 부분(빨간색 네모)만 다루고자 합니다.

 

2.2 pod 디폴트게이트웨이

파드의 디폴트게이트웨이는 cilum_net 인터페이스 IP로 설정됩니다. 그리고 MAC주소는 놀랍게도 lxc인터페이스 MAC주소에 해당합니다. lxc인터페이스는 파드가 생성될때 같이 생성되는 인터페이스입니다.

 

lxc인터페이스는 연결된 파드에게 주기적으로 ARP reply 패킷을 전송하기 때문에, 파드입장에서는 디폴트게이트웨이 MAC주소가 lxc MAC주소로 설정된 것입니다.

lxc인터페이스는 proxy_arp가 비활성화 되어 있습니다.

 

2.3 라우팅 주소 검색

디폴트게이트웨이로 트래픽이 전달되면, 다음 라우팅 주소를 찾습니다. 라우팅 주소는 노드 IP입니다. 라우팅 정보는 map(자료구조)으로 저장되어 있어 key, value형태를 갖습니다. 라우팅 테이블을 찾은 후에 이후 과정은 [챕터 2.1]에서 본 것처럼 커널 라우팅 단계를 거칩니다. 

map정보는 cilium get cilium_ipcache명령어로 조회할 수 있습니다.

 

3. 실습

3.1 실습환경

스터디에서 제공한 vagrantfile을 이용하여 환경을 구축했습니다.

출처: 스터디 공유자료

 

3.2 각 노드 cilium 클라이언트 alias설정

cilium클라이언트는 데몬셋으로 실행되는 cilium 파드에서 실행할 수 있습니다. 편의성을 위해 alias설정했습니다. alias가 잘 설정되었다면 각 cilium 파드에서 cilium명령어가 잘 수행됩니다. 예를 들어 k8s-m노드에 있는 cilium파드의 cilium명령어를 수행하려면 c0 <명령어 인자>로 실행하면 됩니다.

# cilium 파드 이름
CILIUMPOD0=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-m  -o jsonpath='{.items[0].metadata.name}')
CILIUMPOD1=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-w1 -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}')

# 단축키(alias) 지정
alias c0="kubectl exec -it $CILIUMPOD0 -n kube-system -- cilium"
alias c1="kubectl exec -it $CILIUMPOD1 -n kube-system -- cilium"
alias c2="kubectl exec -it $CILIUMPOD2 -n kube-system -- cilium"

 

3.3 테스트를 위한 파드 배포

traefik/whoami도커 이미지를 이용하여 3개 파드를 배포합니다.

cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: netpod
  labels:
    app: netpod
spec:
  nodeName: k8s-m
  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:  
  containers:
  - name: container
    image: traefik/whoami
  terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
  name: webpod2
  labels:
    app: webpod
spec:  
  containers:
  - name: container
    image: traefik/whoami
  terminationGracePeriodSeconds: 0
EOF

 

그리고, pod 쉘 명령어를 편하게 사용하기 위해 alias를 설정했습니다.

# 테스트 파드들 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 -- "

 

3.4 인터페이스 확인

파드가 생성되면 lxc인터페이스가 생성되어 root네임스페이스와 연결됩니다.

netpod 파드의 디폴트게이트웨이 주소는 cilium_net ip와 일치합니다.

p0 ip -c route
ip -c -br addr show | grep cil

 

그리고 MAC주소는 lxc인터페이스 MAC주소와 같습니다.

 # 파드 게이트웨이 MAC주소 확인
 p0 -c neigh
 
 # lxc인터페이스 찾는 과정
 docker ps | grep netpod
 docker top <conatinerid>
 nsenter -t <pid> -n ip -br addr show eth0
 ip -c addr show dev <ifxx>

 

3.5 Hubble 서비스 타입 변경

외부접속을 위해 hubble 서비스 타입을 nodeport로 수정했습니다.

kubectl patch -n kube-system svc hubble-ui -p '{"spec": {"type": "NodePort"}}'

 

외부접속주소는 kubectl로 직접확인하셔도 되고 스터디에서 제공한 스크립트를 사용해도 됩니다.

HubbleUiPodHostIP=$(kubectl get pod -n kube-system -l k8s-app=hubble-ui -o jsonpath='{.items[0].status.hostIP}')
HubbleUiNodePort=$(kubectl get svc -n kube-system hubble-ui -o jsonpath={.spec.ports[0].nodePort})
echo -e "Hubble UI URL = http://$HubbleUiPodHostIP:$HubbleUiNodePort"

 

웹브라우저로 접속하면 Hubble메인 페이지가 보입니다.

 

3.6 pod 통신 테스트와 hubble에서 관찰

netpod에서 webpod2로 ping, http GET요청을 합니다.

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

 

hubble 웹페이지로 접속한 후에 네임스페이스를 default로 변경합니다. 그러면, netpod<->webpod2에서 통신내역을 시각화 한 결과가 보입니다.

 

참고자료

[1] [블로그] Life of a Packet in Cilium: Discovering the Pod-to-Service Traffic Path and BPF Processing Logics - https://arthurchiao.art/blog/cilium-life-of-a-packet-pod-to-service/

반응형