📌 Notice
Kubernetes Advanced Networking Study (=KANS)
k8s 네트워크 장애 시, 네트워크 상세 동작 원리를 기반으로 원인을 찾고 해결하는 내용을 정리한 블로그입니다.
CloudNetaStudy
그룹에서 스터디를 진행하고 있습니다.
Gasida
님께 다시한번 🙇 감사드립니다.
EKS 관련 이전 스터디 내용은 아래 링크를 통해 확인할 수 있습니다.
이번 주에는 Kubernetes 네트워킹의 핵심인 Calico를 깊이 있게 탐구했습니다.
스터디를 거듭하면서, 하나씩 지식을 쌓으면서 새로운것을 배워나가는것이 힘들긴 하지만 굉장한 보람을 느끼게 해주는것 같습니다.
Calico는 Kubernetes 클러스터를 위한 강력한 네트워크 솔루션으로, 다양한 네트워크 모드와 기능을 제공합니다.
주요 모드로는 Direct, IPIP, VXLAN, 그리고 WireGuard를 이용한 암호화 모드가 있습니다.
Calico는 BGP를 통한 효율적인 라우팅, 네트워크 정책을 통한 세밀한 접근 제어를 지원합니다.
Prometheus와 Grafana를 활용하여 Calico 컴포넌트의 메트릭을 모니터링하고 시각화할 수 있습니다.
Calico 설치
# 모니터링 watch -d 'kubectl get pod -A -owide' # calico cni install ## kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/calico.yaml - 서브넷 24bit 추가 # 기본 yaml 에 4946줄 이동 후 아래 내용 추가 해둠 vi calico.yaml ... # Block size to use for the IPv4 POOL created at startup. Block size for IPv4 should be in the range 20-32. default 24 - name: CALICO_IPV4POOL_BLOCK_SIZE value: "24" kubectl apply -f https://raw.githubusercontent.com/gasida/KANS/main/kans3/calico-kans.yaml # tree /opt/cni/bin/ ls -l /opt/cni/bin/ ip -c route ip -c addr iptables -t filter -L iptables -t nat -L iptables -t filter -L | wc -l iptables -t nat -L | wc -l
Calicoctl 설치
# calicoctl install curl -L https://github.com/projectcalico/calico/releases/download/v3.28.1/calicoctl-linux-amd64 -o calicoctl chmod +x calicoctl && mv calicoctl /usr/bin calicoctl version
metric-server 설치
# metrics-server helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/ helm upgrade --install metrics-server metrics-server/metrics-server --set 'args[0]=--kubelet-insecure-tls' -n kube-system kubectl get all -n kube-system -l app.kubernetes.io/instance=metrics-server kubectl get apiservices |egrep '(AVAILABLE|metrics)' # 확인 kubectl top node kubectl top pod -A --sort-by='cpu' kubectl top pod -A --sort-by='memory' # (참고) 삭제 helm uninstall -n kube-system metrics-server
이번 단계에서는 Calico가 Kubernetes 클러스터 내에서 어떻게 기본적인 네트워크 통신을 처리하는지 알아보겠습니다.
이를 위해 Calico CNI 플러그인의 주요 구성 요소와 동작 방식을 살펴보겠습니다.
Calico는 Kubernetes 플랫폼에서 널리 사용되는 Container Network Interface(CNI) 플러그인입니다. Calico는 워크로드 간의 네트워크 통신과 네트워크 보안 기능을 제공합니다.
Calico의 주요 구성 요소
calicoctl: Calico 오브젝트를 관리하는 명령줄 도구
calico-node: 각 노드에서 데몬셋으로 실행되는 핵심 컴포넌트
Felix: 호스트 엔드포인트 관리 및 라우팅 테이블 업데이트 담당
BIRD: BGP 라우팅 데몬으로, 파드 네트워크 대역을 광고
confd: Calico 설정 변경 관리 도구
구성 요소 확인
# 버전 확인 - 링크 ## kdd 의미는 쿠버네티스 API 를 데이터저장소로 사용 : k8s API datastore(kdd) calicoctl version # calico 관련 정보 확인 kubectl get daemonset -n kube-system kubectl get pod -n kube-system -l k8s-app=calico-node -owide kubectl get deploy -n kube-system calico-kube-controllers kubectl get pod -n kube-system -l k8s-app=calico-kube-controllers -owide
Calico IPAM(IP Address Management)의 상태 확인, 노드별 IP 블록 할당 정보, 그리고 strictAffinity 설정에 따른 IP 할당 정책을 확인
# 칼리코 IPAM 정보 확인 : 칼리코 CNI 를 사용한 파드가 생성된 노드에 podCIDR 네트워크 대역 확인 - 링크 calicoctl ipam show # Block 는 각 노드에 할당된 podCIDR 정보 calicoctl ipam show --show-blocks calicoctl ipam show --show-borrowed calicoctl ipam show --show-configuration ## strictAffinity True 설정 시 : 각 노드는 할당된 IP 블록에서만 IP 주소를 사용, 특정 pod들에 해당해둔 pod ip/mac을 고정할경우, 해당 대역들을 무작위로 배치하는 IPAM 대역에서 제외 -> 이로써 중복으로 같은 IP 할당 방지 ## strictAffinity False 설정 시 : 노드가 부족한 경우 다른 노드에서 IP를 공유 가능 ## When StrictAffinity is true, borrowing IP addresses is not allowed - https://docs.tigera.io/calico/latest/reference/resources/ipamconfig ## 관련 코드 ### https://github.com/projectcalico/libcalico-go/blob/v3.9.0-0.dev/lib/ipam/ipam.go ### https://github.com/projectcalico/libcalico-go/blob/v3.9.0-0.dev/lib/ipam/ipam_types.go#L78
Kubernetes 노드별 podCIDR 할당 정보 확인, CNI 플러그인 구성 확인, 그리고 Calico의 데이터 저장소 및 IPAM 설정을 확인
# host-local IPAM 정보 확인 : k8s-m 노드의 podCIDR 은 host-local 대신 칼리코 IPAM 를 사용함 ## 워커 노드마다 할당된 dedicated subnet (podCIDR) 확인 kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}' ;echo kubectl get node k8s-m -o json | jq '.spec.podCIDR' # CNI Plugin 정보 확인 - 링크 tree /etc/cni/net.d/ cat /etc/cni/net.d/10-calico.conflist | jq ... "datastore_type": "kubernetes", # 칼리코 데이터저장소는 쿠버네티스 API 를 사용 "ipam": { "type": "calico-ipam" # IPAM 은 칼리코 자체 IPAM 을 사용 }, ...
Calico의 노드 상태, IP 풀 정보, 그리고 Kubernetes 클러스터의 네트워크 대역 정보를 확인합니다.
# calicoctl node 정보 확인 : Bird 데몬(BGP)을 통한 BGP 네이버 연결 정보(bgp peer 는 노드의 IP로 연결) - 링크 calicoctl node status calicoctl node checksystem # ippool 정보 확인 : 클러스터가 사용하는 IP 대역 정보와 칼리코 모드 정보 확인 calicoctl get ippool -o wide # 파드와 서비스 사용 네트워크 대역 정보 확인 kubectl cluster-info dump | grep -m 2 -E "cluster-cidr|service-cluster-ip-range" "--service-cluster-ip-range=10.200.1.0/24", "--cluster-cidr=172.16.0.0/16", kubectl get cm -n kube-system kubeadm-config -oyaml | grep -i subnet podSubnet: 172.16.0.0/16 serviceSubnet: 10.96.0.0/12
Calico에서 동일 노드 내 파드 간 통신은 다음과 같이 이루어집니다.
출처 - CloudNet@
네트워크 구성
- 각 파드는 고유한 네트워크 네임스페이스를 가집니다.
- 파드의 eth0 인터페이스는 호스트의 veth (Virtual Ethernet) 인터페이스와 페어로 연결됩니다.
- veth 인터페이스는 호스트의 root 네트워크 네임스페이스에 존재합니다.
- Calico는 각 파드에 /32 CIDR (단일 IP 주소)를 할당합니다.
통신 과정
- 출발지 파드에서 패킷 전송:
파드는 자신의 eth0 인터페이스를 통해 패킷을 전송합니다.
패킷은 페어를 이루는 veth 인터페이스로 전달됩니다.
- 호스트에서의 패킷 처리:
호스트의 커널은 수신한 패킷을 처리합니다.
Calico가 설정한 라우팅 규칙과 iptables 규칙에 따라 패킷을 전달합니다.
- 목적지 파드로 패킷 전달:
패킷은 목적지 파드와 연결된 veth 인터페이스로 전달됩니다.
최종적으로 목적지 파드의 eth0 인터페이스로 패킷이 전달됩니다.
파드 생성 전 노드(k8s-w1) Shell 에서 기본 정보 확인
# 네트워크 인터페이스 정보 확인 : 터널(ipip) 인터페이스가 존재! 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 # 네트워크 네임스페이스 확인 lsns -t net # 네트워크 라우팅 경로 정보 확인 # 이중 bird 는 bird 데몬이 BGP 라우팅 프로토콜에 의해 파드 네트워크 대역을 전달받거나 전달하는 경로 → 각각 노드의 파드 대역입니다 Quiz. blackhole 라우팅은 왜 있을까요? 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 # 아래 tunl0 Iface 에 목적지 네트워크 대역은 ipip 인캡슐레이션에 의해서 각 노드에 전달됩니다 → 각각 노드의 파드 대역입니다 route -n root@k8s-w1:~# route -n 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 172.16.158.0 0.0.0.0 255.255.255.0 U 0 0 0 * ... # (옵션) iptables rule 갯수 확인 >> iptables rule 이 모든 노드에서 똑같나요? 다른가요? iptables -t filter -S | grep cali | wc -l iptables -t nat -S | grep cali | wc -l
파드 배포 후 상태 확인
파드를 배포하며, workloadEndpoint가 어떻게 관리되는지 확인합니다.
# [터미널1] k8s-m 모니터링 watch -d calicoctl get workloadEndpoint # [터미널2] k8s-m 모니터링 # 파드 생성 : 노드의 이름이 다를 경우 아래 yaml 파일 다운로드 후 수정해서 사용하시면 됩니다 curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/4/node1-pod2.yaml kubectl apply -f node1-pod2.yaml # 생성된 파드 정보 확인 kubectl get pod -o wide root@k8s-m:~# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod1 1/1 Running 0 34s 172.16.228.78 k8s-w1 <none> <none> pod2 1/1 Running 0 34s 172.16.228.79 k8s-w1 <none> <none> # calicoctl 이용한 endpoint 확인 : veth 정보도 출력! calicoctl get workloadendpoints WORKLOAD NODE NETWORKS INTERFACE pod1 k8s-w1 172.16.158.2/32 calice0906292e2 pod2 k8s-w1 172.16.158.1/32 calibd2348b4f67
파드 내부에 접속하여 ip를 확인합니다.
# 마스터 노드에서 아래 실행 kubectl exec pod1 -it -- zsh ... # 아래 처럼 호스트 네트워크 인터페이스 9번인 caliceY와 veth 연결되어 있다 # IP는 32bit 서브넷을 가진다 pod1> ip -c addr ... 4: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP group default link/ether ee:2f:83:31:9b:d0 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.16.158.2/32 brd 172.16.158.2 scope global eth0 valid_lft forever preferred_lft forever # 라우팅 정보에 169.254.1.1 를 디폴트 게이트웨이 주소로 사용 pod1> route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 169.254.1.1 0.0.0.0 UG 0 0 0 eth0 169.254.1.1 0.0.0.0 255.255.255.255 UH 0 0 0 eth0 # ARP 정보는 현재 아무것도 없다 ip -c neigh
출처 - CloudNet@
사전 준비
실습을 진행하기 전에 calico 설정 정보 확인 & 노드에 iptables 정보를 확인합니다.
# 마스터 노드에서 확인 : natOutgoing 의 기본값은 true 이다 calicoctl get ippool -o wide NAME CIDR NAT IPIPMODE VXLANMODE DISABLED SELECTOR default-ipv4-ippool 172.16.0.0/16 true Always Never false all() # 노드에서 확인 : 노드에서 외부로 통신 시 MASQUERADE 동작 Rule 확인 iptables -n -t nat --list cali-nat-outgoing 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 ipset list ipset list cali40masq-ipam-pools
출발지의 IP와 노드의 외부 IP로 NAT되어 외부 환경과 통신하는것을 확인합니다.
# 파드에서 외부 정상 통신 확인 kubectl exec pod1 -it -- zsh ---------------------------- # 혹은 통신 확인 pod1> ping -c 10 8.8.8.8 # The right way to check the weather - 링크 curl wttr.in/seoul curl 'wttr.in/seoul?format=3' curl 'wttr.in/busan?format=3' curl -s 'wttr.in/{London,Busan}' curl v3.wttr.in/Seoul.sxl curl wttr.in/Moon curl wttr.in/:help # 패킷 덤프 내용 확인 tcpdump -i <각자 실습 환경에 따라 다름> -nn icmp root@k8s-w1:~# tcpdump -i calice0906292e2 -nn icmp tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on calice0906292e2, link-type EN10MB (Ethernet), capture size 262144 bytes 09:27:29.236878 IP 172.16.228.82 > 8.8.8.8: ICMP echo request, id 56376, seq 1, length 64 09:27:29.311810 IP 8.8.8.8 > 172.16.228.82: ICMP echo reply, id 56376, seq 1, length 64 # [실습환경 A Type] 아래 192.168.10.101는 노드의 외부(인터넷) 연결된 네트워크 인터페이스의 IP이며, 출발지 IP가 변경되어서 외부로 나감 root@k8s-w1:~# tcpdump -i ens5 -nn icmp 15:37:56.579286 IP 192.168.10.101 > 8.8.8.8: ICMP echo request, id 57122, seq 1, length 64 15:37:56.610585 IP 8.8.8.8 > 192.168.10.101: ICMP echo reply, id 57122, seq 1, length 64 # [실습환경 B Type] 아래 10.0.2.15는 VM의 1번 네트워크 인터페이스의 IP이며, 출발지 IP가 변경되어서 외부로 나감 root@k8s-w1:~# tcpdump -i enp0s3 -nn icmp 06:05:12.356260 IP 10.0.2.15 > 8.8.8.8: ICMP echo request, id 15671, seq 5, length 64 06:05:12.402586 IP 8.8.8.8 > 10.0.2.15: ICMP echo reply, id 15671, seq 5, length 64 # nat MASQUERADE rule 카운트(pkts)가 증가! ## 출발지 매칭은 cali40masq-ipam-pools 을 사용 watch -d 'iptables -n -v -t nat --list cali-nat-outgoing' root@k8s-w1:~# iptables -n -v -t nat --list cali-nat-outgoing Chain cali-nat-outgoing (1 references) pkts bytes target prot opt in out source destination 3 252 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 # IPSET 으로 의 cali40masq-ipam-pools IP 대역 정보 확인 : 172.16.0.0/16 대역임을 확인 ipset list cali40masq-ipam-pools Name: cali40masq-ipam-pools Type: hash:net Revision: 7 Header: family inet hashsize 1024 maxelem 1048576 bucketsize 12 initval 0x97754149 Size in memory: 504 References: 1 Number of entries: 1 Members: 172.16.0.0/16
출처 - CloudNet@
각 노드에 파드 네트워크 대역은 Bird
에 의해서 BGP 로 광고 전파/전달 되며, Felix
에 의해서 호스트의 라우팅 테이블에 자동으로 추가 및 삭제 됩니다.
다른 노드 간의 파드 통신은 tunl0
인터페이스를 통해 IP 헤더에 감싸져서 상대측 노드로 도달 후 tunl0
인터페이스에서 Outer 헤더
를 제거하고 내부의 파드와 통신됩니다.
파드 배포 전 기본 상태 확인
# 아래 명령어로 확인 시 나머지 노드들의 파드 대역을 자신의 호스트 라우팅 테이블에 가지고 있고, 해당 경로는 tunl0 인터페이스로 보내게 된다 route | head -2 ; route -n | grep tunl0 # 마스터노드, 노드1~ root@k8s-m:~# route | head -2 ; route -n | grep tunl0 Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 172.16.46.0 192.168.100.102 255.255.255.192 UG 0 0 0 tunl0 172.16.197.0 192.168.100.103 255.255.255.192 UG 0 0 0 tunl0 172.16.228.64 192.168.100.101 255.255.255.192 UG 0 0 0 tunl0 # 노드1 root@k8s-w1:~# route | head -2 ; route -n | grep tunl0 Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 172.16.29.0 192.168.100.10 255.255.255.192 UG 0 0 0 tunl0 172.16.46.0 192.168.100.102 255.255.255.192 UG 0 0 0 tunl0 172.16.197.0 192.168.100.103 255.255.255.192 UG 0 0 0 tunl0 ...
노드의 tunl0 정보 확인
# 터널 인터페이스에 IP가 할당되어 있고, MTU는 1480(IP헤더 20바이트 추가를 고려)을 사용하며, 현재 TX/RX 카운트는 0 이다 # Calico 사용 시 파드의 인터페이스도 기본 MTU 1480 을 사용한다 ifconfig tunl0 # 노드1 root@k8s-w1:~# ifconfig tunl0 tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480 inet 172.16.228.76 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 # 노드2 root@k8s-w2:~# ifconfig tunl0 tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480 inet 172.16.46.10 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
파드간 통신을 처리하는 라우팅 정보 확인 : 각각 상대방 노드의 IP를 게이트웨이로 전달하게 됩니다!
# 파드 생성 curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/4/node2-pod2.yaml kubectl apply -f node2-pod2.yaml # calicoctl 이용한 endpoint 확인 calicoctl get workloadendpoints route -n | head -2 ; route -n | grep 172.16. # 노드1 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.46.0 192.168.100.102 255.255.255.192 UG 0 0 0 tunl0 ... # 노드2 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.228.64 192.168.100.101 255.255.255.192 UG 0 0 0 tunl0 ...
지금까지 tunl0 인터페이스가 사용되지 않았는데, 다른 노드의 파드간 통신시에 사용되는지 확인합니다.
# tunl0 인터페이스 TX/RX 패킷 카운트 모니터링 실행 watch -d 'ifconfig tunl0 | head -2 ; ifconfig tunl0 | grep bytes' root@k8s-w1:~# watch -d 'ifconfig tunl0 | head -2 ; ifconfig tunl0 | grep bytes' tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480 inet 172.16.228.76 netmask 255.255.255.255 RX packets 0 bytes 0 (0.0 B) TX packets 0 bytes 0 (0.0 B) # (옵션) 패킷 덤프 : calice# tcpdump -i -nn <calice#> # 패킷 덤프 : tunl0 tcpdump -i tunl0 -nn 혹은 패킷을 파일로 추출시 tcpdump -i tunl0 -nn -w /tmp/calico-tunl0.pcap # 패킷 덤프 : IP 헤더에 상위 프로토콜을 IPIP(4)인 패킷만 필터 #tcpdump -i <각자 자신의 노드의 eth0> -nn proto 4 tcpdump -i ens5 -nn proto 4 # [실습환경 A Type] tcpdump -i enp0s8 -nn proto 4 # [실습환경 B Type] 혹은 패킷을 파일로 추출시 tcpdump -i ens5 -nn proto 4 -w /tmp/calico-ipip.pcap # [실습환경 A Type] tcpdump -i enp0s8 -nn proto 4 -w /tmp/calico-ipip.pcap # [실습환경 B Type] # [실습환경 A Type] 자신의 PC로 패킷 복사 scp ubuntu@<node 유동공인 IP>:/tmp/calico-ipip.pcap . scp ubuntu@3.35.229.92:/tmp/calico-ipip.pcap . # [실습환경 B Type] 자신의 PC로 패킷 복사 : https://github.com/invernizzi/vagrant-scp ## vagrant scp 플러그인 설치 vagrant plugin install vagrant-scp vagrant plugin list ## k8s-w1 VM 내부의 파일을 자신의 PC(호스트)에 복사 vagrant scp k8s-w1:/tmp/calico-ipip.pcap ./
# 마스터 노드에서 pod1 Shell 접속 kubectl exec pod1 -it -- zsh # pod1 에서 pod2 로 핑 통신 : 정상 통신! ping -c 10 <pod2 IP> pod1> ping -c 10 172.16.46.12 PING 172.16.46.12 (172.16.46.12) 56(84) bytes of data. 64 bytes from 172.16.46.12: icmp_seq=1 ttl=62 time=0.781 ms 64 bytes from 172.16.46.12: icmp_seq=2 ttl=62 time=0.803 ms ... # tunl0 인터페이스 TX/RX 패킷 카운트 모니터링 확인 : TX/RX 패킷 카운트가 각각 10개로 증가했다 watch -d 'ifconfig tunl0 | head -2 ; ifconfig tunl0 | grep bytes' tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480 inet 172.16.228.76 netmask 255.255.255.255 RX packets 10 bytes 840 (840.0 B) TX packets 10 bytes 840 (840.0 B) # 패킷 덤프 : tunl0 - 터널 인터페이스에 파드간 IP 패킷 정보 확인! tcpdump -i tunl0 -nn 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 23:36:36.621795 IP 172.16.228.84 > 172.16.46.12: ICMP echo request, id 32298, seq 1, length 64 23:36:36.622470 IP 172.16.46.12 > 172.16.228.84: ICMP echo reply, id 32298, seq 1, length 64 23:36:37.623274 IP 172.16.228.84 > 172.16.46.12: ICMP echo request, id 32298, seq 2, length 64 23:36:37.623977 IP 172.16.46.12 > 172.16.228.84: ICMP echo reply, id 32298, seq 2, length 64 ... # 패킷 덤프 : eth0(enp#~) - IP Outer 헤더 안쪽에 IP 헤더 1개가 더 있음을 알 수 있다! tcpdump -i ens5 -nn proto 4 # [실습환경 A Type] tcpdump -i enp0s8 -nn proto 4 # [실습환경 B Type] root@k8s-w2:~# tcpdump -i ens5 -nn proto 4 # [실습환경 A Type] root@k8s-w2:~# tcpdump -i enp0s8 -nn proto 4 # [실습환경 B Type] tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on enp0s8, link-type EN10MB (Ethernet), capture size 262144 bytes 23:36:36.625169 IP 192.168.100.101 > 192.168.100.102: IP 172.16.228.84 > 172.16.46.12: ICMP echo request, id 32298, seq 1, length 64 (ipip-proto-4) 23:36:36.625413 IP 192.168.100.102 > 192.168.100.101: IP 172.16.46.12 > 172.16.228.84: ICMP echo reply, id 32298, seq 1, length 64 (ipip-proto-4) 23:36:37.626715 IP 192.168.100.101 > 192.168.100.102: IP 172.16.228.84 > 172.16.46.12: ICMP echo request, id 32298, seq 2, length 64 (ipip-proto-4) 23:36:37.626866 IP 192.168.100.102 > 192.168.100.101: IP 172.16.46.12 > 172.16.228.84: ICMP echo reply, id 32298, seq 2, length 64 (ipip-proto-4) ... tcpdump -i ens5 -nn proto 4 -w /tmp/calico-ipip.pcap # [실습환경 A Type] tcpdump -i enp0s8 -nn proto 4 -w /tmp/calico-ipip.pcap # [실습환경 B Type] ls -l /tmp # [실습환경 A Type] 자신의 PC로 패킷 복사 scp ubuntu@<node 유동공인 IP>:/tmp/calico-ipip.pcap . scp ubuntu@3.35.229.92:/tmp/calico-ipip.pcap . # [실습환경 B Type] 자신의 PC로 패킷 복사 : https://github.com/invernizzi/vagrant-scp ## vagrant scp 플러그인 설치 vagrant plugin install vagrant-scp vagrant plugin list ## k8s-w1 VM 내부의 파일을 자신의 PC(호스트)에 복사 vagrant scp k8s-w1:/tmp/calico-ipip.pcap ./
Calico는 다양한 네트워크 모드를 제공하여 다양한 환경과 요구사항에 맞춰 쿠버네티스 클러스터의 네트워킹을 구성할 수 있습니다.
주요 모드는 다음과 같습니다
Direct 모드
IPIP 모드
VXLAN 모드
파드 패킷 암호화 (Wireguard)
각 모드의 특징
Direct 모드는 최고의 성능을 제공하지만 네트워크 구성에 제약이 있을 수 있습니다.
IPIP와 VXLAN 모드는 유연성이 높지만 약간의 성능 오버헤드가 있습니다.
패킷 암호화는 보안을 강화하지만 추가적인 처리 비용이 발생합니다.
Calico의 다양한 네트워크 모드를 통해 사용자는 자신의 환경과 요구사항에 가장 적합한 네트워킹 솔루션을 구성할 수 있습니다.
파드 간 통신이 노드와 노드 구간에서는 IPIP 인캡슐레이션을 통해서 이루어 집니다.
다른 노드 간의 파드 통신은 tunl0 인터페이스를 통해 IP 헤더에 감싸져서 상대측 노드로 도달 후 tunl0 인터페이스에서 Outer 헤더를 제거하고 내부의 파드와 통신
다른 노드의 파드 대역은 BGP로 전달 받아 호스트 라우팅 테이블에 업데이트됩니다.
Azure 네트워크에서는 IPIP 통신이 불가능하여 IPIP 모드 대신 VXLAN 모드 사용해야 합니다.
멀티 캐스트, 브로드캐스트, IP-IP 캡슐화 패킷 및 GRE(일반 라우팅 캡슐화) 패킷은 Azure VNet 내에서 차단됩니다.
파드 통신 패킷이 출발지 노드의 라우팅 정보를 보고 목적지 노드로 원본 패킷 그대로 전달합니다.
출처 - CloudNet@
클라우드 사업자 네트워크의 경우 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}"
Direct 모드 설정을 진행합니다.
# Calico 모드 정보 확인 calicoctl get ippool -o wide NAME CIDR NAT IPIPMODE VXLANMODE DISABLED SELECTOR default-ipv4-ippool 172.16.0.0/16 true Always Never false all() # (옵션) 모니터링 watch -d "route -n | egrep '(Destination|UG)'" # 설정 calicoctl get ippool default-ipv4-ippool -o yaml calicoctl get ippool default-ipv4-ippool -o yaml | sed -e "s/ipipMode: Always/ipipMode: Never/" | calicoctl apply -f - # 모드 정보 확인 : 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() # BGP 로 전달 받은 파드 네트워크 대역이 호스트 라우팅 테이블에 적용되었는지 확인 : Iface 가 tunl0 에서 ens5 혹은 enp0s8 로 변경! route -n | egrep '(Destination|UG)' root@k8s-w1:~# route -n | egrep '(Destination|UG)' Destination Gateway Genmask Flags Metric Ref Use Iface 172.16.29.0 192.168.100.10 255.255.255.192 UG 0 0 0 ens5 혹은 enp0s8 172.16.46.0 192.168.100.102 255.255.255.192 UG 0 0 0 ens5 혹은 enp0s8 172.16.197.0 192.168.100.103 255.255.255.192 UG 0 0 0 ens5 혹은 enp0s8
파드를 생성합니다.
# 파드 생성 curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/5/node3-pod3.yaml kubectl apply -f node3-pod3.yaml # 파드 IP 정보 확인 kubectl get pod -o wide calicoctl get wep
파드의 IP가 직접 사용되는것을 확인합니다.
# 파드 Shell 접속(zsh) kubectl exec -it pod1 -- zsh ## 파드 Shell 에서 아래 입력 ping <pod2 혹은 pod3 IP> # 파드가 동작하는 노드의 eth0(예시)에서 패킷 덤프 tcpdump -i <eth0> -nn icmp tcpdump -i ens5 -nn icmp # [실습환경 A Type] tcpdump -i enp0s8 -nn icmp # [실습환경 B Type] # 파일로 저장 후 해당 파일을 다운받아서 확인(wireshark 등 사용) tcpdump -i <eth0> icmp -w /tmp/calico-direct.pcap tcpdump -i ens5 icmp -w /tmp/calico-direct.pcap # [실습환경 A Type] tcpdump -i enp0s8 icmp -w /tmp/calico-direct.pcap # [실습환경 B Type]
워커 노드 0으로 ping 실행시 IP대역이 다르므로, 통신을 받지 못하는것을 확인
# 파드 Shell 접속(zsh) kubectl exec -it pod1 -- zsh ## 파드 Shell 에서 아래 입력 ping <pod2 혹은 pod3 IP> # 파드가 동작하는 노드의 eth0(예시)에서 패킷 덤프 tcpdump -i <eth0> -nn icmp tcpdump -i ens5 -nn icmp # [실습환경 A Type] tcpdump -i enp0s8 -nn icmp # [실습환경 B Type] # 파일로 저장 후 해당 파일을 다운받아서 확인(wireshark 등 사용) tcpdump -i <eth0> icmp -w /tmp/calico-direct.pcap tcpdump -i ens5 icmp -w /tmp/calico-direct.pcap # [실습환경 A Type] tcpdump -i enp0s8 icmp -w /tmp/calico-direct.pcap # [실습환경 B Type]
worker node 0은 서브넷이 다름!
CrossSubnet 모드
노드 간 같은 네트워크 대역(Direct 모드로 동작), 노드 간 다른 네트워크 대역(IPIP 모드로 동작)# CrossSubnet 모드 설정 calicoctl patch ippool default-ipv4-ippool -p '{"spec":{"ipipMode":"CrossSubnet"}}' # 모드 확인 calicoctl get ippool -o wide NAME CIDR NAT IPIPMODE VXLANMODE DISABLED SELECTOR default-ipv4-ippool 172.16.0.0/16 true CrossSubnet Never false all() # 파드 생성 kubectl apply -f node3-pod3.yaml calicoctl get wep # 호스트 라우팅 정보 확인 route -n | grep UG root@ip-172-20-63-146:~# route -n | grep UG 100.105.79.128 172.20.61.184 255.255.255.192 UG 0 0 0 ens5 # 노드간 같은 네트워크 대역 - Direct 모드 100.125.78.64 172.20.59.153 255.255.255.192 UG 0 0 0 ens5 # 노드간 같은 네트워크 대역 - Direct 모드 100.127.64.128 172.20.64.181 255.255.255.192 UG 0 0 0 tunl0 # 노드간 다른 네트워크 대역 - IPIP 모드 # 파드 Shell 접속(zsh) kubectl exec -it pod1 -- zsh ## 파드 Shell 에서 아래 입력 ping <pod2 혹은 pod3 IP>
내부에서는 Direct, 외부로는 tunl0이 설정되는것을 확인할 수 있습니다.
K8S 클러스터 네트워크 대역과 IDC 내부망 네트워크 대역간 직접 통신 ↔ BGP 로 네트워크 대역을 전파
출처 - CloudNet@
IDC망을 관리하는 네트워크 팀과 협조하여 K8S 클러스터와의 통신 간 효율적인 네트워크 환경을 구성하시길 권장합니다.
파드 간 통신이 노드와 노드 구간에서는 VXLAN 인캡슐레이션을 통해서 이루어 집니다.
출처 - CloudNet@
다른 노드 간의 파드 통신은 vxlan 인터페이스를 통해 L2 프레임이 UDP - VXLAN에 감싸져서 상대측 노드로 도달 후 vxlan 인터페이스에서 Outer 헤더를 제거하고 내부의 파드와 통신
BGP 미사용, VXLAN L3 라우팅을 통해서 동작
Azure 네트워크에서도 사용 가능 🙆🏻 (UDP를 사용하므로)
Calico 의 다양한 네크워크 모드 환경 위에서 WireGuard 터널을 자동 생성 및 파드 트래픽을 암호화하여 노드간 전달합니다.
WireGuard 소개
WireGuard는 구닥다리 IPsec 및 OpenVPN의 대항마로 등장한 open source VPN project 이며 작년, Linux 5.6 커널에 WireGuard 1.0.0 기본 패키지로 탑재되었다.
정말 간결한 코드 구조와 빠른 성능 (모든 것이 kernel에서 동작하고, 주요 암호 알고리즘에 대해서 병렬처리하므로써 빠른 속도를 자랑함)
WireGuard는 보시다시피 경쟁자들인 IPsec, SoftEther VPN, OpenVPN 등과 비교할 때, 코드 size(Line of Codes)가 현격하게 작다.
코드량이 많지 않으니 그만큼 철저히 검증될 가능성이 높고, 예상치 못한 곳에서의 버그로 인한 취약점이 발생할 가능성이 상대적으로 적다는 얘기가 된다.
WireGuard 설정 및 확인합니다.
# 설정 calicoctl get felixconfiguration -o yaml calicoctl patch felixconfiguration default --type='merge' -p '{"spec":{"wireguardEnabled":true}}' # 확인 calicoctl get felixconfiguration default -o yaml | grep wireguardEnabled root@k8s-m:~/yaml# calicoctl get felixconfiguration default -o yaml | grep wireguardEnabled wireguardEnabled: true calicoctl get node -o yaml | grep wireguardPublicKey calicoctl get node <노드 Name> -o yaml | grep wireguardPublicKey root@k8s-m:~/yaml# calicoctl get node k8s-w1 -o yaml | grep wireguardPublicKey wireguardPublicKey: BToK9bLEhMaPUJsuKy3KdrxVOpklyo0qlGRdMN6lHWc= # wireguard.cali 인터페이스 확인 ip -c -d addr show wireguard.cali root@k8s-w1:~# ip -c -d addr show wireguard.cali 12: wireguard.cali: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1440 qdisc noqueue state UNKNOWN group default qlen 1000 link/none promiscuity 0 minmtu 0 maxmtu 2147483552 wireguard numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 inet 172.16.228.74/32 scope global wireguard.cali valid_lft forever preferred_lft forever ifconfig wireguard.cali root@k8s-w1:~# ifconfig wireguard.cali wireguard.cali: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1440 inet 172.16.228.69 netmask 255.255.255.255 destination 172.16.228.69 unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC)
사설키 등 와이어 가드 정보를 확인합니다.
# wireguard.cali 설정 확인 : 통신 포트, Peer/Endpoint 정보, 패킷 암호화를 위한 공개키/사설키 정보 wg showconf wireguard.cali root@k8s-w1:~# wg showconf wireguard.cali [Interface] ListenPort = 51820 FwMark = 0x100000 PrivateKey = AIgTihI2p4icwVMR4sIvuVaSqwKlkxMImQp4A/Gm+Gg= [Peer] PublicKey = BToK9bLEhMaPUJsuKy3KdrxVOpklyo0qlGRdMN6lHWc= AllowedIPs = 172.16.228.64/26, 172.16.228.69/32, 172.16.228.67/32 Endpoint = 192.168.100.101:51820 [Peer] PublicKey = 9TCD8hG6SLutZSOZSzQeqj6O0icJAxA3RPIipcBKBxs= AllowedIPs = 172.16.197.0/26, 172.16.197.3/32, 172.16.197.5/32 Endpoint = 192.168.100.103:51820 [Peer] PublicKey = Ercb/0pNZ+I1ELOkiXlWbZA9J0Fjt7XqsstDH4GhNmI= AllowedIPs = 172.16.46.3/32, 172.16.46.0/26, 172.16.46.5/32 Endpoint = 192.168.100.102:51820 # Peer 의 정보(고유한 index) wg show interface: wireguard.cali public key: 8TNaYyzzc1N4SHfqE+Y5b4rMBKX/lqPe0tWO/h8sOB4= private key: (hidden) listening port: 51820 fwmark: 0x100000 peer: 6WtZqEKSmoSKiFp20fhk/jyTcrTqf9qshyZI1HvE9Qk= endpoint: 192.168.10.102:51820 allowed ips: 172.16.184.0/32, 172.16.184.0/24, 172.16.184.1/32 peer: +fOEOJgFxueIbrp709iB4F4gFRb2ny4lWKbxCNNfczM= endpoint: 192.168.20.100:51820 allowed ips: 172.16.34.0/32, 172.16.34.0/24, 172.16.34.1/32 peer: d2LgXvRo4DwsyhiLXUn9TEt6D3l4pFIVlCD7KESR/m0= endpoint: 192.168.10.101:51820 allowed ips: 172.16.158.0/32, 172.16.158.0/24, 172.16.158.1/32 # 키 정보 확인 wg show all public-key wireguard.cali 8TNaYyzzc1N4SHfqE+Y5b4rMBKX/lqPe0tWO/h8sOB4= wg show all private-key wireguard.cali kJbrfATGFP2v4sl+Wqg1Gv8zwFpIXshYFFD3udMDd3k= wg show all preshared-keys wireguard.cali 6WtZqEKSmoSKiFp20fhk/jyTcrTqf9qshyZI1HvE9Qk= (none) wireguard.cali +fOEOJgFxueIbrp709iB4F4gFRb2ny4lWKbxCNNfczM= (none) wireguard.cali d2LgXvRo4DwsyhiLXUn9TEt6D3l4pFIVlCD7KESR/m0= (none) # 그외 키타 정보 wg show all dump wg show all endpoints wg show all peers wg show all transfer wg show all persistent-keepalive
네트워크 정책(Network Policy)
네트워크 정책(Network Policy)은 쿠버네티스 클러스터 내부에서 파드 간에 통신할 경우 트래픽 룰을 규정하는 것이다.
네트워크 정책을 사용하지 않을 경우 클러스터 내부의 모든 파드는 서로 통신이 가능하다.
그러나 네트워크 정책을 사용할 수 있다면, 네임스페이스별로 트래픽을 전송하지 못하게 하거나
기본적으로 모든 파드 간 통신을 차단하고 특정 파드 간 통신만 허용하는 화이트리스트 방식을 사용할 수 있다.
또한 CNI(Calico, Cilium 등)에서 네트워크 정책을 지원해야 한다
출처 - CloudNet@
네트워크 정책 구성
네트워크 정책은 인그레스(Ingress 수신)과 이그레스(Egrss 송신)로 구성되어 있다.
인그레스는 인바운드 방향의 트래픽 룰을 설정하고, 이그레스는 아웃바운드 방향의 트래픽 룰을 설정한다.
설정 범위를 podSelector 로 지정한다. 네트워크 정책은 네임스페이스별로 생성해야 한다.네트워크 정책 예시
sample-networkpolicy.yamlapiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: sample-networkpolicy namespace: default # 보안 정책을 생성할 네임스페이스 지정 spec: podSelector: # 설정할 대상 파드를 여기에 기입 # 레이블 셀렉터이므로 복수의 파드를 대상으로 할 수 있음. policyTypes: - Ingress # 인그레이스 룰을 생성하는 경우 명시 - Egress # 이그레스 룰을 생성할 경우 명시 ingress: - from: # 인그레스 룰을 여기에 기입(이그레스 룰과 형식은 동일) ports: # 이 인그레스 룰로 허가할 수신 포트 번호와 프로토콜 기입 egress: - to: # 이그레스 룰을 여기에 기입(인그레스 룰과 형식은 동일) ports: # 이 이그레스 룰로 허가할 송신 포트 번호와 프로토콜 기입
Use Prometheus configured for Calico components to get valuable metrics about the health of Calico.
For Calico, the “jobs” that Prometheus can harvest metrics from are the Felix and Typha
You can configure Felix, Typha, and/or kube-controllers to provide metrics to Prometheus.
Configure Calico to enable metrics reporting
# Felix configuration calicoctl get felixconfiguration -o yaml calicoctl patch felixconfiguration default --patch '{"spec":{"prometheusMetricsEnabled": true}}' # Creating a service to expose Felix metrics : Felix by default uses port 9091 TCP to publish its metrics. kubectl apply -f - <<EOF apiVersion: v1 kind: Service metadata: name: felix-metrics-svc namespace: kube-system spec: clusterIP: None selector: k8s-app: calico-node ports: - port: 9091 targetPort: 9091 EOF kubectl get svc,ep -n kube-system felix-metrics-svc # kube-controllers configuration : Prometheus metrics are enabled by default on TCP port 9094 for calico-kube-controllers ## Creating a service to expose kube-controllers metrics calicoctl get kubecontrollersconfiguration default -o yaml kubectl apply -f - <<EOF apiVersion: v1 kind: Service metadata: name: kube-controllers-metrics-svc namespace: kube-system spec: clusterIP: None selector: k8s-app: calico-kube-controllers ports: - port: 9094 targetPort: 9094 EOF kubectl get svc,ep -n kube-system kube-controllers-metrics-svc
Cluster preparation
# Namespace creation kubectl create -f -<<EOF apiVersion: v1 kind: Namespace metadata: name: calico-monitoring labels: app: ns-calico-monitoring role: monitoring EOF kubectl get ns # Service account creation kubectl apply -f - <<EOF apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: calico-prometheus-user rules: - apiGroups: [""] resources: - endpoints - services - pods verbs: ["get", "list", "watch"] - nonResourceURLs: ["/metrics"] verbs: ["get"] --- apiVersion: v1 kind: ServiceAccount metadata: name: calico-prometheus-user namespace: calico-monitoring --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: calico-prometheus-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: calico-prometheus-user subjects: - kind: ServiceAccount name: calico-prometheus-user namespace: calico-monitoring EOF kubectl get sa -n calico-monitoring
Install prometheus
# kubectl apply -f - <<EOF apiVersion: v1 kind: ConfigMap metadata: name: prometheus-config namespace: calico-monitoring data: prometheus.yml: |- global: scrape_interval: 15s external_labels: monitor: 'tutorial-monitor' scrape_configs: - job_name: 'prometheus' scrape_interval: 5s static_configs: - targets: ['localhost:9090'] - job_name: 'felix_metrics' scrape_interval: 5s scheme: http kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: [__meta_kubernetes_service_name] regex: felix-metrics-svc replacement: $1 action: keep - job_name: 'felix_windows_metrics' scrape_interval: 5s scheme: http kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: [__meta_kubernetes_service_name] regex: felix-windows-metrics-svc replacement: $1 action: keep - job_name: 'typha_metrics' scrape_interval: 5s scheme: http kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: [__meta_kubernetes_service_name] regex: typha-metrics-svc replacement: $1 action: keep - job_name: 'kube_controllers_metrics' scrape_interval: 5s scheme: http kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: [__meta_kubernetes_service_name] regex: kube-controllers-metrics-svc replacement: $1 action: keep EOF kubectl get cm -n calico-monitoring prometheus-config # Create Prometheus pod kubectl apply -f - <<EOF apiVersion: v1 kind: Pod metadata: name: prometheus-pod namespace: calico-monitoring labels: app: prometheus-pod role: monitoring spec: nodeSelector: kubernetes.io/os: linux serviceAccountName: calico-prometheus-user containers: - name: prometheus-pod image: prom/prometheus resources: limits: memory: "128Mi" cpu: "500m" volumeMounts: - name: config-volume mountPath: /etc/prometheus/prometheus.yml subPath: prometheus.yml ports: - containerPort: 9090 volumes: - name: config-volume configMap: name: prometheus-config EOF kubectl get pods prometheus-pod -n calico-monitoring -owide
View metrics
# 파드 IP 확인 kubectl get pods prometheus-pod -n calico-monitoring -owide # 파드 IP metrics 엔드포인트 curl 접속 확인 curl <파드 IP>:9090/metrics curl 172.16.34.7:9090/metrics # kubectl apply -f - <<EOF apiVersion: v1 kind: Service metadata: name: prometheus-dashboard-svc namespace: calico-monitoring spec: type: NodePort selector: app: prometheus-pod role: monitoring ports: - protocol: TCP port: 9090 targetPort: 9090 nodePort: 30001 EOF kubectl get svc,ep -n calico-monitoring # 프로메테우스 접속 주소 echo -e "Prometheus URL = http://$(curl -s ipinfo.io/ip):30001" # [실습환경 A Type] echo -e "Prometheus URL = http://192.168.10.10:30001" # [실습환경 B Type]
위의 모든 구성이 완료되면, 프로메테우스에서 구성을 확인할 수 있습니다.
Use Grafana dashboard to view Calico component metrics.
# Provisioning datasource kubectl apply -f - <<EOF apiVersion: v1 kind: ConfigMap metadata: name: grafana-config namespace: calico-monitoring data: prometheus.yaml: |- { "apiVersion": 1, "datasources": [ { "access":"proxy", "editable": true, "name": "calico-demo-prometheus", "orgId": 1, "type": "prometheus", "url": "http://prometheus-dashboard-svc.calico-monitoring.svc:9090", "version": 1 } ] } EOF kubectl get cm -n calico-monitoring # Provisioning Calico dashboards : Here you will create a configmap with Felix and Typha dashboards. kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/grafana-dashboards.yaml # Creating Grafana pod kubectl apply -f - <<EOF apiVersion: v1 kind: Pod metadata: name: grafana-pod namespace: calico-monitoring labels: app: grafana-pod role: monitoring spec: nodeSelector: kubernetes.io/os: linux containers: - name: grafana-pod image: grafana/grafana:latest resources: limits: memory: "128Mi" cpu: "500m" volumeMounts: - name: grafana-config-volume mountPath: /etc/grafana/provisioning/datasources - name: grafana-dashboards-volume mountPath: /etc/grafana/provisioning/dashboards - name: grafana-storage-volume mountPath: /var/lib/grafana ports: - containerPort: 3000 volumes: - name: grafana-storage-volume emptyDir: {} - name: grafana-config-volume configMap: name: grafana-config - name: grafana-dashboards-volume configMap: name: grafana-dashboards-config EOF # kubectl get pod -n calico-monitoring # kubectl apply -f - <<EOF apiVersion: v1 kind: Service metadata: name: grafana namespace: calico-monitoring spec: type: NodePort selector: app: grafana-pod role: monitoring ports: - protocol: TCP port: 3000 targetPort: 3000 nodePort: 30002 EOF kubectl get svc,ep -n calico-monitoring # 그라파나 접속 주소 : 초기 계정 ( admin , admin ) echo -e "Grafana URL = http://$(curl -s ipinfo.io/ip):30002" # [실습환경 A Type] echo -e "Grafana URL = http://192.168.10.10:30002" # [실습환경 B Type]
위의 구성을 완료하면, 그라파나에서 다음과 같이 felix의 각종 지표를 대시보드로 확인할 수 있습니다.
이번 Calico 네트워크 스터디를 통해 쿠버네티스의 고급 네트워킹 솔루션에 대해 심도 있게 이해할 수 있었습니다. 특히 Calico의 다양한 네트워크 모드(Direct, IPIP, VXLAN)와 그 작동 원리를 탐구하며, 각 모드가 파드 간 통신을 어떻게 효율적으로 지원하는지 학습했습니다.
BGP 기반의 Calico 라우팅 기술을 통해 클러스터 내부 및 외부와의 네트워크 연결이 어떻게 최적화되는지 파악하였으며, WireGuard를 활용한 암호화 기능으로 보안이 강화된 통신이 가능함을 확인했습니다.
네트워크 정책(Network Policy)을 활용하여 Calico가 세밀한 트래픽 제어와 보안을 제공하는 방법을 이해하였으며, 인그레스와 이그레스 규칙을 통해 파드 간 통신을 효과적으로 관리하는 방법을 배웠습니다.
또한 Prometheus와 Grafana를 활용한 모니터링 설정을 실습하면서 Calico 컴포넌트의 성능 지표를 실시간으로 수집하고 시각화하는 방법을 익혔습니다. 이는 네트워크 문제 진단과 성능 최적화에 큰 도움이 될 것으로 기대됩니다.
Calico는 복잡하면서도 유연한 네트워킹 솔루션으로서, 쿠버네티스 환경에서 안정적이고 효율적인 네트워크 인프라를 제공합니다. 이번 스터디를 통해 Calico의 기본 원리와 실제 구성 방법을 숙지하게 되었으며, 향후 대규모 쿠버네티스 클러스터의 네트워크 설계 및 문제 해결 시 이 지식을 적극 활용할 수 있을 것입니다. 또한 클라우드 네이티브 환경에서의 네트워크 보안과 성능 최적화에 대한 깊은 인사이트를 얻을 수 있었습니다.