개요
Flannel을 통해 CNI를 학습하고 아래 내용을 탐구
•
CNI의 정의와 동작 방식
•
Flannel, Calico, Cilium의 간단한 특징
•
로컬, 리모트 노드 간의 Pod 통신 과정
•
Flannel의 통신 환경 3가지와 podCIDR 라우팅 정보 획득 방법
k8s 네트워크 모델
k8s 네트워크 모델은 아래 요구사항을 만족
•
NAT 없는 Pod 간 통신 지원
•
kubelet 및 데몬 등의 노드 에이전트는 Pod와 통신 가능
•
중복 없는 서비스 클러스터 IP 대역과 Pod IP 대역
k8s 네트워크 모델은 아래 문제를 해결
•
Pod 내 컨테이너들은 루프백으로 통신
•
Pod 간 통신 지원
•
클러스터 내부에서 서비스를 통해 통신 가능
•
클러스터 외부에서 서비스를 통해 통신 가능
→ 이와 같은 통신을 지원하기 위해 CNI를 정의
CNI
개념
CNI는 컨테이너 런타임과 통합하여 컨테이너의 네트워크 인터페이스를 추가하고 IP를 할당하는 역할을 담당
오로지 컨테이너의 네트워크 연결성과 컨테이너 삭제 시 관련 네트워크 리소스 해제에만 관여하기에, 어떤 컨테이너 런타임을 이용하든 무관
명세
•
컨테이너는 리눅스 네트워크 네임스페이스 안에 존재
•
도커와 같은 컨테이너는 실행 마다 새로운 네임스페이스를 생성
•
CNI 정의서는 JSON으로 표기
•
CNI 정의서는 표준 입력, 매개 변수는 환경 변수로 CNI 플러그인에 전달
•
CNI 플러그인은 실행 파일로 구현
•
CNI 플러그인은 컨테이너 네트워크 연결을 위한 모든 작업에 책임 존재
•
CNI 플러그인은 IPAM (IP 주소 할당 및 라우팅 정보 입력) 책임도 존재
플러그인
CNCF에서 기술한 위의 명세를 준수하여 구현한 것을 CNI 플러그인이라 지칭
다양한 플러그인이 있지만 대표적으로 Flannel, Calico, Cilium이라는 CNI 플러그인을 이용
•
Flannel : VXLAN을 사용하여 간단하게 동작하는 오버레이 네트워크
•
Calico : BGP를 사용하여 다양한 기능을 제공하는 오버레이 네트워크
•
Cilium : eBPF 기반으로 동작하는 오버레이 네트워크
언더레이 네트워크는 실제 장비를 이용하여 통신하는 기술이며, 오버레이 네트워크는 네트워크를 가상화 하여 통신하는 기술을 지칭
Pod 간 통신
Pause 컨테이너를 선행적으로 학습
구성 요소와 특징
image from https://kschoi728.tistory.com/248
Pod는 자체적인 네트워크 네임스페이스를 구축하고, 이는 루트 네트워크 네임스페이스와 격리된 별개의 네임스페이스
Pod는 네임스페이스 단위로 IP 주소가 할당되는데, 컨테이너들은 동일한 네트워크 네임스페이스와 IP 주소를 공유
image from https://kschoi728.tistory.com/248
Pod 간 통신 시 eth0끼리 통신이 필요한데 네트워크 네임스페이스가 다르기에, 루트 네트워크 네임스페이스를 경유하여 통신을 수행
따라서 각 Pod는 루트 네트워크 네임스페이스로의 접근 권한이 필요하고, 이는 각 Pod가 사용하는 인터페이스가 veth (Virtual Ethernet Pair)로 연결되어 만족
Virtual Ethernet Pair는 두 개의 인터페이스를 서로 연결하는 가상의 네트워크 케이블과 같은 역할을 수행
cni0는 Pod 네트워크 인터페이스들을 묶어 Pod 간 통신을 관리하는 가상의 브릿지로, Pod 네트워크 인터페이스와 호스트 네트워크 인터페이스를 연결하여 외부로의 접근도 허용
브릿지는 네트워크 인터페이스들을 하나의 네트워크로 묶어서 통신이 가능하도록 돕는데, 위의 경우 veth 사이의 트래픽이 루트 네트워크 네임 스페이스를 통과할 수 있도록 돕는 일종의 가상화된 2계층 Switch로 동작
동일 노드 간 Pod 통신
1.
Pod A와 Pod B는 동일한 네트워크 네임스페이스를 사용하는 것이 아니므로, Pod A에서 출발한 패킷은 Pod A의 eth0 인터페이스로 이동
2.
Pod A의 eth0와 연결된 veth0로 전달되어 루트 네트워크 네임스페이스로 전달
3.
cni0 브릿지로 전달된 패킷을 전달하기 위해 Pod B의 IP 주소에 해당되는 MAC 주소를 ARP로 탐색
4.
veth1로 패킷을 전달하고, 이와 연결된 Pod B의 eth0로 전달
다른 노드 간 Pod 통신
1.
동일 노드 간 Pod 통신 1, 2번을 동일하게 수행
2.
노드 내 통신이 아니므로 노드 네트워크 통과를 위해 추가 홉이 필요하고, 노드 1의 eth0에서 노드 2의 eth0로 전달
3.
노드 2의 eth0로 전달된 패킷을 노드2의 cni0 브릿지가 받음
4.
동일 노드 간 Pod 통신 3, 4번을는 동일하게 수행
→ 오버레이 네트워크는 가상화된 네트워크로 Pod들이 같은 네트워크에 있는 것처럼 쉽게 통신할 수 있도록 돕고, 물리적인 네트워크로 전달될 때 트래픽을 특정 형태로 Encap / Decap을 수행
→ Pod 간 통신 시 노드를 벗어나야 하는 경우에 Pod가 타겟팅하는 노드를 알 수 있도록 돕게 오버레이 네트워크를 적용할 수 있는데, 이와 같은 역할을 하는 것이 Flannel과 같은 CNI 플러그인
모든 CNI 플러그인이 오버레이 네트워크를 지원하는 것은 아님
Flannel
개념
Encap) Image from https://kschoi728.tistory.com/248
Decap) Image from https://kschoi728.tistory.com/248
Flannel은 단일 바이너리 에이전트인 flanneld가 각 노드에서 동작하고, 작은 규모의 클러스터에서 Pod 간 통신 가능한 환경을 구성하는 CNI 플러그인
위 Pod 통신 환경에서 노드의 eth0와 cni0 브릿지 사이에 새로운 인터페이스로써 존재하고, VXLAN과 같은 기술을 통해 트래픽이 캡슐화 되어 전달
즉, Flannel은 노드 내에서의 통신 보다는 다른 노드 사이의 Pod 간 통신을 지원하기 위한 노드 단위의 가상 네트워크 인터페이스
따라서 해당 계층을 지나 캡슐화된 패킷은 Pod의 IP 주소가 아닌 노드의 IP 주소를 이용하는 식으로 치환
Flannel이 모든 Pod를 대상으로 해당 Pod가 위치한 노드와 IP 주소를 알 수 있는 것은 노드에서 동작 중인 flanneld가 etcd 분산 데이터베이스를 통해 ARP 테이블을 업데이트 하여 IP 주소 결정을 동기화하는 구조 때문
네트워크 환경
•
오버레이 네트워크를 구현하는 대표적인 방법인 VXLAN
◦
권장
•
오버레이 네트워크 없이 노드에 있는 Pod 네트워크 대역을 라우팅 테이블에 업데이트하여 직접 라우팅을 수행하는 host-gw
◦
모든 노드가 동일한 서브넷에 있어야 해서, 퍼블릭 클라우드에서 사용이 어려워 비권장
•
오래된 리눅스 커널에서 사용할 수 있는 오버레이 네트워크 기법인 UDP
◦
비권장
실습 흐름
Flannel 적용
•
클러스터 생성
◦
networking.disableDefaultCNI를 true로 설정
•
레포지토리 클론 및 bridge 플러그인 빌드 및 /opt/cni/bin 경로 배치
•
manifest 이용하여 Flannel 배포
Flannel 확인
•
kubectl get no -o jsonpath='{.items[*].spec.podCIDR}'
◦
Flannel이 각 노드에 서브넷 할당을 어떻게 했는지 Pod CIDR 범위를 통해 확인
•
kubectl describe no | grep -A3 Annotations | grep flannel.alpha.coreos.com/public-ip
◦
노드가 Flannel 네트워크 참여시 사용하는 공개 IP 주소 확인
•
lsns -p $(pgrep flanneld)
◦
Flannel은 별도의 네트워크 네임스페이스를 이용하지 않음에 따라 클러스터와 동일한 네트워크 네임스페이스를 이용
◦
Flannel은 클러스터 단위에 걸쳐 노드들의 네트워크 설정을 관리하기 때문에 격리 없이 호스트 네트워크 이용
•
lsns -p $(pgrep kube-proxy)
◦
kube-proxy는 클러스터 네트워크에서 서비스로 트래픽을 라우팅
◦
kube-proxy는 네트워크 네임스페이스를 init 프로세스와 동일하게 이용하여 호스트 네트워크와 직접 상호작용
•
Pod 직접 생성하여 cni0와 flannel.1 인터페이스를 확인
◦
brctl show cni0 → cni0에 연결된 veth들을 확인
◦
bridge link → 상태가 정상인 veth가 flannel.1 네트워크에 연결되어 cni0 하위 인터페이스임을 확인
◦
bridge vlan → vlan을 확인하고 cni0와 그 하위 인터페이스들이 vlan에 속함을 확인
◦
tree /var/lib/cni/networks/cbr0 → 컨테이너에 할당한 마지막으로 예약된 IP 주소 기록 (last_reserved_ip.0)와 다른 프로세스에서 cbr0 네트워크 상태 업데이트 할 때 충돌 방지를 위한 파일 (lock)을 확인 가능
•
아래 명령어들을 이용하여 다른 노드에 배포된 Pod 간 통신 / 외부 인터넷 IP 접속 / 외부 인터넷 도메인 접속 / GW IP 인터페이스 (cni0)를 확인
◦
tcpdump -i cni0 -nn icmp와 ping을 조합
◦
tcpdump -i flannel.1 -nn icmp와 ping을 조합
◦
tcpdump -i eth0 -nn icmp 와 ping을 조합
Reference
CNI가 왜 필요하고 구성이 어떻게 되는지와 Flannel이 어떤 역할을 해주는지, 그리고 Flannel 적용 실습 및 분석이 상세히 기록되어 있음