KANS 스터디 3주차 - Calico CNI 2편
KANS 스터디 3주차 - Calico CNI 2편
개요
지난 Calico CNI 1편에 이어서 작성된 내용이다. 앞서 작성한 1편에서는 Calico CNI의 기본 구조와 통신에 대한 이해를 중점적으로 다루었다.
2편에서는 Calico CNI에서 제공하는 다양한 네트워크 모드에 대해서 분석해보려 한다.
2. Calico 네트워크 모드
💡 요약
- Calico 는 다양한 네트워크 통신 방법(모드)를 제공한다.
- Calico 나 Cilium 에서 파드 혹은 네임스페이스의 레벨에서 IN/OUT 트래픽에 대한 통제가 가능하다.(Network Policy)
0) Calico Mode 요약
💡 요약
- Calico 는 다양한 네트워크 통신 방법(모드)를 제공한다.
- Calico 나 Cilium 에서 파드 혹은 네임스페이스의 레벨에서 IN/OUT 트래픽에 대한 통제가 가능하다.(Network Policy)
Clico에서는 다음과 같은 모드를 제공한다.
- IPIP(기본)
- Direct(권장)
- BGP
- VXLAN
- Pod 패킷 암호화
📢 토론 & 발표 : Calico 를 사용하신다면, 어떤 모드나 기능을 사용하시는지 사례를 알려주세요!
1) IPIP
1) 통신 흐름
💡 요약 : 파드 간 통신이 노드와 노드 구간에서는 IPIP 인캡슐레이션을 통해서 이루어 진다. 1편 참고
- 다른 노드 간의 파드 통신은 tunl0 인터페이스를 통해 IP 헤더에 감싸져서 상대측 노드로 도달 후 tunl0 인터페이스에서 Outer 헤더를 제거하고 내부의 파드와 통신
- 다른 노드의 파드 대역은 BGP로 전달 받아 호스트 라우팅 테이블에 업데이트됨(Bird->Felix->Confd)
2) Direct
성능이 뛰어남(약 20%정도)
1) 통신 흐름
💡 요약 : 파드 통신 패킷이 출발지 노드의 라우팅 정보를 보고 목적지 노드로 원본 패킷 그대로 전달한다.
사전 요구사항 및 참고사항
- 클라우드 사업자 네트워크의 경우 NIC 에 매칭되지 않는 IP 패킷은 차단되니, NIC에 Source/Destination Check 기능을 Disable 해야 한다. - 링크
# AWS CLI 로 특정 인스턴스의 Source/Destination Check 기능을 Disable 하기
aws ec2 modify-instance-attribute --instance-id <INSTANCE_ID> --source-dest-check "{\"Value\": false}"
참고 : 리눅스의 ESB 모드
- Virtualbox 설정 : 노드(VM)에 네트워크 NIC 2 번에
무작위 모드
를모두 허용
설정이 vagrant file 에 의해 되어 있음
2) Direct 모드 설정
Direct 모드 설정 및 확인
- 모드 정보 확인 :
IPIPMODE: Always
이므로Never
로 변경!
(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()
# (옵션) 모니터링
watch -d "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.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
192.168.20.0 192.168.10.254 255.255.255.0 UG 0 0 0 enp0s8
# 설정
(calico-k8s:default) root@k8s-m:~# calicoctl get ippool default-ipv4-ippool -o yaml | sed -e "s/ipipMode: Always/ipipMode: Never/" | calicoctl apply -f -
Successfully applied 1 'IPPool' resource(s)
- Iface가 tunl0에서 enp0s8로 바뀌는 모습
- 변경 확인
# 모드 정보 확인 : IPIPMODE 가 Never 로 변경!
calicoctl get ippool -o wide
root@k8s-m:~/yaml# calicoctl get ippool -o wide
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED SELECTOR
default-ipv4-ippool 172.16.0.0/16 true Never Never false all()
(calico-k8s:default) root@k8s-m:~# 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.158.0 192.168.10.101 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
# calico config 설정 변경 확인
(calico-k8s:default) root@k8s-m:~# calicoctl get ippool default-ipv4-ippool -o yaml
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
creationTimestamp: "2022-02-05T02:27:50Z"
name: default-ipv4-ippool
resourceVersion: "43961"
uid: b529fcb1-7e4c-4a16-b7c9-de6e37c7eea7
spec:
allowedUses:
- Workload
- Tunnel
blockSize: 24
cidr: 172.16.0.0/16
ipipMode: Never
natOutgoing: true
nodeSelector: all()
vxlanMode: Never
결론적으로 터널 인터페이스 IP를 사용하지 않고 물리 인터페이스를 사용해서 통신. 즉, Pod IP를 사용해서 통신이 되는 것을 알 수 있다.
3) 동작 확인
파드생성
# 파드 생성
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/5/node3-pod3.yaml
kubectl apply -f node3-pod3.yaml
pod/pod1 created
pod/pod2 created
pod/pod3 created
# 파드 IP 정보 확인
(calico-k8s:default) root@k8s-m:~# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod1 1/1 Running 0 2m34s 172.16.158.5 k8s-w1 <none> <none>
pod2 1/1 Running 0 2m34s 172.16.184.2 k8s-w2 <none> <none>
pod3 1/1 Running 0 2m34s 172.16.34.1 k8s-w0 <none> <none>
(calico-k8s:default) root@k8s-m:~# calicoctl get workloadEndpoint
WORKLOAD NODE NETWORKS INTERFACE
pod1 k8s-w1 172.16.158.5/32 calice0906292e2
pod2 k8s-w2 172.16.184.2/32 calibd2348b4f67
pod3 k8s-w0 172.16.34.1/32 cali49778cadcf1
파드간 ping 통신 실행 및 패킷 캡쳐 확인
- pod1 shell에서 pod1~3 으로 ping 통신
pod1 ~ ping -c1 172.16.158.5
PING 172.16.158.5 (172.16.158.5) 56(84) bytes of data.
64 bytes from 172.16.158.5: icmp_seq=1 ttl=64 time=0.032 ms
--- 172.16.158.5 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.032/0.032/0.032/0.000 ms
pod1 ~ ping -c1 172.16.184.2
PING 172.16.184.2 (172.16.184.2) 56(84) bytes of data.
64 bytes from 172.16.184.2: icmp_seq=1 ttl=62 time=1.49 ms
--- 172.16.184.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.485/1.485/1.485/0.000 ms
pod1 ~ ping -c1 172.16.34.1
PING 172.16.34.1 (172.16.34.1) 56(84) bytes of data.
^C
--- 172.16.34.1 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
❓ 워커노드1(파드) → 워커노드2(파드) or 워커노드0(파드) 와 통신 확인해보자! 되는 경우 어떻게 되는 걸까? 안되는 경우는 왜일까? ⇒ Overlay 네트워크 기법이 필요한 이유!
(힌트) k8s-w0 에서 route -n 확인 및 k8s-rtr 에서 tcpdump -i any icmp -nn 로 정보 확인해보자!
Pod1에서 Pod2, Pod3으로 통신할 경우 Pod2는 정상적으로 request/reply가 찍히지만, Pod3의 경우에는 request만 찍히는 모습
통신이 안된 이유를 분석해보자
k8s-w1의 라우팅 테이블을 확인해본 결과 pod3의 대역인 172.16.34.0
으로 통신을 할 때 192.168.10.254 라고하는 Gateway를 통해서 나간다.
그럼 192.168.10.254대역은 무엇일까? 바로 k8s-rtr 이다.
- k8s-rtr에 접속 후 ip 정보를 확인
root@k8s-rtr:~# ip -br -c -4 addr
lo UNKNOWN 127.0.0.1/8
enp0s3 UP 10.0.2.15/24
enp0s8 UP 192.168.10.254/24
enp0s9 UP 192.168.20.254/24
loop1 UNKNOWN 10.1.1.254/24
loop2 UNKNOWN 10.1.2.254/24
k8s-w0에 배포된 Pod로 Ping을 한 결과 k8s-rtr에서 request가 들어오는 것을 알 수 있다.
- 라우팅 테이블 정보 확인
root@k8s-rtr:~# ip -c route
default via 10.0.2.2 dev enp0s3 proto dhcp src 10.0.2.15 metric 100
10.0.2.0/24 dev enp0s3 proto kernel scope link src 10.0.2.15
10.0.2.2 dev enp0s3 proto dhcp scope link src 10.0.2.15 metric 100
10.1.1.0/24 dev loop1 proto kernel scope link src 10.1.1.254
10.1.2.0/24 dev loop2 proto kernel scope link src 10.1.2.254
192.168.10.0/24 dev enp0s8 proto kernel scope link src 192.168.10.254
192.168.20.0/24 dev enp0s9 proto kernel scope link src 192.168.20.254
w0, w1, w2 간에 통신할 때 rtr을 통하도록 되어있는데 Direct 모드로 되어있다 보니 캡슐레이션 되지 않고 172.x
대역으로 통신하다 보니 정상적으로 라우팅 해주지 못하는 것으로 확인된다.
이전 Overay Network 환경에서 가능했던 이유는 Linux Router(rtr)을 통하더라도 캡슐화되어 Worker Node 대역으로 들어오기 때문에 정상적으로 라우팅 된 것을 알 수 있다.
4) CrossSubnet 모드
❗ 동작 : 노드 간 같은 네트워크 대역(Direct 모드로 동작) , 노드 간 다른 네트워크 대역(IPIP 모드로 동작)
IPIPMode 변경
# CrossSubnet 모드 설정
calicoctl get ippool default-ipv4-ippool -o yaml | sed -e "s/ipipMode: Never/ipipMode: CrossSubnet/" | calicoctl apply -f -
# 변경사항 Watch
watch -d "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.158.0 192.168.10.101 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
(변경 후)
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.158.0 192.168.10.101 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
k8s-m와 네트워크 대역이 다른 172.16.34.0
대역이 할당된 노드만 tunl0로 변경된 것을 확인할 수 있다.
물론 k8s-w0은 다른 노드들과 대역이 다르기 때문에 다음과 같이 라우팅 테이블이 모두 tunl0이다.
root@k8s-w0:~# ip -c route | grep bird
blackhole 172.16.34.0/24 proto bird
172.16.116.0/24 via 192.168.10.10 dev tunl0 proto bird onlink
172.16.158.0/24 via 192.168.10.101 dev tunl0 proto bird onlink
172.16.184.0/24 via 192.168.10.102 dev tunl0 proto bird onlink
결론 : 결론적으로 CrossSubnet 모드가 가장 효율적(?)이라고 볼 수 있다.
3) BGP (생략) -> 추후 재작성 예정
요약 : K8S 클러스터 내부 네트워크와 IDC 내부망 네트워크간 직접 라우팅이 가능합니다!
K8S 클러스터 네트워크 대역과 IDC 내부망 네트워크 대역간 직접 통신 ↔ BGP 로 네트워크 대역을 전파
참고 : IDC망을 관리하는 네트워크 팀과 협조하여 K8S 클러스터와의 통신 간 효율적인 네트워크 환경을 구성하는 것을 권장
1) 네트워크 기본 정보
IDC(내부망)과 K8S 클러스터 사용 네트워크 대역
- IDC 호스트 : 아래 빨간색은 회사 내부 네트워크 대역
2) IDC 호스트
3) K8S Calico 확인 및 파드/서비스 생성
4) K8S Calico BGP 구성 및 파드와 통신 설정
5) IDC 내부망 ↔ K8S 파트 네트워크 통신
6) 별도 IP Pool 생성 제공 ← IP 대역 관리를 편하게 할 수 있다!
4) VXLAN(생략)
- Calico에서는 VXLAN 모드 사용시 BGP 사용 불가!
- BGP를 사용하기 위해서는 IPIP모드 또는 Direct 모드 사용
- Network 장비와 연동을 위해서 BGP 사용하는 경우
5) Pod 패킷 암호화
WireGuard 기능등을 사용하여 쉽고 간편하게 암호화 통신 제공가능
(1) 통신 흐름
요약 : Calico 의 다양한 네크워크 모드 환경 위에서 WireGuard 터널을 자동 생성 및 파드 트래픽을 암호화하여 노드간 전달합니다
📌 참고 : WireGuard 소개 글
(2) WireGuard 설정 - 링크
노드에 WireGuard 설치 - 링크 ← 이미 설치되어 있음
# 설치
apt install wireguard -y
# WireGuard 버전 확인
wg version
root@k8s-m:~/yaml# wg version
wireguard-tools v1.0.20200513 - https://git.zx2c4.com/wireguard-tools/
WireGuard 설정 및 확인
- WireGuard 설정 및 확인
# 설정
(calico-k8s:default) root@k8s-m:~# calicoctl patch felixconfiguration default --type='merge' -p '{"spec":{"wireguardEnabled":true}}'
Successfully patched 1 'FelixConfiguration' resource
# 확인
(calico-k8s:default) root@k8s-m:~# calicoctl get felixconfiguration default -o yaml | grep wireguardEnabled
wireguardEnabled: true
# wireguard.cali 인터페이스 확인
(calico-k8s:default) root@k8s-m:~# calicoctl get node -o yaml | grep wireguardPublicKey
wireguardPublicKey: Zpr9B1xt/vNfqVDd7+khL/Sgp/UgPax9cRLCviIw23Q=
wireguardPublicKey: JRfFa5cs0u1OmPEzTqZlqgZyNpVeS1r3g3jOG7JAkT4=
wireguardPublicKey: TIRRGkoyyhtAOWl7sDGVhCBTRW8tDGoTEELuDgsRCFk=
wireguardPublicKey: CazuOk0lhm8DB4CaRKwPNeyVQvs6hSb6jtB9z0jhERA=
(calico-k8s:default) root@k8s-m:~# ifconfig wireguard.cali
wireguard.cali: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1440
inet 172.16.116.5 netmask 255.255.255.255 destination 172.16.116.5
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC)
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
- wireguard.cali 설정 확인 : 통신 포트, Peer/Endpoint 정보, 패킷 암호화를 위한 공개키/사설키 정보
(calico-k8s:default) root@k8s-m:~# wg showconf wireguard.cali
[Interface]
ListenPort = 51820
FwMark = 0x100000
PrivateKey = kLTb72iPcf2oCEV+Unj8hfV/cwi718O/ErNPvbW2g1Q=
[Peer]
PublicKey = TIRRGkoyyhtAOWl7sDGVhCBTRW8tDGoTEELuDgsRCFk=
AllowedIPs = 172.16.158.6/32, 172.16.158.7/32, 172.16.158.0/24
Endpoint = 192.168.10.101:51820
[Peer]
PublicKey = CazuOk0lhm8DB4CaRKwPNeyVQvs6hSb6jtB9z0jhERA=
AllowedIPs = 172.16.184.0/24, 172.16.184.3/32, 172.16.184.4/32
Endpoint = 192.168.10.102:51820
[Peer]
PublicKey = JRfFa5cs0u1OmPEzTqZlqgZyNpVeS1r3g3jOG7JAkT4=
AllowedIPs = 172.16.34.0/24, 172.16.34.2/32, 172.16.34.3/32
Endpoint = 192.168.20.100:51820
# Peer 의 정보(고유한 index)
(calico-k8s:default) root@k8s-m:~# wg show
interface: wireguard.cali
public key: Zpr9B1xt/vNfqVDd7+khL/Sgp/UgPax9cRLCviIw23Q=
private key: (hidden)
listening port: 51820
fwmark: 0x100000
peer: TIRRGkoyyhtAOWl7sDGVhCBTRW8tDGoTEELuDgsRCFk=
endpoint: 192.168.10.101:51820
allowed ips: 172.16.158.6/32, 172.16.158.7/32, 172.16.158.0/24
peer: CazuOk0lhm8DB4CaRKwPNeyVQvs6hSb6jtB9z0jhERA=
endpoint: 192.168.10.102:51820
allowed ips: 172.16.184.0/24, 172.16.184.3/32, 172.16.184.4/32
peer: JRfFa5cs0u1OmPEzTqZlqgZyNpVeS1r3g3jOG7JAkT4=
endpoint: 192.168.20.100:51820
allowed ips: 172.16.34.0/24, 172.16.34.2/32, 172.16.34.3/32
(3) 동작 확인
파드생성 및 확인
(calico-k8s:default) root@k8s-m:~# kubectl apply -f node3-pod3.yaml
pod/pod1 created
pod/pod2 created
pod/pod3 created
(calico-k8s:default) root@k8s-m:~# calicoctl get workloadEndpoint
WORKLOAD NODE NETWORKS INTERFACE
pod1 k8s-w1 172.16.158.8/32 calice0906292e2
pod2 k8s-w2 172.16.184.5/32 calibd2348b4f67
pod3 k8s-w0 172.16.34.4/32 cali49778cadcf1
파드간 ping 통신 실행 및 패킷 캡쳐 확인
# pod1에서 pod2로 ping
pod1 ~ ping 172.16.184.5
PING 172.16.184.5 (172.16.184.5) 56(84) bytes of data.
64 bytes from 172.16.184.5: icmp_seq=1 ttl=62 time=3.22 ms
64 bytes from 172.16.184.5: icmp_seq=2 ttl=62 time=1.52 ms
64 bytes from 172.16.184.5: icmp_seq=3 ttl=62 time=2.39 ms
^C
--- 172.16.184.5 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 1.521/2.377/3.221/0.694 ms
# w1에서 tcpdump
root@k8s-w1:~# tcpdump -i enp0s8 -nn udp port 51820
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s8, link-type EN10MB (Ethernet), capture size 262144 bytes
12:36:51.476347 IP 192.168.10.101.51820 > 192.168.10.102.51820: UDP, length 128
12:36:51.478762 IP 192.168.10.102.51820 > 192.168.10.101.51820: UDP, length 128
- WireShark를 통한 패킷분석
root@k8s-w1:~# tcpdump -i enp0s8 udp port 51820 -w /tmp/calico-wireguard.pcap
tcpdump: listening on enp0s8, link-type EN10MB (Ethernet), capture size 262144 bytes
^C12 packets captured
12 packets received by filter
0 packets dropped by kernel
패킷캡쳐한 정보를 직접 WireShark에서 분석해보니 Protocol: WireGuard
으로 되어 있어있으며, 실제 Inner 헤더에 들어가 있어야할 정보가 Encrypted Packet
으로 처리된 것을 확인할 수 있다.
6) Calico 네트워크 접근 통제
네트워크 접근 통제(Network Policy) 기능은 Cilium 스터디 시간에 추가 작성 예정.
네트워크 정책 소개
네트워크 정책(Network Policy)은 쿠버네티스 클러스터 내부에서 파드 간에 통신할 경우 트래픽 룰을 규정하는 것이다.
네트워크 정책을 사용하지 않을 경우 클러스터 내부의 모든 파드는 서로 통신이 가능하다.
그러나 네트워크 정책을 사용할 수 있다면, 네임스페이스별로 트래픽을 전송하지 못하게 하거나
기본적으로 모든 파드 간 통신을 차단하고 특정 파드 간 통신만 허용하는 화이트리스트 방식을 사용할 수 있다.
또한 CNI(Calico, Cilium 등)에서 네트워크 정책을 지원해야 한다.
네트워크 정책 실습
(심화 정보) Calico 자체 제공 추가 기능 Netwok Policy
이렇게 3주차 스터디 내용에 대한 복습이 끝이났다.
본 스터디를 신청할 때 가장 궁금했고 필요했던 내용이었는데... 생각보다 훨씬 어렵고 공부해야 할 내용이 많았다.
핑계지만 투입된 프로젝트 마무리 기간 + 설 연휴가 겹쳐서 복습을 하지못했는데... 다가오는 4주차 스터디이후에 꼭 다시한번 3주차 내용을 복습해야 할 것 같다.
그래도 지난 1달 사이에 많은 것을 느끼고 배울 수 있는 시간이었던 것 같다.
마지막 8주차까지 런🔥
Author And Source
이 문제에 관하여(KANS 스터디 3주차 - Calico CNI 2편), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@hyungwook/KANS-스터디-3주차-Calico-CNI-2편저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)