Calico
Calico 는 쿠버네티스에서 사용 가능한 CNI 중 하나이며, IPIP, VXLAN, Direc와 같은 다양한 모드를 제공합니다. 현업에서 사용중인 CSP인 Google Cloud에서는 Google Kubernetes Engine 사용시 dataplane v2에 대한 옵션을 활성화지 않는 경우 dataplane v1으로 생성되며, Google 문서에 따르면 dataplan v1은 Calico로 구성된다고 되어있습니다. 참고로, dataplane v2는 Cilium입니다.
현재 현업에서 운영중인 GKE들은 dataplane v1(Calico)로 운영하고 있으며, Cilium의 버전변경을 모니터링하고, 문서 업데이트 속도를 확인하여 최근에 생성하는 GKE부터는 Dataplane v2(Cilium)으로 생성 및 테스트를 진행하고 있습니다. 물론, 이 부분은 Standard 타입의 클러스터에 한해서 운영하고 있으며, Composer(Airflow PaaS)의 경우에는 Composer v2버전이 GKE Autopilot으로 구성되기 때문에, Dataplane v2로 기본 구성이 되어있습니다. 쿠버네티스 네트워크 스터디가 종료될 시점에는 Dataplane v2에서의 테스트/운영에 대한 이야기도 작성해 보도록 하겠습니다.
아래에 나오는 명령어 및 출력물은 현업에서 운영되는 GKE에서는 PaaS로 Control Plane에 접근이 불가능하기 때문에, 스터디에서 제공받은 스크립트를 통한 VirtualBox와 Vagrant로 구성된 VM으로 구성하여 테스트 되었습니다.
Calico 구성요소
calicoctl
Calico를 제어하는 CMD 툴로써 kubectl로 하는것보다는 손쉽게 사용가능합니다.
calico 저장소
K8s API 저장소 내에 저장됩니다.
calico-node
K8s node에 daemonset으로 1개씩 구성되며, 3가지 요소인 BIRD, Felix, confd가 있습니다.
- BIRD: OSS 라우팅 프로그램으로 노드내 POD 대역을 BGP를 통해 광고합니다.
- Felix: BIRD의 노드내 POD 대역에 대한 라우팅 테이블을 제어합니다.
- confd: calico의 설정파일을 관리합니다.
Calico 설치
구성 정보 확인
노드 정보 확인
k get nodes -A -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-m Ready control-plane 12m v1.30.5 192.168.10.10 <none> Ubuntu 22.04.5 LTS 5.15.0-119-generic containerd://1.7.22
k8s-w0 Ready <none> 10m v1.30.5 192.168.20.100 <none> Ubuntu 22.04.5 LTS 5.15.0-119-generic containerd://1.7.22
k8s-w1 Ready <none> 8m44s v1.30.5 192.168.10.101 <none> Ubuntu 22.04.5 LTS 5.15.0-119-generic containerd://1.7.22
k8s-w2 Ready <none> 6m49s v1.30.5 192.168.10.102 <none> Ubuntu 22.04.5 LTS 5.15.0-119-generic containerd://1.7.22
calico 구성요소 배포 확인
k get pod -n kube-system -l k8s-app=calico-node -owide
출력 확인시 calico-node 의 ip는 노드가 사용하는 host ip를 사용한다.
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
calico-node-5xtr7 1/1 Running 0 4m15s 192.168.10.102 k8s-w2 <none> <none>
calico-node-72mx5 1/1 Running 0 4m15s 192.168.10.101 k8s-w1 <none> <none>
calico-node-tqggs 1/1 Running 0 4m15s 192.168.20.100 k8s-w0 <none> <none>
calico-node-wlwfr 1/1 Running 0 4m15s 192.168.10.10 k8s-m <none> <none>
POD 생성시 Calico CNI를 통해 배치받는 IP 대역정보 확인
calicoctl ipam show
+----------+---------------+-----------+------------+--------------+
| GROUPING | CIDR | IPS TOTAL | IPS IN USE | IPS FREE |
+----------+---------------+-----------+------------+--------------+
| IP Pool | 172.16.0.0/16 | 65536 | 7 (0%) | 65529 (100%) |
+----------+---------------+-----------+------------+--------------+
블록 할당 정보 확인
calicoctl opsm show --show-blocks
+----------+-----------------+-----------+------------+--------------+
| GROUPING | CIDR | IPS TOTAL | IPS IN USE | IPS FREE |
+----------+-----------------+-----------+------------+--------------+
| IP Pool | 172.16.0.0/16 | 65536 | 7 (0%) | 65529 (100%) |
| Block | 172.16.116.0/24 | 256 | 1 (0%) | 255 (100%) |
| Block | 172.16.158.0/24 | 256 | 4 (2%) | 252 (98%) |
| Block | 172.16.184.0/24 | 256 | 1 (0%) | 255 (100%) |
| Block | 172.16.34.0/24 | 256 | 1 (0%) | 255 (100%) |
+----------+-----------------+-----------+------------+--------------+
calico 설정 정보
calicoctl ipam show --show-configuration
+--------------------+-------+
| PROPERTY | VALUE |
+--------------------+-------+
| StrictAffinity | false | -> true시 할당된 블록에서만 사용, false시 다른노드에서 ip 사용가능
| AutoAllocateBlocks | true |
| MaxBlocksPerHost | 0 |
+--------------------+-------+
calico node 연결 정보
calicoctl node status
Calico process is running.
IPv4 BGP status
+----------------+-------------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+----------------+-------------------+-------+----------+-------------+
| 192.168.20.100 | node-to-node mesh | up | 07:39:33 | Established |
| 192.168.10.101 | node-to-node mesh | up | 07:39:32 | Established |
| 192.168.10.102 | node-to-node mesh | up | 07:39:32 | Established |
+----------------+-------------------+-------+----------+-------------+
IPv6 BGP status
No IPv6 peers found.
k8s에서 사용하는 ip 대역 정보와 calico 모드 확인
calicoctl get ippool -o wide
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR
default-ipv4-ippool 172.16.0.0/16 true Always Never false false all()
Calico에서의 POD의 통신 이해
- POD - Internet: POD가 위치한 Node의 IP로 MASQUERADE로 IP 변경이되어 외부와의 통신이 됩니다.
- POD - POD(같은 노드): 같은 노드 내 POD간 통신은 Node 내부에서 직접 통신됩니다.
- POD - POD(다른 노드): 별도의 설정을 하지 않았다면 IPIP모드로 다른 노드간 통신이 됩니다.
POD - Internet
NAT가 true로 활성화 되어있습니다.
calicoctl get ippool -o wide
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR
default-ipv4-ippool 172.16.0.0/16 true Always Never false false all()
iptables 확인
iptables -n -t nat --list cali-nat-outgoing
Chain cali-nat-outgoing (1 references)
target prot opt source destination
MASQUERADE all -- 0.0.0.0/0 0.0.0.0/0 /* cali:flqWnvo8yq4ULQLa */ match-set cali40masq-ipam-pools src ! match-set cali40all-ipam-pools dst random-fully
masq 확인
ipset list cali40masq-ipam-pools
Name: cali40masq-ipam-pools
Type: hash:net
Revision: 7
Header: family inet hashsize 1024 maxelem 1048576 bucketsize 12 initval 0xd577ac3b
Size in memory: 504
References: 1
Number of entries: 1
Members:
172.16.0.0/16
POD - POD (같은 노드)간 통신
cat << EOF | k apply -f -
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
nodeName: k8s-w1
containers:
- name: pod1
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
spec:
nodeName: k8s-w1
containers:
- name: pod2
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
pod/pod1 created
pod/pod2 created
calicoctl get workloadEndpoint
WORKLOAD NODE NETWORKS INTERFACE
pod1 k8s-w1 172.16.158.4/32 calice0906292e2
pod2 k8s-w1 172.16.158.6/32 cali3a3e66463d6
ip -c link
10: calice0906292e2@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netns cni-10a1c842-93de-2773-2975-6ad473f9d123
12: cali3a3e66463d6@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netns cni-1c54eb9c-1ee1-84d5-94a8-def5a78476d5
ip -c route
172.16.158.4 dev calice0906292e2 scope link
172.16.158.6 dev cali3a3e66463d6 scope link
POD - POD (다른 노드)간 통신
노드 내 BGP 확인
Worker 0
route | head -2 ; route -n | grep tunl0
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
172.16.116.0 192.168.10.10 255.255.255.0 UG 0 0 0 tunl0
172.16.158.0 192.168.10.101 255.255.255.0 UG 0 0 0 tunl0
172.16.184.0 192.168.10.102 255.255.255.0 UG 0 0 0 tunl0
Worker 1
route | head -2 ; route -n | grep tunl0
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
172.16.34.0 192.168.20.100 255.255.255.0 UG 0 0 0 tunl0
172.16.116.0 192.168.10.10 255.255.255.0 UG 0 0 0 tunl0
172.16.184.0 192.168.10.102 255.255.255.0 UG 0 0 0 tunl0
POD 생성
apiVersion: v1
kind: Pod
metadata:
name: pod0
spec:
nodeName: k8s-w0
containers:
- name: pod0
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
nodeName: k8s-w1
containers:
- name: pod1
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
pod endpoint 확인
calicoctl get workloadendpoints
WORKLOAD NODE NETWORKS INTERFACE
pod0 k8s-w0 172.16.34.2/32 cali7ac1b8e1615
pod1 k8s-w1 172.16.158.9/32 calice0906292e2
node 간 라우팅 확인
Worker 0
route -n | head -2 ; route -n | grep 172.16.
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
172.16.34.0 0.0.0.0 255.255.255.0 U 0 0 0 *
172.16.34.2 0.0.0.0 255.255.255.255 UH 0 0 0 cali7ac1b8e1615
172.16.116.0 192.168.10.10 255.255.255.0 UG 0 0 0 tunl0
172.16.158.0 192.168.10.101 255.255.255.0 UG 0 0 0 tunl0
172.16.184.0 192.168.10.102 255.255.255.0 UG 0 0 0 tunl0
Worker 1
route -n | head -2 ; route -n | grep 172.16.
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
172.16.34.0 192.168.20.100 255.255.255.0 UG 0 0 0 tunl0
172.16.116.0 192.168.10.10 255.255.255.0 UG 0 0 0 tunl0
172.16.158.0 0.0.0.0 255.255.255.0 U 0 0 0 *
172.16.158.1 0.0.0.0 255.255.255.255 UH 0 0 0 cali8e446144959
172.16.158.2 0.0.0.0 255.255.255.255 UH 0 0 0 calie37aee99def
172.16.158.3 0.0.0.0 255.255.255.255 UH 0 0 0 cali7245e7a0fea
172.16.158.9 0.0.0.0 255.255.255.255 UH 0 0 0 calice0906292e2
172.16.184.0 192.168.10.102 255.255.255.0 UG 0 0 0 tunl0
PING을 통한 패킷 카운트 확인
POD 1 -> POD 0
Worker 0
ifconfig tunl0 | head -2 ; ifconfig tunl0 | grep bytes
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 172.16.34.0 netmask 255.255.255.255
RX packets 10 bytes 840 (840.0 B)
TX packets 10 bytes 840 (840.0 B)
Worker 1
ifconfig tunl0 | head -2 ; ifconfig tunl0 | grep bytes
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 172.16.158.0 netmask 255.255.255.255
RX packets 10 bytes 840 (840.0 B)
TX packets 10 bytes 840 (840.0 B)
Calico의 여러 모드
- IPIP: Calico 기본모드이며, IPIP 인캡슐레이션으로 이루어짐
- Direct: 원본패킷이 목적지로 원본 그대로 전달됨
- CrossSubnet: 노드간 같은 네트워크에서는 Direct, 노드간 다른 네트워크에서는 IPIP모드로 동작
- VXLAN: vxlan 인캡슐래이션을 통해 통신이 됨
IPIP 모드 : POD - POD(다른 노드)에서 IPIP 내용 참조
Direct 모드
현재 모드 확인
calicoctl get ippool -o wide
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR
default-ipv4-ippool 172.16.0.0/16 true Always Never false false all()
calicoctl get ippool default-ipv4-ippool -o yaml
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
creationTimestamp: "2024-09-21T07:39:23Z"
name: default-ipv4-ippool
resourceVersion: "1487"
uid: d105e1a3-a1d6-4c6b-a9d6-a88739b8fca6
spec:
allowedUses:
- Workload
- Tunnel
blockSize: 24
cidr: 172.16.0.0/16
ipipMode: Always
natOutgoing: true
nodeSelector: all()
vxlanMode: Never
모드 변경
calicoctl get ippool default-ipv4-ippool -o yaml | sed -e "s/ipipMode: Always/ipipMode: Never/" | calicoctl apply -f -
변경 확인
calicoctl get ippool -o wide
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR
default-ipv4-ippool 172.16.0.0/16 true Never Never false false all()
Worker 확인
기존에는 tunl0 인터페이스를 사용했지만, host의 인터페이스로 변경 확인
route -n | head -2 ; route -n | grep 172.16.
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
172.16.34.0 192.168.20.100 255.255.255.0 UG 0 0 0 tunl0
172.16.116.0 192.168.10.10 255.255.255.0 UG 0 0 0 tunl0
172.16.158.0 192.168.10.101 255.255.255.0 UG 0 0 0 tunl0
172.16.184.0 0.0.0.0 255.255.255.0 U 0 0 0 *
root@k8s-w2:~# route -n | egrep '(Destination|UG)'
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.0.2.2 0.0.0.0 UG 100 0 0 enp0s3
172.16.34.0 192.168.10.254 255.255.255.0 UG 0 0 0 enp0s8
172.16.116.0 192.168.10.10 255.255.255.0 UG 0 0 0 enp0s8
172.16.158.0 192.168.10.101 255.255.255.0 UG 0 0 0 enp0s8
192.168.20.0 192.168.10.254 255.255.255.0 UG 0 0 0 enp0s8
CrossSubnet 모드
모드 변경
calicoctl patch ippool default-ipv4-ippool -p '{"spec":{"ipipMode":"CrossSubnet"}}'
변경 확인
calicoctl get ippool -o wide
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR
default-ipv4-ippool 172.16.0.0/16 true CrossSubnet Never false false all()
Worker 확인
노드에 할당된 서브넷이 아니면 tunl0 으로 잡힌다.
Worker1
route -n | egrep '(Destination|UG)'
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.0.2.2 0.0.0.0 UG 100 0 0 enp0s3
172.16.34.0 192.168.20.100 255.255.255.0 UG 0 0 0 tunl0
172.16.116.0 192.168.10.10 255.255.255.0 UG 0 0 0 enp0s8
172.16.184.0 192.168.10.102 255.255.255.0 UG 0 0 0 enp0s8
192.168.20.0 192.168.10.254 255.255.255.0 UG 0 0 0 enp0s8
Worker2
route -n | grep UG
0.0.0.0 10.0.2.2 0.0.0.0 UG 100 0 0 enp0s3
172.16.34.0 192.168.20.100 255.255.255.0 UG 0 0 0 tunl0
172.16.116.0 192.168.10.10 255.255.255.0 UG 0 0 0 enp0s8
172.16.158.0 192.168.10.101 255.255.255.0 UG 0 0 0 enp0s8
192.168.20.0 192.168.10.254 255.255.255.0 UG 0 0 0 enp0s8
VXLAN 모드
모드 변경
calicoctl get ippool default-ipv4-ippool -o yaml | sed -e "s/vxlanMode: Never/vxlanMode: Always/" | calicoctl apply -f -
변경 확인
calicoctl get ippool default-ipv4-ippool -o wide
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR
default-ipv4-ippool 172.16.0.0/16 true Never Always false false all()
calico-node pod 재생성
kubectl delete pod -n kube-system -l k8s-app=calico-node
실습 환경에서 라우팅 테이블 갱신을 위한 인터페이스 down & up
route -n && echo && ip link set enp0s8 down && sleep 1 && ip link set enp0s8 up && route -n
calico 노드 확인
calicoctl node status
Calico process is running.
The BGP backend process (BIRD) is not running.
노드 내 어노테이션 확인
k describe node | grep -A3 An
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: unix:///run/containerd/containerd.sock
node.alpha.kubernetes.io/ttl: 0
projectcalico.org/IPv4Address: 192.168.10.10/24
projectcalico.org/IPv4VXLANTunnelAddr: 172.16.116.2
인터페이스 확인
ip -c link
4: vxlan.calico: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/ether 66:04:03:49:b1:1e brd ff:ff:ff:ff:ff:ff
ip -c nei
10.0.2.2 dev enp0s3 lladdr 52:54:00:12:35:02 REACHABLE
10.0.2.3 dev enp0s3 lladdr 52:54:00:12:35:03 STALE
172.16.34.1 dev cali53ccf54a47b lladdr 32:9b:2c:7d:ca:56 REACHABLE
172.16.158.0 dev vxlan.calico lladdr 66:74:91:32:7c:04 PERMANENT
192.168.20.254 dev enp0s8 lladdr 08:00:27:83:fb:36 REACHABLE
172.16.184.0 dev vxlan.calico lladdr 66:55:c4:6b:81:ed PERMANENT
172.16.116.0 dev vxlan.calico lladdr 66:04:03:49:b1:1e PERMANENT
172.16.34.2 dev calibf28d443af8 lladdr 82:4f:c5:77:4f:a2 REACHABLE
라우팅 테이블 확인
route -n | egrep '(Destination|vxlan)'
Destination Gateway Genmask Flags Metric Ref Use Iface
172.16.116.0 172.16.116.0 255.255.255.0 UG 0 0 0 vxlan.calico
172.16.158.0 172.16.158.0 255.255.255.0 UG 0 0 0 vxlan.calico
172.16.184.0 172.16.184.0 255.255.255.0 UG 0 0 0 vxlan.calico