CloudNet@ 팀의 가시다님께서 리딩하시는 KANS Study (Kubernetes Advanced Networking Study) 3주차 스터디 내용 정리
칼리코 CNI 가 실제 동작하는 통신 방식에 대해 알아보겠습니다.
실습을 위해서는 칼리코가 설치된 쿠버네티스가 필요하며, 컨트롤 플레인을 제외하고 3대의 노드가 필요합니다.
1. 동일 노드 내의 Pod 간 통신
편의를 위해 데몬셋을 제외한 아무런 파드가 배포되어 있지 않은 노드에서 실습을 진행합니다.
그런 파드가 없다면, cordon 과 drain 을 통해서 해당 노드를 비워줍니다.
# 노드 스케쥴링 방지
kubectl cordon k8s-w1
# Pod eviction
kubectl drain k8s-w1 --ignore-daemonsets
# 노드 스케쥴링 방지 해제
kubectl uncordon k8s-w1
그 후 아래 칼리코 cli 를 입력하면 k8s-w1 노드에 아무런 파드가 없다고 나옵니다.
calicoctl get workloadEndpoint -A
1.1. 노드의 기본 정보 확인
해당 실습을 진행할 노드에 ssh 접속을 하여 기본 정보를 확인해줍니다.
ip -c -d addr show
현재 노드 내부는 다음과 같습니다.
1.2. 파드 배포
k8s-w1 노드에 2개의 파드를 배포합니다.
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
nodeName: k8s-w1 # 노드의 호스트이름을 직접 지정했습니다
containers:
- name: pod1
image: nicolaka/netshoot # 이미지는 네트워크 장애 처리에 유용한 이미지를 사용합니다
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
spec:
nodeName: k8s-w1
containers:
- name: pod2
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/4/node1-pod2.yaml
kubectl apply -f node1-pod2.yaml
K8S-W1 노드에서 네트워크 인터페이스 확인
ip -c -d addr show
2개의 Calice 인터페이스가 생성된 것을 확인할 수 있습니다.
해당 인터페이스가 어떤 파드에 연결되었는 지 확인하기 위해, 파드에 직접 접속해줍니다.
# Pod 1 번에 zsh 로 접속
kubectl exec pod1 -it -- zsh
# IP Address 확인
ip -c addr
Pod1 은 9 번 네트워크 인터페이스와 페어링 연결되어 있는 것을 알 수 있습니다.
즉, 현재 노드 내부 네트워크 인터페이스 구조는 다음과 같습니다.
1.3. 파드 통신 실행
Pod 1 에서 Pod 2 로 Ping 을 날려봅니다.
kubectl exec pod1 -it -- zsh
# Pod 2 로 ICMP
ping -c 10 172.16.158.5
다음 실습을 위해 파드를 삭제합니다.
kubectl delete -f node1-pod2.yaml
2. 파드와 외부 인터넷 간 통신
칼리코의 기본 설정은 natOutgoing: true 입니다.
즉, iptables 에서 MASQUERADE Rule 에 의해 외부와 연결이 가능합니다.
2.1. 노드의 기본 정보 확인
calicoctl get ippool -o wide
2.2. 파드 배포
curl -O https://raw.githubusercontent.com/gasida/NDKS/main/4/node1-pod1.yaml
kubectl apply -f node1-pod1.yaml
2.3. 외부 통신 확인
# Pod1 접속
kubectl exec pod1 -it -- zsh
# 외부 통신
ping -c 10 8.8.8.8
노드의 각 네트워크 인터페이스에서 패킷 캡처
VETH1=calice0906292e2
tcpdump -i $VETH1 -nn icmp
tcpdump -i tunl0 -nn icmp
tcpdump -i ens5 -nn icmp
3. 다른 노드 간 Pod 통신
각 노드에서 네트워크 대역은 Bird 에 의해 BGP 전파되며, Felix 에 의해서 라우팅 테이블에 등록됩니다.
다른 노드 간 파드 통신은 tunl0 인터페이스를 통해 IP 헤더로 감싸져서,
상대측 노드로 도달 후 tunl0 인터페이스에서 Outer 헤더를 제거하고 내부 파드와 통신됩니다. (IPIP 방식)
3.1. 파드 배포
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
nodeName: k8s-w1
containers:
- name: pod1
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
spec:
nodeName: k8s-w2
containers:
- name: pod2
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/4/node2-pod2.yaml
kubectl apply -f node2-pod2.yaml
3.3. 파드 간 통신 확인
# pod1 이 배포된 노드에서 tcpdump 확인
tcpdump -i tunl0 -nn
# IPIP 프로토콜 패킷 확인
tcpdump -i ens5 -nn proto 4