[Study 2주차] 쿠버네티스 Flannel CNI
- -
CloudNet@ 팀의 가시다님께서 리딩하시는 KANS Study (Kubernetes Advanced Networking Study) 2주차 스터디 내용 정리
이번에는 Flannel 을 공부하면서, 쿠버네티스 CNI 에 대해서 이해해보겠습니다.
1. CNI (Container Network Interface)
CNI 는 컨테이너 간 네트워크 제어 플러그인을 작성하기 위한 표준입니다.
- 쿠버네티스 네트워크 모델 요구사항 4가지
- 파드와 파드 간 통신 시 NAT 없이 통신 가능
- 노드 에이전트는 파드와 통신 가능
- 호스트 네트워크 파드는 NAT 없이 파드와 통신 가능
- 서비스 클러스터 IP 대역과 파드 IP 대역 간 중복 방지
- CNI 가 해결해야 하는 쿠버네티스 네트워크 통신 문제
- 파드 내부 컨테이너는 루프백 (Loopback) 을 통한 통신 가능
- 파드 간 통신 가능
- 클러스터 내부에서 쿠버네티스 서비스를 통한 통신 가능
- 클러스터 외부에서 쿠버네티스 서비스를 통한 통신 가능
이러한 요구사항을 충족하는 CNI 는 종류가 다양하지만, 이번에는 가볍고 간단하게 동작할 수 있는 Flannel 을 알아보겠습니다.
1.1. Flannel CNI 소개 및 설치
Flannel 은 단일 바이너리 에이전트인 flanneld 가 각 노드에서 동작하여, 작은 규모의 클러스터 환경에서 파드 간 통신 환경을 구성해주는 CNI 입니다.
- kind 를 통한 실습환경 구축
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
labels:
mynode: control-plane
extraPortMappings:
- containerPort: 30000
hostPort: 30000
- containerPort: 30001
hostPort: 30001
- containerPort: 30002
hostPort: 30002
kubeadmConfigPatches:
- |
kind: ClusterConfiguration
controllerManager:
extraArgs:
bind-address: 0.0.0.0
etcd:
local:
extraArgs:
listen-metrics-urls: http://0.0.0.0:2381
scheduler:
extraArgs:
bind-address: 0.0.0.0
- |
kind: KubeProxyConfiguration
metricsBindAddress: 0.0.0.0
- role: worker
labels:
mynode: worker
- role: worker
labels:
mynode: worker2
networking:
disableDefaultCNI: true
kind 는 kindnet 이라는 기본 CNI 가 같이 배포되는데, Flannel CNI 설치를 위해 배포하지 않겠다는 설정을 하는 것입니다.
networking:
disableDefaultCNI: true
# 클러스터 배포
kind create cluster --config kind-cni.yaml --name myk8s --image kindest/node:v1.30.4
# Node 와 Pods 상태 확인
kubectl get nodes -o wide
kubectl get pods -A -o wide
CNI 가 배포되지 않았기 때문에, Node 가 NotReady 상태이며 Static Pod 를 제외한 모든 파드가 배포되지 않았습니다.
# 실습을 위한 네트워크 도구 설치
docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump iputils-ping htop git nano -y'
docker exec -it myk8s-worker sh -c 'apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump iputils-ping -y'
docker exec -it myk8s-worker2 sh -c 'apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump iputils-ping -y'
- Flannel CNI 설치
# Flannel 설치
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
# Flannel 확인
kubectl get ds,pod,cm -n kube-flannel
1.2. Bridge 에러 해결
Flannel 을 설치하더라도, CoreDNS 가 배포되지 않습니다.
kubectl describe pod -n kube-system -l k8s-app=kube-dns
'/opt/cni/bin' 안에 'bridge' 파일이 없어서 발생한 오류인 것을 알 수 있습니다.
아래와 같은 방법으로 bridge 실행 파일을 생성하여 컨테이너에 주입하면 해결할 수 있습니다.
#
docker exec -it myk8s-control-plane bash
---------------------------------------
apt install golang -y
git clone https://github.com/containernetworking/plugins
cd plugins
chmod +x build_linux.sh
#
./build_linux.sh
Building plugins
bandwidth
firewall
portmap
sbr
tuning
vrf
bridge
host-device
ipvlan
loopback
macvlan
ptp
vlan
dhcp
host-local
static
# 파일 권한 확인 755
ls -l bin
-rwxr-xr-x 1 root root 4559683 Sep 3 04:54 bridge
...
exit
---------------------------------------
# 자신의 PC에 복사 : -a 권한 보존하여 복사(755)
docker cp -a myk8s-control-plane:/plugins/bin/bridge .
ls -l bridge
# 로컬에 복사한 bridge 파일을 kind 노드에 배포
docker cp bridge myk8s-control-plane:/opt/cni/bin/bridge
docker cp bridge myk8s-worker:/opt/cni/bin/bridge
docker cp bridge myk8s-worker2:/opt/cni/bin/bridge
문제가 해결되어 파드가 배포되었습니다.
1.3. Flannel 정보 확인
# 각 노드의 파드 서브넷 대역
for i in myk8s-control-plane myk8s-worker myk8s-worker2; do echo ">> node $i <<"; docker exec -it $i cat /run/flannel/subnet.env ; echo; done
# 파드의 Public IP
kubectl describe node | grep -A3 Annotations
- 노드 내부에서 Flannel 프로세스 확인
docker exec -it myk8s-worker bash
lsns -p $(pgrep flanneld)
lsns -p $(pgrep kube-proxy)
# 노드의 라우팅 정보 확인
ip -c route
라우팅 정보를 확인해보면, CNI 가 자동으로 내부 네트워크 라우팅을 잡아주는 것을 확인할 수 있습니다.
1.4. 쿠버네티스 파드 통신
파드 간 통신 테스트를 위해 2개의 파드를 배포합니다.
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
name: pod-1
labels:
app: pod
spec:
nodeSelector:
kubernetes.io/hostname: myk8s-worker
containers:
- name: netshoot-pod
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
name: pod-2
labels:
app: pod
spec:
nodeSelector:
kubernetes.io/hostname: myk8s-worker2
containers:
- name: netshoot-pod
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
- 파드의 네트워크 통신 흐름 파악
스터디 멤버 중 한 분이신 광순님께서 테스트 흐름도를 너무 이해하기 쉽게 만들어 주셨습니다.
kubectl exec -it pod-1 -- zsh
# 호스트 GW IP 호출 (동일 노드 간 내부 통신)
ping 10.244.1.1
# Pod2 IP 호출 (다른 노드의 파드 간 통신)
ping 10.244.2.2
# 외부 인터넷 IP 호출
ping 8.8.8.8
# 외부 인터넷 도메인 ghcnf
curl -s wttr.in/Seoul
- Node 의 eth0 인터페이스에서 패킷 덤프
## Terminal 1번
# Node 1번 접속
docker exec -it myk8s-worker bash
# eth0 에서 UDP 패킷 덤프
tcpdump -i eth0 -nn udp port 8472 -w /root/vxlan.pcap
## Terminal 2번
# Pod 접근
kubectl exec -it pod-1 -- zsh
# 다른 노드의 파드로 Ping 전송
ping 10.244.2.2
성공적으로 ping 을 전송했다면, Wireshark 를 통해 덤프를 확인해봅니다.
# Node 에 덤프 뜬 패킷을 로컬로 복사
docker cp myk8s-worker:/root/vxlan.pcap .
# Wireshark 로 패킷 확인
wireshark vxlan.pcap
Flannel 은 다른 노드의 파드와 통신할 때, UDP 8472 를 사용하여 전송합니다.
만약 Wireshark 에서 Source / Destination IP 정보가 제대로 안보인다면,
Preference 설정에서 VXLAN 프로토콜을 8472로 설정해주면 됩니다.
이번 주차 스터디를 통해서 쿠버네티스의 파드 간 통신과 CNI 에 대해 잘 이해할 수 있었습니다.
처음에는 하나도 몰라서 멘붕이 왔는데, 반복해서 학습을 하다보니 내것이 되어가고 있는 느낌이었습니다.
다음은 어떤 쿠버네티스 네트워크를 배울 지 기대가 되네요!
'Kubernetes' 카테고리의 다른 글
[Study 3주차] 쿠버네티스 Calico CNI 기본 통신 이해 (1) | 2024.09.22 |
---|---|
[Study 3주차] 쿠버네티스 Calico CNI 소개 (0) | 2024.09.22 |
[Study 2주차] 쿠버네티스 Pause 컨테이너 (0) | 2024.09.07 |
[Study 2주차] Kind 로 로컬 PC 에 쿠버네티스 설치 (0) | 2024.09.06 |
[KANS Study 1주차] 컨테이너 네트워크 알아보기 (3) | 2024.09.01 |