제목 : CNI 와 Calico Network

본문의 내용은 이후에도 업데이트 될 수 있음
내용의 결과값은 #1 에서 초기 구성한 ( controller , worker ) 시스템에서 진행 

CNI ( Container Network Interface )

CNCF 에서 정의한 컨테이너 네트워크 인터페이스.
Kubernetes는 기본적으로 Kubenet 이라는 CNI 를 준수하는 Network Plugin 을 갖고 있다.
하지만 복합적이고 다양한 구조의 네트워킹 사용 용도로는 다소 부족하여, 외부 네트워크 플러그인의 필요성이 대두되었다.

Calico Network?

vRouter 기반의 라우터(L3) 기반의 네트워크 관리 모델이다. 
Kubernetes 의 서비스 Network 를 구성하는 CNI 를 준수하는 Network Plugin 중 하나이다.
쿠버네티스의 기본 네트워크 서비스는 기능적으로 부족한 부분이 있는데 자주 사용되는 외부 플러그인이다.

프로젝트 공식 Document URL : https://projectcalico.docs.tigera.io/reference/

Non-overlay 방식의 라우팅

# Direct 방식 
- BGP(Border Gateway Protocol) 인 BIRD 를 통해 다른 노드 간 라우팅 정보를 동적으로 공유하여 통신할 수 있다
즉 Pod 에서 다른 Pod 로 직접 네트워킹하는 방식으로 성능적으로 가장 뛰어나다.
각 Node 에 존재하는 Calico Pod 는 BGP를 처리하는 Peer 라고 볼 수 있다.
보통 같은 서브넷에 존재하는 노드들을 묶는 방법으로 사용된다. ( ex: 라우터 밑의 여러 서버 )

Overlay Network 방식의 라우팅

Workload IP( ex: 서비스 컨테이너) 를 모르는 다른 네트워크와의 통신 기법을 의미한다.
여러 노드의 네트워크 패킷을 캡슐화(Encaptulation) 하여 논리적인 공통(L2) 네트워크를 구성하는 방식이다.
캡슐화 패킷 패턴 : 외부 패킷에는 Node 간 IP 정보가 있고, 내부에는 POD 간의 IP 정보가 있다. 

# IP in IP 방식(Default) 
- 각 노드의 네트워크 위치가 달라 Direct 방식으로 통신하기 어려운 경우 
IP 패킷 정보를 캡슐화하여 tunl0(tunneling) 인터페이스를 거쳐 노드 간 통신을 가능하게 연결한다.
이후 Direct 와 마찬가지로 BGP (BIRD) 를 통해 노드 간 라우팅 정보를 다른 Node 와 동적(IPVS)으로 전달 및 갱신한다.
Calico Routing 기본 방식이다. 

# VXLAN 방식 
- 가령 물리적 네트워크의 노드와 특정 퍼블릭 클라우드의 다른 네트워크를 연결할 경우
퍼블릭 클라우드 쪽의 라우터 설정 차이 등으로 IP in IP 방식을 쓰지 못할 수 있다. ( ex: Azure )
이럴 경우 Calico 에서는 라우터를 거치는 BGP 프로토콜을 사용하지 않고 가상의 VXLAN 인터페이스를 Node 간에 생성하여
L2 캡슐화된 UDP 패킷을 서로 통신할 수 있게 하는 방법이다.
IP in IP 방식에 비해 패킷의 크기가 조금 더 크지만 대규모의 워크로드 시스템이 아닌 한 큰 체감은 없다.

# Cross-subnet 방식
캡슐화가 필요한 경우(네트워크가 다를 경우)에서만 선택적인 캡슐화 구성도 가능하다. 
( 일부 구간/전체 구간 ) 

패킷 암호화 ( 옵션 )

# WireGuard 
Calico 는 모든 유형의 라우팅 방식에서 패킷 암호화 기능을 별도로 추가할 수 있다.
모든 네트워크 성능의 저하가 발생하게 되므로 적절한 계획 수립이 필요하다.   

Calicoctl

Controller 에서 Calico Network 정보를 확인할 수 있는 유틸리티이다.
Host의 단독 명령어 또는 kubectl 에 plugin 타입으로도 설치할 수 있다.

# Host 의 명령어 타입으로 설치
$ cd /usr/local/bin
$ sudo curl -L https://github.com/projectcalico/calico/releases/download/v3.22.1/calicoctl-linux-amd64 -o calicoctl
$ sudo chmod +x calicoctl

# Check
Calico 가 관리하는 Network 의 Pool과 Block 을 확인할 수 있다.
$ sudo calicoctl ipam show --show-blocks
+----------+--------------------+-----------+------------+--------------+
| GROUPING |        CIDR        | IPS TOTAL | IPS IN USE |   IPS FREE   |
+----------+--------------------+-----------+------------+--------------+
| IP Pool  | 192.168.0.0/16     |     65536 | 5 (0%)     | 65531 (100%) |
| Block    | 192.168.136.0/26   |        64 | 4 (6%)     | 60 (94%)     |
| Block    | 192.168.153.192/26 |        64 | 1 (2%)     | 63 (98%)     |
+----------+--------------------+-----------+------------+--------------+

BGP 프로토콜을 사용해 라우팅 정보를 전달중인 노드를 확인할 수 있다
$ sudo calicoctl node status
Calico process is running.
IPv4 BGP status
+----------------+-------------------+-------+----------+-------------+
|  PEER ADDRESS  |     PEER TYPE     | STATE |  SINCE   |    INFO     |
+----------------+-------------------+-------+----------+-------------+
| 203.248.23.215 | node-to-node mesh | up    | 05:27:05 | Established |
+----------------+-------------------+-------+----------+-------------+

Block 에서 사용중인 관련 인터페이스들
$ route -n | egrep "tun|cali|\*"
192.168.136.0   0.0.0.0         255.255.255.192 U     0       0        0 *
192.168.136.1   0.0.0.0         255.255.255.255 UH    0      0        0 calibc6c3028870
192.168.136.2   0.0.0.0         255.255.255.255 UH    0      0        0 calid6edae09645
192.168.136.3   0.0.0.0         255.255.255.255 UH    0      0        0 calic6bfd11bfbe
192.168.153.192 203.248.23.215  255.255.255.192 UG    0      0        0 tunl0

어떤 Pod가 어떤 calicxxxxxx 인터페이스를 사용하는지 확인하려면 다음의 명령어를 사용한다
System(default) Namespace 까지 보이게 하려면 -A 옵션을 추가한다.

$ calicoctl get workloadendpoint -A
NAMESPACE     WORKLOAD                                   NODE              NETWORKS           INTERFACE
kube-system   calico-kube-controllers-56fcbf9d6b-nlqg2   user-controller   192.168.136.2/32   calid6edae09645
kube-system   coredns-64897985d-jgj5s                    user-controller   192.168.136.3/32   calic6bfd11bfbe
kube-system   coredns-64897985d-vbpn4                    user-controller   192.168.136.1/32   calibc6c3028870

Calico 인터페이스는 Veth type(Pair) 이다.
$ ip -br -c link show type veth
calibc6c3028870@if3 UP             ee:ee:ee:ee:ee:ee <BROADCAST,MULTICAST,UP,LOWER_UP>
calid6edae09645@if4 UP             ee:ee:ee:ee:ee:ee <BROADCAST,MULTICAST,UP,LOWER_UP>
calic6bfd11bfbe@if4 UP             ee:ee:ee:ee:ee:ee <BROADCAST,MULTICAST,UP,LOWER_UP>

Calico Management Pod

특정 Daemon이 아닌 Pod 형태로 존재한다. 
Controller 와 Worker Node 에 각각 실행되는 Pod 가 다름을 체크한다. 

$ kubectl get pods -o wide -n kube-system
NAME                                       READY   STATUS    RESTARTS   AGE   IP              NODE  
calico-kube-controllers-56fcbf9d6b-nlqg2   1/1     Running   0          30m   192.168.136.2   user-controller
calico-node-8cts6                          1/1     Running   0          30m   10.0.2.15       user-controller  
calico-node-mb9n6                          1/1     Running   0          29m   10.0.2.15       user-worker       

Calico의 설정 정보 등의 DB 값은 etcd 라는 서비스의 datastore 에 저장된다.
$ kubectl get pods -o wide -n kube-system | grep -i etcd
etcd-user-controller                       1/1     Running   0          39m   10.0.2.15       user-controller

Calico Felix

쿠버네티스 Pod 네트워크에서 kube-proxy 상위 역할을 해 주는 컴포넌트이다.
etcd 에서 정보들을 읽어와서 Pod Network 의 라우팅 테이블과 룰을 관리한다.
kube-proxy 가 iptables / ipvs Mode 일경우 그에 맞춰 관리해준다.
iptables 라인이 너무 클 경우 성능에 영향이 있을 수 있어 플러그인에 의한 ipvs 방식이 선호된다.
※ IPVS = Hash 값으로 동적으로 라우팅 테이블을 관리하는 로드밸런서 알고리즘

$ sudo iptables -t nat -S  | grep -i cali
$ sudo iptables -t filter -S  | grep -i cali

Networking 과정

IP in IP Networking

Controller Node 에서 Worker Node 에 있는 Pod 네트워크로 통신을 시도한다

1) Controller의 192.168.136.2 Pod 에서 Worker의 192.168.153.193 Pod 로 통신
2) Controller의 Pod 인터페이스(veth) 는 Pair 인 Host의 calico (veth) 인터페이스로 ARP 요청
3) Host 의 Calico 인터페이스는 Worker Pod 의 네트워크 정보를 모르므로 ARP 응답 할 수 없어야 함
4) 하지만 Calico 인터페이스는 link-local 타입(내부 브로드캐스트 학습)으로써 HOST 가 BIRD 에 의해 학습한 Worker 의 라우팅 정보를 알고 있음
5) Controller의 Calico 인터페이스는 vRouter에 설정된 ARP_Proxy 기능을 활용하여 Worker 의 ARP 응답을 대신 해 줌
6) BIRD는 Tunl0 --> Host 의 실제 인터페이스를 통해 상대 노드와 Pod 정보를 추가한 캡슐화 된 패킷으로 통신
7) 그림에는 보이지 않지만 만약 다른 노드와 통신이 아닌 퍼블릭 대역과 통신을 한다면  
Felix 를 통한 SNAT ( MASQUERADE ) 를 설정하여 tunl0 을 거치지 않고 HOST 의 ens33 으로 바로 연결.

Packet Check

# 다른 네트워크 ( Controllor POD <---> Worker POD ) 간 Ping 체크를 진행한다

$ kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP                NODE              NOMINATED NODE   READINESS GATES
hello-776c774f98-894tt   1/1     Running   0          13d   192.168.153.193   user-worker       <none>           <none>
hi                       1/1     Running   0          13d   192.168.136.5     user-controller   <none>           <none>

# Worker POD --> Container POD. 컨테이너에 Ping 명령이 없어 Pod 밖의 Host 에서 컨테이너 PID 를 따서 진행했다. 
$ sudo nsenter -t 225201 -n ping 192.168.136.5
64 bytes from 192.168.136.5: icmp_seq=627 ttl=62 time=0.709 ms
64 bytes from 192.168.136.5: icmp_seq=628 ttl=62 time=0.675 ms
64 bytes from 192.168.136.5: icmp_seq=629 ttl=62 time=0.727 ms
64 bytes from 192.168.136.5: icmp_seq=630 ttl=62 time=0.797 ms
64 bytes from 192.168.136.5: icmp_seq=631 ttl=62 time=0.887 ms

# Controller 에서 패킷 캡쳐를 한다. IPIP 구조는 API 공인 인터페이스를 통해 터널링하므로, API 인터페이스든 터널링 인터페이스든 상관없다.
$ sudo tcpdump -i enp0s8 -nn proto 4 -w test.pcap 

# Wireshark 로 확인한다.
1) 두 POD IP의 다른 네트워트 간 정상 ICMP 통신을 하고 있는 부분을 확인할 수 있다.
   

2) MAC 확인시 Controller 와 Worker Node 의 API 공인IP 인터페이스 간 통신임을 확인했다.
# Controller 
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:39:ce:bd brd ff:ff:ff:ff:ff:ff
    inet 203.248.23.214/25 brd 203.248.23.255 scope global enp0s8

# Worker
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:bc:85:3a brd ff:ff:ff:ff:ff:ff
    inet 203.248.23.215/25 brd 203.248.23.255 scope global enp0s8

3) IPv4 Protocol 확인 시 2개의 헤더를 확인할 수 있다. 
# 공인망의 Outer IP 와 POD 네트워크인 Inner IP 2개를 확인할 수 있다.


Outer IP 헤더가 InnerIP 를 밖에서 캡슐로 감싼 IP-IP Protocol 임을 확인할 수 있다.



4) Messages 에서 통신에 정상 문제가 없음을 확인했다.

참고자료

Network Overlay : https://ikcoo.tistory.com/117
image_print
카테고리: Kubernetes

호스트웨이 시스템 팀

호스트웨이 시스템1팀