본문 바로가기

study/KANS 3기

KANS 3기 3주차 첫번째

 

.. 매번 스터디를 참여해왔지만 이렇게 매운 맛은 처음입니다....ㅠ

그럼 바로 공유 시작하겠습니다!

 

 

Calico CNI 알아보기

 

Calico components - Docs

https://docs.tigera.io/calico/latest/reference/architecture/overview

 

 

-데몬셋으로 각 노드에 calico-node 파드가 동작하여, 해당 파드에 bird, felix, confd 등이 동작 + Calico 컨트롤러 파드디플로이먼트로 생성

# 버전 확인 - 링크
## kdd 의미는 쿠버네티스 API 를 데이터저장소로 사용
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

# 칼리코 IPAM 정보 확인 : 칼리코 CNI 를 사용한 파드가 생성된 노드에 podCIDR 네트워크 대역 확인 - 링크
calicoctl ipam show

# Block 는 각 노드에 할당된 podCIDR 정보
calicoctl ipam show --show-blocks
calicoctl ipam show --show-borrowed
calicoctl ipam show --show-configuration


Quiz. 바로 위 Calico IPAM 과 아래 출력되는 IPAM 의 차이는 무엇일까요? 우선순위 확인 - 링크 , Flannel 과 차이
- 별도의 IPAM 이 있다면 무엇을 할 수 있을까요? (예. 특정 파드/네임스페이스에 파드의 네트워크 대역을 추가 및 삭제)
1. Kubernetes annotations
2. CNI configuration (Calico IPAM)
3. IP pool node selectors

# 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 을 사용
      },
...

# 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 endpoint (파드)의 정보 확인 : WORKLOAD 는 파드 이름이며, 어떤 노드에 배포되었고 IP 와 cali 인터페이스와 연결됨을 확인
calicoctl get workloadEndpoint
calicoctl get workloadEndpoint -A
calicoctl get workloadEndpoint -o wide -A

# 노드에서 컨테이너(프로세스) 확인 : pstree
ps axf
   4405 ?        Sl     0:09 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id dd532e5efaad436ebe7d10cdd3bb2ffe5a2873a0604ce3b
   4425 ?        Ss     0:00  \_ /pause
   4740 ?        Ss     0:00  \_ /usr/local/bin/runsvdir -P /etc/service/enabled
   4811 ?        Ss     0:00      \_ runsv allocate-tunnel-addrs
   4819 ?        Sl     0:00      |   \_ calico-node -allocate-tunnel-addrs
   4812 ?        Ss     0:00      \_ runsv bird
   4994 ?        S      0:00      |   \_ bird -R -s /var/run/calico/bird.ctl -d -c /etc/calico/confd/config/bird.cfg
   4813 ?        Ss     0:00      \_ runsv cni
   4822 ?        Sl     0:00      |   \_ calico-node -monitor-token
   4814 ?        Ss     0:00      \_ runsv bird6
   4993 ?        S      0:00      |   \_ bird6 -R -s /var/run/calico/bird6.ctl -d -c /etc/calico/confd/config/bird6.cfg
   4815 ?        Ss     0:00      \_ runsv confd
   4820 ?        Sl     0:00      |   \_ calico-node -confd
   4816 ?        Ss     0:00      \_ runsv felix
   4824 ?        Sl     0:54      |   \_ calico-node -felix
   4817 ?        Ss     0:00      \_ runsv node-status-reporter
   4823 ?        Sl     0:00      |   \_ calico-node -status-reporter
   4818 ?        Ss     0:00      \_ runsv monitor-addresses
   4825 ?        Sl     0:00          \_ calico-node -monitor-addresses

 

-felix (필릭스) : Host의 Network Inteface, Route Table, iptables을 관리를 합니다

# 칼리코 필릭스를 통한 IPTables 규칙 설정 확인
iptables -t filter -S | grep cali
...

iptables -t nat -S | grep cali
...

 

 

파드(Pod) ↔ 파드간 통신

동일 노드 내의 파드 간 통신은 내부에서 직접 통신됨

- iptables FORWARD Rule 에 정책(허용) 사용

- calice# 인터페이스에 proxy arp 설정으로 파드에서 바라보는 게이트웨이의 MAC 정보를 파드가 전달 받음

- 동일 노드 내에 파드 간 통신에서는 tunnel 인터페이스는 미 관여

- 참고 링크 : Proxy ARP - 링크

 

[오리뎅이의 LAN 통신 이야기 - 5] Proxy ARP가 없다면?

안녕하세요? 오리뎅이입니다.   지난 시간까지 삼 테이블(Routing Table, ARP Table, MAC T...

blog.naver.com

 

파드 배포 전 기본 상태 확인

 

파드 생성 전 노드(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

 

 

 

파드 배포 후 상태 확인

노드(k8s-w1)에 파드 2개 생성

- node1-pod2.yaml : 노드이름(nodeName)은 kubectl get node 출력되는 Name 을 사용

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

 

파드 생성 후 확인

# [터미널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

 

 

파드 생성 된 이후 다시 정보 확인

# 네트워크 인터페이스 정보 확인 : calice#~ 2개 추가됨!, 각각 net ns(네임스페이스) 0, 1로 호스트와 구별됨
ip -c link
root@k8s-w1:~# ip -c link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 02:70:da:68:71:43 brd ff:ff:ff:ff:ff:ff
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:1b:e3:db brd ff:ff:ff:ff:ff:ff
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
    link/ether 02:42:34:f0:2c:88 brd ff:ff:ff:ff:ff:ff
5: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
8: calibd2348b4f67@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP mode DEFAULT group default
    link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid cni-348afd47-fece-7c08-4488-9046da1e6139
9: calice0906292e2@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP mode DEFAULT group default
    link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid cni-3342c988-81a5-ebfa-058d-193dbbcb1d81

# 네트워크 네임스페이스 확인 : 아래 2개 pause(infra 컨테이너)가 각각 파드별로 생성됨 - 위 link-netnsid 0, link-netnsid 1 매칭됨
lsns -t net
root@k8s-w1:~# lsns -t net
        NS TYPE NPROCS   PID USER     NETNSID NSFS                                                COMMAND
4026531840 net     131     1 root  unassigned                                                     /sbin/init
4026532216 net       2 31336 65535          0 /run/netns/cni-348afd47-fece-7c08-4488-9046da1e6139 /pause
4026532277 net       2 31372 65535          1 /run/netns/cni-3342c988-81a5-ebfa-058d-193dbbcb1d81 /pause

# 파드의 IP/32bit 호스트 라우팅 대역이 라우팅 테이블에 추가됨
ip -c route
root@k8s-w1:~# ip -c route
172.16.158.1 dev calibd2348b4f67 scope link
172.16.158.2 dev calice0906292e2 scope link
...

# (옵션) iptables rule 갯수 확인 : 필터(filter)에 기본 39 에서 91개로 룰(rule)이 많이 추가 되었다 >> 파드가 많아지면 rule 갯수는? >> 노드별로 똑같나요? 다른가요?
root@k8s-w1:~# iptables -t filter -S | grep cali | wc -l
91
root@k8s-w1:~# iptables -t nat -S | grep cali | wc -l
15

 

175개는 Pod가 있을때고 117는 pod를 삭제했을 때의 숫자다

 

 

 

 

파드에 Shell 접속 후 확인

# 마스터 노드에서 아래 실행
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

 

파드 2 Shell 접속

# 마스터 노드에서 아래 실행
kubectl exec pod2 -it -- zsh
...
# 아래 처럼 if12 는 호스트 네트워크 인터페이스 12번인 calice0906292e2와 veth 연결되어 있다
# IP는 32bit 서브넷을 가진다
pod2> ip -c addr
...
4: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP group default
    link/ether 7e:61:c6:fe:4f:8f brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.16.228.79/32 brd 172.16.228.79 scope global eth0
       valid_lft forever preferred_lft forever

# 라우팅 정보에 169.254.1.1 를 디폴트 게이트웨이 주소로 사용
pod2> 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 neighbor show

 

 

파드간 통신 실행 이해를 위한 준비

노드에서 실행)
# iptables 필터 테이블에 FORWARD 리스트 중 cali-FORWARD 룰 정보를 필터링해서 watch 로 확인
watch -d -n 1 "iptables -v --numeric --table filter --list FORWARD | egrep '(cali-FORWARD|pkts)'" 

# (마스터노드) 파드 연결된 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 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

# 파드1 혹은 파드2에 veth 로 연결된 호스트 네트워크 인터페이스 calice# 중 1개 선택해서 tcpdump
tcpdump -i $VETH1 -nn
tcpdump -i $VETH2 -nn

 

 

 

질문?!

파드1 → 파드2 간 통신이 어떻게 가능한걸까요? 파드는 32bit IP를 가지고 있고 GW 는 169.254.1.1 인 상황입니다!

파드1 → 파드2 ping 통신 및 확인

# 파드1 Shell 에서 실행 : 정상 통신!
ping -c 10 <파드2 IP>

# 게이트웨이 169.254.1.1 의 MAC 주소를 ARP 에 의해서 학습되었다
ip -c -s neigh

# 노드에서 확인
# iptables 에 기본 FORWARD 는 DROP 이지만, 아래 cali-FORWARD Rule에 의해 허용되며, pkts 카운트가 증가한다
iptables -v --numeric --table filter --list FORWARD | egrep '(cali-FORWARD|pkts)'
watch -d "iptables -v --numeric --table filter --list FORWARD | egrep '(cali-FORWARD|pkts)'"

# 파드1에서 게이트웨이의 IP인 169.254.1.1 의 MAC 주소를 알기 위해서 ARP Request 를 보낸다
# 이때 veth 연결된 calice#~ 에 proxy arp 설정이 되어 있고, 자신의 mac 주소(ee:ee:ee:ee:ee:ee)를 알려주고, 이후 정상 통신됨
tcpdump -i $VETH1 -nn
tcpdump -i $VETH2 -nn
root@k8s-w1:~# tcpdump -i calice0906292e2 -nn
08:25:44.216545 ARP, Request who-has 169.254.1.1 tell 172.16.228.78, length 28
08:25:44.216566 ARP, Reply 169.254.1.1 is-at ee:ee:ee:ee:ee:ee, length 28
08:25:45.144618 IP 172.16.228.78 > 172.16.228.79: ICMP echo request, id 45451, seq 7, length 64
08:25:45.144674 IP 172.16.228.79 > 172.16.228.78: ICMP echo reply, id 45451, seq 7, length 64

# 호스트에서 calice0906292e2 의 MAC 주소 다시 확인
root@k8s-w1:~# ip -c -d link
...
12: calice0906292e2@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP mode DEFAULT group default
    link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0 minmtu 68 maxmtu 65535
    veth addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535

 

덤프 확인

 

삭제

kubectl delete -f node1-pod2.yaml

 

 

 

 

 

파드 → 외부(인터넷) 통신

파드에서 외부(인터넷) 통신 시에는 해당 노드의 네트워크 인터페이스 IP 주소로 MASQUERADE(출발지 IP가 변경) 되어서 외부에 연결됨

-calico 기본 설정은 natOutgoing: true 이다. 즉, iptables 에 MASQUERADE Rule(룰) 에 의해서 외부에 연결됨

-calice# 인터페이스에 proxy arp 설정

-파드와 외부간 직접 통신에서는 tunnel 인터페이스는 미 관여

 

 

파드 배포 전 기본 상태 확인

-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

 

파드 배포 및 외부 통신 확인

 

노드(k8s-w1)에 파드 1개 생성

- node1-pod1.yaml : : 노드이름(nodeName)은 kubectl get node 출력되는 Name 을 사용

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

 

파드 생성 후 확인

# 파드 생성
curl -O https://raw.githubusercontent.com/gasida/NDKS/main/4/node1-pod1.yaml
kubectl apply -f node1-pod1.yaml

# 생성된 파드 정보 확인
kubectl get pod -o wide

 

외부 통신 확인

준비

# 노드에서 실행
# iptables NAT MASQUERADE 모니터링 : pkts 증가 확인
watch -d 'iptables -n -v -t nat --list cali-nat-outgoing'

# (마스터노드) 파드 연결된 veth 를 변수를 확인
VETH1=$(calicoctl get workloadEndpoint | grep pod1 | awk '{print $4}')
echo $VETH1

# (워커노드1) 위에서 확인한 파드 연결된 veth 를 변수에 지정
VETH1=calice0906292e2

# 패킷 덤프 실행 >> 어떤 인터페이스에서 패킷 캡쳐 확인이 되나요?
tcpdump -i any -nn icmp
tcpdump -i $VETH1 -nn icmp
tcpdump -i tunl0 -nn icmp
tcpdump -i ens5 -nn icmp

확인

# 파드에서 외부 정상 통신 확인
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

# 패킷 덤프 내용 확인
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

# 아래 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

# 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

 

삭제

kubectl delete pod pod1

 

 

 

 

다른 노드에서 파드파드간 통신

다른 노드 환경에서 파드 간 통신 시에는 IPIP 터널(기본값) 모드를 통해서 이루어 집니다

 

 - 각 노드에 파드 네트워크 대역은 Bird 에 의해서 BGP 로 광고 전파/전달 되며, Felix 에 의해서 호스트의 라우팅 테이블에 자동으로 추가 및 삭제 됩니다

 - 다른 노드 간의 파드 통신은 tunl0 인터페이스를 통해 IP 헤더에 감싸져서 상대측 노드로 도달 후 tunl0 인터페이스에서 Outer 헤더를 제거하고 내부의 파드와 통신됩니다 - 링크

 

 

 

파드 배포 전 기본 상태 확인

 

- 노드간 BGP 로 Pod 대역 정보 전파 확인

 -노드에서 BGP 에 의해서 전달 받은 정보가 호스트 라우팅 테이블에 존재하는지 확인

# 아래 명령어로 확인 시 나머지 노드들의 파드 대역을 자신의 호스트 라우팅 테이블에 가지고 있고, 해당 경로는 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

 

 

 

파드 배포

노드1과 노드2에 각각 파드 1개씩 생성

 

node2-pod2.yaml : 노드이름(nodeName)은 kubectl get node 출력되는 Name 을 사용

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-w2
  containers:
  - name: pod2
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0

 

파드 생성 후 확인

# 파드 생성
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

파드 생성 후 상태

 

파드간 통신을 처리하는 라우팅 정보 확인 : 각각 상대방 노드의 IP를 게이트웨이로 전달하게 됩니다!

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
...

 

 

파드간 통신 실행 및 확인

-파드간 통신 실행 이해를 위한 준비 ⇒ IPIP(IP Protocol 4 허용이 필요, Azure 는 불가능)

 

지금까지 tunl0 인터페이스가 사용되지 않았는데, 다른 노드의 파드간 통신시에 사용되는지 확인을 해보자

- 노드1 기준 설명

# 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
혹은 패킷을 파일로 추출시
tcpdump -i ens5 -nn proto 4 -w /tmp/calico-enp0s8.pcap

 

 

파드1 → 파드2 ping 통신 및 확인

 

# 마스터 노드에서 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
root@k8s-w2:~# tcpdump -i ens5 -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
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

 

삭제

kubectl delete -f node2-pod2.yaml

 

'study > KANS 3기' 카테고리의 다른 글

KANS 3기 4주차  (0) 2024.09.28
KANS 3기 3주차 두번째  (0) 2024.09.18
KANS 3기 3주차 실습환경 구축  (0) 2024.09.08
KANS 3기 2주차 두번째  (0) 2024.09.07
KANS 3기 2주차 첫번째  (0) 2024.09.07