쿠버네티스 일반

Flannel CNI

Jerry_이정훈 2022. 1. 12. 10:16
728x90

아래 내용은 KANS 가시다(서종호) 님 스터디 2주차 내용을 기반으로 정리하였습니다.
https://www.notion.so/gasidaseo/KANS-1-17b0ee7990aa4839ace414b76a09cec8 

(가시다 님은 그저 빛인듯 ㅎㅎ)

제가 네트워크 관련 부분은 부족한게 많아 부정확할 수 있습니다. 내용에 오류가 있으면 언제든지 의견 부탁 드립니다. 

 

먼저 쿠버네티스는 Flannel CNI로 Kubespray 이용하여 설치하였다. (kubespray flannel 설치는 간단한데 별도 포스팅 할 예정이다. 기본 kubespray 설정에 2줄만 변경하면 된다..)

[spkr@erdia22 ~ (ubun71:default)]$ kgn  ## k get nodes -o wide
NAME        STATUS   ROLES                  AGE   VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
ubun20-71   Ready    control-plane,master   16h   v1.23.1   172.17.29.71   <none>        Ubuntu 20.04.2 LTS   5.4.0-65-generic   containerd://1.5.8
ubun20-72   Ready    control-plane,master   16h   v1.23.1   172.17.29.72   <none>        Ubuntu 20.04.2 LTS   5.4.0-65-generic   containerd://1.5.8
ubun20-73   Ready    control-plane,master   16h   v1.23.1   172.17.29.73   <none>        Ubuntu 20.04.2 LTS   5.4.0-65-generic   containerd://1.5.8
ubun20-74   Ready    <none>                 16h   v1.23.1   172.17.29.74   <none>        Ubuntu 20.04.2 LTS   5.4.0-65-generic   containerd://1.5.8
  • 쿠베 버전은 최신 버전 1.23.1이고 런타임은 containerd 
  • 컨트롤 플레인 & 워커 노드 3대, 워커 전용 노드 1대. 늘 그렇듯이 나는 컨트롤 플레인 노드를 전용으로 두지않고 컨트롤 플레인 노드에도 워커 노드를 같이 올린다. 

flannel을 설치하면 다른 cni와 동일하게 kube-system 네임스페이스에 flannel 관련 파드가 실행된다. 

[spkr@erdia22 ~ (ubun71:default)]$ kgp -n kube-system
NAME                                READY   STATUS    RESTARTS      AGE     IP             NODE        NOMINATED NODE   READINESS GATES
(생략)
kube-flannel-dxfd7                  1/1     Running   0             16h     172.17.29.74   ubun20-74   <none>           <none>
kube-flannel-hpcl5                  1/1     Running   0             16h     172.17.29.73   ubun20-73   <none>           <none>
kube-flannel-lkfqx                  1/1     Running   0             16h     172.17.29.71   ubun20-71   <none>           <none>
kube-flannel-nf2lf                  1/1     Running   0             16h     172.17.29.72   ubun20-72   <none>           <none>

다른 cni와 동일하게 데몬셋 형태로 실행 중이다. (그런데 특이하게 flannel 관련 데몬셋이 여러개고 그 중 제일 위(kube-flannel)만 실행 중이다. 무언가 오류 같은데 설치 옵션에 머가 있을 것 같다. 이름을 보아서는 cpu 아키텍쳐 관련 옵션인데, 당연히 arm, ppc64le 이런 건 제외해도 될 것 같다.)

[spkr@erdia22 ~ (ubun71:default)]$ k get ds -n kube-system
NAME                      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-flannel              4         4         4       4            4           <none>                   16h
kube-flannel-ds-arm       0         0         0       0            0           <none>                   16h
kube-flannel-ds-arm64     0         0         0       0            0           <none>                   16h
kube-flannel-ds-ppc64le   0         0         0       0            0           <none>                   16h
kube-flannel-ds-s390x     0         0         0       0            0           <none>                   16h

참고로 calico는 데몬셋 하나이다.

[spkr@erdia22 system32 (ubun11:default)]$ k get ds -n kube-system
NAME           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
calico-node    3         3         3       3            3           kubernetes.io/os=linux   126d

Flannel을 설치하면 노드에 어떤게 추가되었는지 알아보았다. 

[spkr@erdia22 ~ (ubun71:default)]$ ssh ubun20-71
spkr@ubun20-71:~$ sudo bash
root@ubun20-71:/home/spkr# su -
## -c color, -br brief
root@ubun20-71:~# ip -c -br addr
lo               UNKNOWN        127.0.0.1/8 ::1/128
ens3             UP             172.17.29.71/20 fe80::526b:8dff:fef3:fc9e/64
kube-ipvs0       DOWN           10.233.0.1/32 10.233.0.3/32 10.233.60.152/32
flannel.1        UNKNOWN        10.233.64.0/32 fe80::b0fd:fbff:fe5e:401e/64
nodelocaldns     DOWN           169.254.25.10/32
cni0             UP             10.233.64.1/24 fe80::5c20:c7ff:fe4c:1185/64
veth1a7a5052@if2 UP             fe80::7c0e:27ff:fe3e:5e2e/64

기존에 없던 새로운 인터페이스(flannel.1, cni0)들이 생성되었다. flannel.1, cni0 애네들이 쿠버네티스 노드 내 파드들이 서로 통신 가능하게 해준다. 

 

자 그럼 파드를 10개만 생성해서 flannel에서 파드가 어떻게 통신하는지 알아보자.

## 네트워크 관련 명령어를 포함하는 nicolaka/netshoot 이미지를 사용한다.
[spkr@erdia22 ~ (ubun71:default)]$ k create deployment netshoot --image=nicolaka/netshoot --replicas=10 -- sleep 1d
deployment.apps/netshoot created

노드 71, 72, 73, 74 4개의 노드에 비교적 동일하게 배포되었다. 

NAME                        READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
busybox-7fd54c485d-g74qv    1/1     Running   0          69s   10.233.67.13   ubun20-74   <none>           <none>
netshoot-5f45949b48-2wcws   1/1     Running   0          42s   10.233.64.8    ubun20-71   <none>           <none>
netshoot-5f45949b48-5d74m   1/1     Running   0          42s   10.233.67.16   ubun20-74   <none>           <none>
netshoot-5f45949b48-7st56   1/1     Running   0          42s   10.233.65.10   ubun20-72   <none>           <none>
netshoot-5f45949b48-cfpwk   1/1     Running   0          42s   10.233.67.15   ubun20-74   <none>           <none>
netshoot-5f45949b48-dbbnh   1/1     Running   0          42s   10.233.65.11   ubun20-72   <none>           <none>
netshoot-5f45949b48-lblql   1/1     Running   0          42s   10.233.66.9    ubun20-73   <none>           <none>
(생략)

파드의 IP를 보면 각 노드마다 서로 다른 IP를 가지고 있다. 각 노드마다 10.233.64, 65, 66, 67/24 대역을 사용 중이다. 

 

그럼 파드에 접속해서 cni 요구 사항인 각각 파드 별로 nat없이 접속 가능한지 확인해본다.

## 파드 접속은 exec 사용한다.
[spkr@erdia22 ~ (ubun71:default)]$ k exec -it netshoot-5f45949b48-2wcws -- bash

bash-5.1# ping -c 1 10.233.64.8
PING 10.233.64.8 (10.233.64.8) 56(84) bytes of data.
64 bytes from 10.233.64.8: icmp_seq=1 ttl=64 time=0.028 ms

--- 10.233.64.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.028/0.028/0.028/0.000 ms
bash-5.1# ping -c 1  10.233.65.10
PING 10.233.65.10 (10.233.65.10) 56(84) bytes of data.
64 bytes from 10.233.65.10: icmp_seq=1 ttl=62 time=0.502 ms

--- 10.233.65.10 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.502/0.502/0.502/0.000 ms

당연히 잘 된다. (그러라고 cni 만들었으니. nat 안하는 건 tcpdump 떠서 확인해봐야 할 것 같은데, 이건 나중에)

 

잘되는 이유를 찾기 위해서 routing을 확인한다.

bash-5.1# ip -c route
default via 10.233.64.1 dev eth0
10.233.64.0/24 dev eth0 proto kernel scope link src 10.233.64.8
10.233.64.0/18 via 10.233.64.1 dev eth0

10.233.64.0/18(24가 아니라) 대역의 라우팅은 게이트웨이가 eth0이다. 10.233.64.0/18 18 subnet 대역 IP는 다른 노드에서 실행 중인 파드의 IP 대역이다. 

 

eth0를 확인하기 위해 파드의 인터페이스를 확인한다. 인터페이스 이름이 eth0 이고 peer는 if13이다.(eth0@if13)

bash-5.1# ip a show
2: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
    link/ether 02:af:ad:f2:9d:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.233.64.8/24 brd 10.233.64.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::af:adff:fef2:9d88/64 scope link
       valid_lft forever preferred_lft forever

파드는 net 네임스페이스를 사용해서 인터페이스를 할당하니 eth0의 peer를 호스트에서 확인할 수 있을 것이다. 노드에서 확인한다. (net 네임스페이스는 항상 peer로 동작한다.)

 

파드에서 peer(이웃, neighborhood) 정보를 확인한다.

bash-5.1# ip -c neigh
10.233.64.1 dev eth0 lladdr 5e:20:c7:4c:11:85 STALE

해당 MAC 정보를 호스트에서 확인한다. (아래는 파드가 아니라 노드이다.) 다른 창에서 노드로 접속한다.

[spkr@erdia22 ~ (ubun71:default)]$ ssh ubun20-71
root@ubun20-71:~# ip -c -br link
(생략)
cni0             UP             5e:20:c7:4c:11:85 <BROADCAST,MULTICAST,UP,LOWER_UP>

노드의 cni0 인터페이스 통해서 파드가 통신하는걸 알 수 있다. (아주 성급하지만) 결론부터 말하면 아래의 경로를 거쳐서 파드는 다른 노드의 파드와 서로 통신한다.

 

출처 : https://ikcoo.tistory.com/101 

 

노드의 라우팅을 확인하면 각 노드 별 IP 대역(10.233.65,66,67/24)이 각각 라우팅되어 있다. 파드는 cni.0와 네임스페이스 peer 설정되어 있고 cni.0가 다른 노드의 ip 대역의 파드와 통신하려면 flannel.1 게이트웨이 통해서 통신한다. 

root@ubun20-71:~# ip -c route
default via 172.17.17.2 dev ens3 proto static
## 같은 노드 내 IP 대역 라우팅
10.233.64.0/24 dev cni0 proto kernel scope link src 10.233.64.1
## 다른 노드 IP 대역 라우팅
10.233.65.0/24 via 10.233.65.0 dev flannel.1 onlink
10.233.66.0/24 via 10.233.66.0 dev flannel.1 onlink
10.233.67.0/24 via 10.233.67.0 dev flannel.1 onlink
172.17.16.0/20 dev ens3 proto kernel scope link src 172.17.29.71

이렇게 위 그림대로 패킷이 전달되는 걸 확인할 수 있다. 

그리고 같은 노드 내 파드 간 통신은 아래와 같다. (이건 생략) 



다음은 좀 더 상세한 flannel 관련 정보이다. flannel은 vxlan을 사용한다. (vxlan이니 다른 노드 통신 시 추가 헤더를 붙혀서 통신하겠지.) 아래와 같이 flannel 인터페이스 정보를 확인하면 vxlan을 확인할 수 있다. (특이한 건 10.233.64.0/32, 32 bit에 0번 ip를 사용한다는 거다. 32bit도 생소하고 0번 ip도 생소하다.)

root@ubun20-71:~# ip -c -d addr show flannel.1
4: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
    link/ether b2:fd:fb:5e:40:1e brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535
    vxlan id 1 local 172.17.29.71 dev ens3 srcport 0 0 dstport 8472 nolearning ttl auto ageing 300 udpcsum noudp6zerocsumtx noudp6zerocsumrx numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 10.233.64.0/32 brd 10.233.64.0 scope global flannel.1
       valid_lft forever preferred_lft forever
    inet6 fe80::b0fd:fbff:fe5e:401e/64 scope link
       valid_lft forever preferred_lft forever

반면에 cni0 인터페이스는 bridge 설정이다. ip는 10.233.64.1/24 일반적인 24bit에 1번을 사용하고. 

root@ubun20-71:~# ip -c -d addr show cni0
6: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
    link/ether 5e:20:c7:4c:11:85 brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535
    bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 0 vlan_protocol 802.1Q bridge_id 8000.5e:20:c7:4c:11:85 designated_root 8000.5e:20:c7:4c:11:85 root_port 0 root_path_cost 0 topology_change 0 topology_change_detected 0 hello_timer    0.00 tcn_timer    0.00 topology_change_timer    0.00 gc_timer  111.92 vlan_default_pvid 1 vlan_stats_enabled 0 vlan_stats_per_port 0 group_fwd_mask 0 group_address 01:80:c2:00:00:00 mcast_snooping 1 mcast_router 1 mcast_query_use_ifaddr 0 mcast_querier 0 mcast_hash_elasticity 16 mcast_hash_max 4096 mcast_last_member_count 2 mcast_startup_query_count 2 mcast_last_member_interval 100 mcast_membership_interval 26000 mcast_querier_interval 25500 mcast_query_interval 12500 mcast_query_response_interval 1000 mcast_startup_query_interval 3124 mcast_stats_enabled 0 mcast_igmp_version 2 mcast_mld_version 1 nf_call_iptables 0 nf_call_ip6tables 0 nf_call_arptables 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 10.233.64.1/24 brd 10.233.64.255 scope global cni0
       valid_lft forever preferred_lft forever
    inet6 fe80::5c20:c7ff:fe4c:1185/64 scope link
       valid_lft forever preferred_lft forever

flannel은 vxlan을 사용하니 VTEP(Virtual Tunnel End Points, 가상 터널 종결점)을 확인할 수 있다. VTEP은 아래와 같이 각 노드 별로 상세 정보로 확인한다. 

[spkr@erdia22 system32 (ubun71:default)]$ kubectl describe node | grep -A3 Annotations
Annotations:        flannel.alpha.coreos.com/backend-data: {"VNI":1,"VtepMAC":"b2:fd:fb:5e:40:1e"}
                    flannel.alpha.coreos.com/backend-type: vxlan
                    flannel.alpha.coreos.com/kube-subnet-manager: true
                    flannel.alpha.coreos.com/public-ip: 172.17.29.71
--
Annotations:        flannel.alpha.coreos.com/backend-data: {"VNI":1,"VtepMAC":"0a:2e:b5:a5:bf:2e"}
                    flannel.alpha.coreos.com/backend-type: vxlan
                    flannel.alpha.coreos.com/kube-subnet-manager: true
                    flannel.alpha.coreos.com/public-ip: 172.17.29.72
--
Annotations:        flannel.alpha.coreos.com/backend-data: {"VNI":1,"VtepMAC":"de:cc:b6:d4:e2:56"}
                    flannel.alpha.coreos.com/backend-type: vxlan
                    flannel.alpha.coreos.com/kube-subnet-manager: true
                    flannel.alpha.coreos.com/public-ip: 172.17.29.73
--
Annotations:        flannel.alpha.coreos.com/backend-data: {"VNI":1,"VtepMAC":"a2:ad:56:b3:f1:e7"}
                    flannel.alpha.coreos.com/backend-type: vxlan
                    flannel.alpha.coreos.com/kube-subnet-manager: true
                    flannel.alpha.coreos.com/public-ip: 172.17.29.74

각 노드의 flannel.1 이 VTEP이다. 아래는 2번 노드 예시.

root@ubun20-72:~# ip -c -br link
flannel.1        UNKNOWN        0a:2e:b5:a5:bf:2e <BROADCAST,MULTICAST,UP,LOWER_UP>
더보기

참고. VTEP 설명 

That is, IP encapsulated traffic is switched or routed as

any IP traffic would be. VXLAN gateways, also called Virtual Tunnel End Points (VTEP), provide the encapsulating/de-encapsulating services central to VXLAN. VTEPS can be virtual bridges in the hypervisor, VXLAN aware VM applications or VXLAN capable switching hardware. VTEPs are key to virtualizing networks across the existing data center infrastructure

출처. https://www.arista.com/assets/data/pdf/Whitepapers/VXLAN_Scaling_Data_Center_Designs.pdf 

컨테이너는 netfilter iptables(or ipvs)로 외부와 통신하니 iptables로 확인하면 상세 규칙을 확인할 수 있다. (아직 iptables에 대한 개념이 없어서 정확하게는 설명이 안된다. MASQUERADE는 알겠는데 RETURN 왜 나오는지. ! 도 헷갈리고) 아무튼 10.233.64.0/18 네트워크는 별도로 되어 있다.

root@ubun20-71:~# iptables -t nat -S|grep 10.233.64.0
-A POSTROUTING -s 10.233.64.0/18 -d 10.233.64.0/18 -j RETURN
-A POSTROUTING -s 10.233.64.0/18 ! -d 224.0.0.0/4 -j MASQUERADE --random-fully
-A POSTROUTING ! -s 10.233.64.0/18 -d 10.233.64.0/24 -j RETURN
-A POSTROUTING ! -s 10.233.64.0/18 -d 10.233.64.0/18 -j MASQUERADE --random-fully

같은 노드 내 컨테이너(파드)는 서로 통신 가능하도록 설정되었다.

root@ubun20-71:~# iptables -t filter -S|grep 10.233.64.0
-A FORWARD -s 10.233.64.0/18 -j ACCEPT
-A FORWARD -d 10.233.64.0/18 -j ACCEPT

일단 오늘은 여기까지 ^^ 

 

flannel 사용 시 어떤 인터페이스가 생성되고 파드끼리 어떻게 통신되는지 확인하였다. 

 

참조

flannel 설명이 아주 잘되어있다. https://ikcoo.tistory.com/101 

반응형