실습 환경은 K8S v1.22.6, 노드 OS(Ubuntu 20.04.3 LTS) , CNI(Calico v3.21.4, IPIP, NAT enable) , IPTABLES proxy mode / 회사 내부 라우터는 Quagga 로 구성
참고 : w3만 대역이 다름 => OverayNetwork 확인을 위해
Calico is an open source networking and network security solution for containers, virtual machines, and native host-based workloads. Calico supports a broad range of platforms including Kubernetes, OpenShift, Mirantis Kubernetes Engine (MKE), OpenStack, and bare metal services.
Calico is an open source networking and network security solution for containers, virtual machines, and native host-based workloads. Calico supports a broad range of platforms including Kubernetes, OpenShift, Mirantis Kubernetes Engine (MKE), OpenStack, and bare metal services.
칼리코 다양한 컴포넌트로 구성되어있다. 그 중에서 대표적으로 사용되는 컴포넌트는 다음과 같다.
Felix (필릭스) : 인터페이스 관리, 라우팅 정보 관리, ACL 관리, 상태 체크
BIRD (버드): BGP Peer 에 라우팅 정보 전파 및 수신, BGP RR(Route Reflector)
Confd : calico global 설정과 BGP 설정 변경 시(트리거) BIRD 에 적용해줌. config 설정값이 자동으로 트리거되어 반영됨.
Dikasted : Enforces network policy for Istio service mesh. Runs on a cluster as a sidecar proxy to Istio Envoy.
Calico CNI Plugin : k8s 에 calico 네트워킹 환경을 제공
Datastore plugin : calico 설정 정보를 저장하는 곳 - k8s API datastore(kdd) 혹은 etcd 중 선택
Calico IPAM plugin : 클러스터 내에서 파드에 할당할 IP 대역
calico-kube-controllers : calico 동작 관련 감시(watch)
Typha : Datastore 와 felix, confd 다수간 연결하지 않고 Datastore 는 단일 Typha(중계자 역할) 로 연결, Typha 는 상태 캐시 및 이벤트 중복 제거 등으로 대규모 환경에서 부하를 감소 할 수 있음, 기본적으로 설치는 되지만 설정 구성되어 있지 않음
calicoctl : calico 오브젝트를 CRUD 할 수 있다, 즉 datastore 접근 가능
❓ 참고 : k8s API datastore(kdd) 와 ETCD 비교
BGP로 Pod IP 대역 정보 전파한다.
특히, 쿠버네티스 내부의 기능 뿐만 아니라 물리적인 Router 장비와 연동해서 사용이 가능하다.
<이미지 출처 : 가시다님 노션>
데몬셋으로 각 노드에 calico-node 파드가 동작하여, 해당 파드에 bird, felix, confd 등이 동작 + Calico 컨트롤러 파드는 디플로이먼트로 생성
calicoctl version
Client Version: v3.21.4
Git commit: 220d04c94
Cluster Version: v3.21.4
Cluster Type: k8s,bgp,kubeadm,kdd
#### (내용이 누락되어 저장된 관계로 다시작성 예정)
❓ Quiz. 바로 위 Calico IPAM 과 아래 출력되는 IPAM 의 차이는 무엇일까요? 우선순위 확인 - 링크 , Flannel 과 차이
- 별도의 IPAM 이 있다면 무엇을 할 수 있을까요? (예. 특정 파드/네임스페이스에 파드의 네트워크 대역을 추가 및 삭제)
- Kubernetes annotations
- CNI configuration (Calico IPAM)
- IP pool node selectors
🤔 요약 : 쿠버네티스를 설치하면 기본적으로 Host Local IPAM이 동작한다.(각 노드별로 podCIDR을 할당) 하지만, Calico에서는 별도의 IPAM이 할당된다. 대다수의 CNI는 Pod의 IP를 별도로 관리하기 위한 IPAM 사용한다.
(추가) : Flannel은 호스트의 IPAM 기능을 사용하지만(전용 IPAM기능이 없음) 다른 CNI(Calico 등)는 별도의 IPAM 대역을 할당한다.
즉, 심플하고 아주 간단한 CNI!
tree /etc/cni/net.d/
/etc/cni/net.d/
├── 10-calico.conflist
└── calico-kubeconfig
cat /etc/cni/net.d/10-calico.conflist
...
"datastore_type": "kubernetes",
"ipam": {
"type": "calico-ipam"
},
...
calicoctl get workloadEndpoint -A
kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}' ;echo
ps axf
❗ 결론 : 동일 노드 내의 파드 간 통신은 내부에서 직접 통신됨
root@k8s-w1:~# ip -c -d addr show tunl0
5: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0 promiscuity 0 minmtu 0 maxmtu 0
ipip any remote any local any ttl inherit nopmtudisc numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
inet 172.16.158.0/32 scope global tunl0
valid_lft forever preferred_lft forever
root@k8s-w1:~# lsns -t net
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026531992 net 126 1 root unassigned /run/docker/netns/default /sbin/init
이중 bird 는 bird 데몬이 BGP 라우팅 프로토콜에 의해 파드 네트워크 대역을 전달받거나 전달하는 경로 → 각각 노드의 파드 대역입니다
root@k8s-w1:~# ip -c route | grep bird
blackhole 172.16.158.0/24 proto bird
172.16.34.0/24 via 192.168.20.100 dev tunl0 proto bird onlink
172.16.116.0/24 via 192.168.10.10 dev tunl0 proto bird onlink
172.16.184.0/24 via 192.168.10.102 dev tunl0 proto bird onlink
🖊 요약 :
172.x
대역이192.x
대역으로 통신하도록 BIRD에 의해서 BGP 프로코콜을 통해 상대방 podCIRD을 학습
❓ Quiz. blackhole 라우팅은 왜 있을까요?
정답 : 루핑방지(?)
curl -LO https://raw.githubusercontent.com/gasida/NDKS/main/4/node1-pod2.yaml
kubectl apply -f node1-pod2.yaml
(calico-k8s:default) root@k8s-m:~# k get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod1 1/1 Running 0 82s 172.16.158.1 k8s-w1 <none> <none>
pod2 1/1 Running 0 82s 172.16.158.2 k8s-w1 <none> <none>
노드에서 실행)
# iptables 필터 테이블에 FORWARD 리스트 중 cali-FORWARD 룰 정보를 필터링해서 watch 로 확인
watch -d -n 1 "iptables -v --numeric --table filter --list FORWARD | egrep '(cali-FORWARD|pkts)'"
파드1에서 실행)
# pod1 -> pod2 ping 통신
ping -c 1 172.16.158.2
즉, cali-FORWARD 라고하는 체인 룰에의해 pod간 통신이 가능 => Clico 컴포넌트에서 iptables Rule을 조작해준다.
# (마스터노드) 파드 연결된 veth 를 변수를 확인
VETH1=$(calicoctl get workloadEndpoint | grep pod1 | awk '{print $4}')
echo $VETH1
VETH2=$(calicoctl get workloadEndpoint | grep pod2 | awk '{print $4}')
echo $VETH2
# (워커노드1) 위에서 확인한 파드 연결된 veth 를 변수에 지정
VETH1=calice0906292e2
VETH2=calibd2348b4f67
# 파드1 혹은 파드2에 veth 로 연결된 호스트 네트워크 인터페이스 calice# 중 1개 선택해서 tcpdump
tcpdump -i $VETH1 -nn
tcpdump -i $VETH2 -nn
# 노드1 calice# 인터페이스의 proxy arp 설정 확인
# cat /proc/sys/net/ipv4/conf/<자신의 pod1에 연결된 calice# 이름>/proxy_arp
cat /proc/sys/net/ipv4/conf/$VETH1/proxy_arp
cat /proc/sys/net/ipv4/conf/$VETH2/proxy_arp
root@k8s-w1:~# cat /proc/sys/net/ipv4/conf/calice0906292e2/proxy_arp
1
root@k8s-w1:~# cat /proc/sys/net/ipv4/conf/calibd2348b4f67/proxy_arp
1
🖊 요약 : calico 의 파드와 peer 로 연결된 veth cali# 인터페이스에 반드시 proxy_arp = 1 로 활성화가 필요하다.
❗ 결론 : 파드에서 외부(인터넷) 통신 시에는 해당 노드의 네트워크 인터페이스 IP 주소로 MASQUERADE(출발지 IP가 변경) 되어서 외부에 연결됨
natOutgoing: true
이다. 즉, iptables 에 MASQUERADE Rule(룰) 에 의해서 외부에 연결됨(calico-k8s:default) root@k8s-m:~# 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()
✔ 참고 : EKS에서 NAT 활성/비활성 기능과 동일. NAT를 비활성화 시키고 Network 팀에서 관리하는 장비를 통해서 관리할 수도 있음
root@k8s-w1:~# 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
😁 참고 : The right way to check the weather - 링크
curl wttr.in/seoul curl 'wttr.in/seoul?format=3' curl 'wttr.in/busan?format=3' curl v3.wttr.in/Seoul.sxl curl wttr.in/Moon curl wttr.in/:help
natOutgoing: false
로 변경# 마스터노드에서 calico ippools 에서 nat 설정 변경
calicoctl get ippool default-ipv4-ippool -o yaml | sed -e "s/natOutgoing: true/natOutgoing: false/" | calicoctl apply -f -
❗ 결론 : 다른 노드 환경에서 파드 간 통신 시에는 IPIP 터널(기본값) 모드를 통해서 이루어 집니다
# 터널 인터페이스에 IP가 할당되어 있고, MTU는 1480(IP헤더 20바이트 추가를 고려)을 사용하며, 현재 TX/RX 카운트는 0 이다
# Calico 사용 시 파드의 인터페이스도 기본 MTU 1480 을 사용한다
ifconfig tunl0
root@k8s-w1:~# ifconfig tunl0
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 172.16.158.0 netmask 255.255.255.255
tunnel txqueuelen 1000 (IPIP Tunnel)
RX packets 48 bytes 7227 (7.2 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 49 bytes 3343 (3.3 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
root@k8s-w2:~# ifconfig tunl0
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 172.16.184.0 netmask 255.255.255.255
tunnel txqueuelen 1000 (IPIP Tunnel)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
(calico-k8s:default) root@k8s-m:~# curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/4/node2-pod2.yaml
kubectl apply -f node2-pod2.yaml
pod/pod1 created
pod/pod2 created
(calico-k8s:default) root@k8s-m:~# calicoctl get workloadendpoints
WORKLOAD NODE NETWORKS INTERFACE
pod1 k8s-w1 172.16.158.4/32 calice0906292e2
pod2 k8s-w2 172.16.184.1/32 calibd2348b4f67
root@k8s-w1:~# route -n | head -2 ; route -n | grep 172.16.
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
...
172.16.184.0 192.168.10.102 255.255.255.0 UG 0 0 0 tunl0
root@k8s-w2:~# route -n | head -2 ; route -n | grep 172.16.
Kernel IP routing table
...
Destination Gateway Genmask Flags Metric Ref Use Iface
172.16.158.0 192.168.10.101 255.255.255.0 UG 0 0 0 tunl0
# k8s-w1
# 패킷 덤프 : tunl0 - 터널 인터페이스에 파드간 IP 패킷 정보 확인!
root@k8s-w1:~# tcpdump -i tunl0 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tunl0, link-type RAW (Raw IP), capture size 262144 bytes
07:42:40.800707 IP 172.16.158.4 > 172.16.184.1: ICMP echo request, id 41434, seq 1, length 64
07:42:40.802513 IP 172.16.184.1 > 172.16.158.4: ICMP echo reply, id 41434, seq 1, length 64
07:42:41.802181 IP 172.16.158.4 > 172.16.184.1: ICMP echo request, id 41434, seq 2, length 64
07:42:41.803339 IP 172.16.184.1 > 172.16.158.4: ICMP echo reply, id 41434, seq 2, length 64
07:42:42.802875 IP 172.16.158.4 > 172.16.184.1: ICMP echo request, id 41434, seq 3, length 64
07:42:42.803880 IP 172.16.184.1 > 172.16.158.4: ICMP echo reply, id 41434, seq 3, length 64
# k8s-w2
# tunl0 인터페이스 TX/RX 패킷 카운트 모니터링 확인 : TX/RX 패킷 카운트가 각각 10개로 증가했다
root@k8s-w2:~# watch -d 'ifconfig tunl0 | head -2 ; ifconfig tunl0 | grep bytes'
Every 2.0s: ifconfig tunl0 | head -2 ; ifconfig tunl0 | grep bytes k8s-w2: Sat Feb 5 07:44:37 2022
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 172.16.184.0 netmask 255.255.255.255
RX packets 10 bytes 840 (840.0 B)
TX packets 10 bytes 840 (840.0 B)
Every 2.0s: ifconfig tunl0 | head -2 ; ifconfig tunl0 | grep bytes k8s-w2: Sat Feb 5 07:44:41 2022
root@k8s-w1:~# tcpdump -i enp0s8 -nn proto 4
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s8, link-type EN10MB (Ethernet), capture size 262144 bytes
07:49:08.954221 IP 192.168.10.101 > 192.168.10.102: IP 172.16.158.4 > 172.16.184.1: ICMP echo request, id 61463, seq 1, length 64 (ipip-proto-4)
07:49:08.955571 IP 192.168.10.102 > 192.168.10.101: IP 172.16.184.1 > 172.16.158.4: ICMP echo reply, id 61463, seq 1, length 64 (ipip-proto-4)
07:49:09.955240 IP 192.168.10.101 > 192.168.10.102: IP 172.16.158.4 > 172.16.184.1: ICMP echo request, id 61463, seq 2, length 64 (ipip-proto-4)
07:49:09.956057 IP 192.168.10.102 > 192.168.10.101: IP 172.16.184.1 > 172.16.158.4: ICMP echo reply, id 61463, seq 2, length 64 (ipip-proto-4)
07:49:10.956993 IP 192.168.10.101 > 192.168.10.102: IP 172.16.158.4 > 172.16.184.1: ICMP echo request, id 61463, seq 3, length 64 (ipip-proto-4)
07:49:10.958197 IP 192.168.10.102 > 192.168.10.101: IP 172.16.184.1 > 172.16.158.4: ICMP echo reply, id 61463, seq 3, length 64 (ipip-proto-4)
...
tcpdump -i enp0s8 -nn proto 4 -w /tmp/calico-ipip.pcap
패킷 캡처결과 Outer IP 헤더에서는 IPIP 프로토콜로 통신을 하는 것을 알 수 있었고, Inner IP 헤더에서는 실제 ICMP 프로토콜을 통해 정보가 전달된 것을 알 수 있었다.
즉, 실제 Pod가 다른 노드에 통신(Overay)할 때 Outer IP 헤더를 감싸서 노드의 IP 주소로 NAT되어 통신된 것을 알 수있었다.
3주차 1편에서는 Calico CNI에 대한 특/장점에 대해서 알아보았고, 기본적인 통신에 대핸 이해를 할 수 있었다.
작성하다보니 그동안 궁금했던 IPAM에 대한 설명이나 Overay Network에 대한 이해를 할 수 있는 시간이었다.
또한, Calico를 구성하고 있는 각종 컴포넌트의 역할에 대해서도 확실히 숙지할 수 있었다.
다음 2편에서는 Calico CNI에서 제공하는 각종 Mode에 대해서 알아볼 예정이다.
안녕하세요 kubernetes calico 통신 해보려는데
저는 다른 워커노드에있는 파드끼리의 통신이 되지 않습니다 ㅜㅜ 혹시 이유가 뭔지 알 수 있을까요?
Centos7 ncloud에서 kubespray로 배포했습니다!
글 중 ip protocol 4 허용 << 이 부분은 어떤 걸 말하는 걸까요?