이전까지 linux에서 network namespace를 만들고, 설정하는 방법과 docker에서 network namespace를 만들어 container에 할당하고 network를 구성하는 방법에 대해서 배웠다.
docker container가 만들어지고 network를 설정하는 부분에 대한 정리를 해보면 다음과 같다.
이러한 동작은 docker도 rkt, mesos, kubernetes 모두 똑같이 동작해야하는 부분이다.
그렇다면 누군가 이 부분에 대해서 표준을 만들어줬으면 좋을 것이다. 또한, 누군가 표준대로 구현한 plugin을 구현하여 container runtime이 container network를 구성할 때, plugin을 사용해 공통화된 방법으로 container network를 구성하고 싶다.
사용하는 측에서는 표준 인터페이스를 기준으로 사용하기만 하면 되기 때문이다.
이것이 바로 'CNI(Container Network Interface)'이다. CNI는 container runtime이 container network를 어떻게 구성하는 가에 대한 표준 집합이다. 즉, 프로그램을 어떻게 정의해야하는 지에 대한 스펙인 것이다.
이렇게 CNI를 준수하여 container network를 구성해주는 tool을 하나의 CNI plugin이라고 한다.
CNI는 CNI plugin들이 어떻게 개발되어야 하는 지 정의하고, container runtime이 어떻게 CNI plugin을 사용해서 container network를 구성해야하는 지 정의한다.
CNI는 다음과 같은 spec들이 있기 때문에 CNI plugin들이 이를 반드시 지켜야한다.
CNI plugin은 또한, 이러한 add, del, check와 같은 command line을 제공하고 지정된 argument들을 제공해야하며, container id, network ns 등을 파라미터로 받아야 한다.
CNI plugin은 pod에 IP를 할당하는 방법, container에 필요한 routes를 설정해 같은 network 내에 있는 다른 container에 접근할 수 있도록 하는 방법들을 구현해놓아야 한다.
container runtime과 plugin이 해당 spec들을 같이지켜 같이 동작하는 것이다.
CNI에는 여러 plugin들이 지원되는데, Bridge, VLAN, IP VLAN, MAC VLAN, Window VLAN 등이 있다.
많이 사용되는 것으로 flannel, calico, cilium 등이 있다.
문제는 docker는 CNI를 지키지 않고 'CNM(container network model)'을 지킨다. 이는 또 다른 표준으로 CNI와 유사하지만 컨테이너 네트워킹 과제를 해결하는 것을 목표로 하고 있다.
때문에 CNI와 docker가 통합되지 않기 때문에 docker를 CNI plugin으로 쓸수가 없다.
kubernetes의 경우는 docker container를 생성할 때, none network로 생성한다. 그런 다음 CNI plugin을 호출하여 구성하도록 하는데, CNI의 구성은 누가 담당하고 호출하는 지에 대해서 알아보도록 하자.
kubernetes는 여러 node들로 이루어져 있는데, 각 node마다 하나씩 interface를 가지고 있다.
192.168 192.168 192.168
.1.10 1.11 1.12
---M--- ---W--- ---W---
| | | | | |
| | | | | |
--eth0- -eth0-- --eth0-
| | |
--------Network--------
| 192.168.1.0 |
-----------------------
각 node들은 각자의 IP를 독자적으로 갖고 있고, network interface를 통해서 network에 접속해있을 수 있다.
이제 각각의 node들은 자신의 node에 배포된 service들을 port로 열어두어야 하는데, 가령 kube-apiserver
는 6443
으로 열려야한다.
이를 정리하면 다음과 같다.
참고로 kubelet은 Master node에서도 사용이 가능하다.
service는 pod의 service로 30000~32767까지 port를 사용할 수 있다. 필요한 경우 port range를 더 열어둘 수도 있다.
이러한 kubernetes component들 중 하나라도 제대로 port가 열려있지 않는다면, kubernetes cluster 자체가 제대로 동작하지 않을 수 있다. 따라서 다음의 명령어들을 외워두도록 하자.
ifconfig
ip link
ip addr
ip addr add 192.168.1.10/24 dev eth0
ip route
ip route add 192.168.1.0/24 via 192.168.2.1
cat /proc/sys/net/ipv4/ip_forward
arp
netstat -plnt
route
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
controlplane Ready control-plane 7m8s v1.30.0 192.33.114.3 <none> Ubuntu 22.04.4 LTS 5.4.0-1106-gcp containerd://1.6.26
node01 Ready <none> 6m19s v1.30.0 192.33.114.6 <none> Ubuntu 22.04.4 LTS 5.4.0-1106-gcp containerd://1.6.26
node01
에서의 internal IP는 192.33.114.6
이다.
node01
의 경우 먼저 ssh에 들어가면 된다.ssh 192.33.114.6
ip link show eth0
10891: eth0@if10892: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP mode DEFAULT group default
link/ether 02:42:c0:21:72:06 brd ff:ff:ff:ff:ff:ff link-netnsid 0
02:42:c0:21:72:06
이다.
containerd
에 의해서 생성된 interface/bridge가 무엇인가??ip link
...
3: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue state UP mode DEFAULT group default qlen 1000
...
cni0
이다.
cni0
의 상태는?ip link
3: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue state UP mode DEFAULT group default qlen 1000
UP
이다.
ip route
default via 172.25.0.1 dev eth1
10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink
172.25.0.0/24 dev eth1 proto kernel scope link src 172.25.0.88
192.33.114.0/24 dev eth0 proto kernel scope link src 192.33.114.3
google과 같은 public network는 default DNS를 지난다. default
는 172.25.0.1
을 통해서 라우팅된다.
kube-scheduler
는 controlplane에서 어떤 port로 열려있는가?netstat -plnt | grep kube-scheduler
tcp 0 0 127.0.0.1:10259 0.0.0.0:* LISTEN 3765/kube-scheduler
10259
이다.
netstat -anp | grep etcd
N 3815/etcd
tcp 0 0 127.0.0.1:2379 0.0.0.0:* LISTEN 3815/etcd
tcp 0 0 192.33.114.3:2380 0.0.0.0:* LISTEN 3815/etcd
tcp 0 0 127.0.0.1:2381 0.0.0.0:* LISTEN 3815/etcd
tcp 0 0 127.0.0.1:2379 127.0.0.1:53136 ESTABLISHED 3815/etcd
tcp 0 0 127.0.0.1:2379 127.0.0.1:53302 ESTA
...
BLISHED 3815/etcd
tcp 0 0 127.0.0.1:2379 127.0.0.1:53458 ESTA
2379
port가 많이 열려있는 것을 볼 수 있다.
왜냐하면 2379
는 모든 control plane component들이 연결되는 port이기 때문이다. 반면에 2380
이는 etcd에 peer-to-peer로 연결되기 때문에 얼마 없다.