Post

Calico 파드 통신 알아보기

Calico 파드 통신 알아보기

💡 KANS 스터디
CloudNet에서 주관하는 KANS(Kubernetes Advanced Networking Study)으로 쿠버네티스 네트워킹 스터디입니다. 아래의 글은 스터디의 내용을 기반으로 작성했습니다.

스터디에 관심이 있으신 분은 CloudNet Blog를 참고해주세요.

Calico 통신 방식

Calico 이해하기 포스팅에서는 Calico의 아키텍처와 Component에 대해 알아볼 수 있었다. 여기서는 구체적으로 어떻게 파드 통신을 지원하는지 알아본다.

같은 노드에 위치한 파드 통신

파드와 네트워크 통신 흐름은 아래와 같다.

  1. 파드에서 게이트웨이로 패킷 전송 시도
  2. calico# 인터페이스에서 proxy arp로 자신의 MAC 정보를 줌
  3. 호스트로 패킷이 옮겨지고 iptables를 통해 알맞은 파드에게 라우팅

image.png

실습 진행

같은 노드에 파드 2개 배포

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
2
3
4
5
6
7
8
(⎈|HomeLab:N/A) root@k8s-m:~# k get pods -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
pod1   1/1     Running   0          33s   172.16.158.3   k8s-w1   <none>           <none>
pod2   1/1     Running   0          33s   172.16.158.2   k8s-w1   <none>           <none>
(⎈|HomeLab:N/A) root@k8s-m:~# calicoctl get workloadendpoints
WORKLOAD   NODE     NETWORKS          INTERFACE
pod1       k8s-w1   172.16.158.3/32   calice0906292e2
pod2       k8s-w1   172.16.158.2/32   calibd2348b4f67
  • ARP 정보 확인
1
2
3
ip -c -s neigh
192.168.10.101 dev eth0 lladdr ee:ee:ee:ee:ee:ee  used 451/511/451probes 0 STALE
169.254.1.1 dev eth0 lladdr ee:ee:ee:ee:ee:ee  used 159/159/131probes 1 STALE

이제 파드1에 접속하여, 파드2에게 ping 통신을 시도한다.

1
2
kubectl exec pod1 -it -- zsh
ping {pod2 IP}
  • ping을 진행하면서 tcpdump를 통해 위에서 확인 calico# 인터페이스 확인
    • calico# 인터페이스를 통해 통신이 진행되는 것 확인

image.png

해당 dump를 통해 와이어샤크 내용을 보면, POD2가 게이트웨이 접속정보를 물어보고, calico interface가 ee:ee:ee:ee:ee:ee라고 알려주는 모습을 확인할 수 있다.

  • 아래는 VETH2에 덤프를 뜬 모습이다.
    1. 게이트웨이 정보(169.254.1.1)에 대한 질의를 cali# MAC주소로 응답
    2. pod2가 자신의 arp 정보 질의에 자신의 MAC 주소로 응답

image.png

이제 ARP 테이블을 확인하면 아래와 같이 추가됐다.

image.png

또한 ip link show를 통해 확인하면 아래와 같이 cali# 인터페이스는 동일한 맥 주소 ee:ee:ee:ee:ee:ee 를 사용하는 것을 볼 수 있는데

image.png

스터디에서 아래와 같이 설명해주셨다.

일부 커널이 고정 맥 주소 생성이 안되서, 칼리코가 자체 맥을 생성한다. 또한 파드와 cali#(veth pair) 는 **point-to-point routed interfaces 를 사용하기 때문에 호스트의 데이터링크 레이어(L2 Layer) 에 도달하지 않아서, 모든 cali# 가 동일한 맥 주소를 사용해도 문제가 없다

다른 노드에 위치한 파드 통신

다른 노드에 위치한 파드 통신을 위해선 터널링이 필요하다. calico는 IPIP 모드를 통해 이뤄진다.

  1. 해당 파드가 다른 노드에 위치한 것은 Bird의 광고를 통해 파악한다.
  2. tunl0 인터페이스를 통해 IPIP 터널링이 진행된다.

파드 배포

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
cat node2-pod2.yaml
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

interface 확인

1
2
3
4
root@k8s-m:~# calicoctl get workloadendpoints
WORKLOAD   NODE     NETWORKS          INTERFACE
pod1       k8s-w1   172.16.158.5/32   calice0906292e2
pod2       k8s-w2   172.16.184.1/32   calibd2348b4f67
1
2
3
4
k get po -o wide
NAME   READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
pod1   1/1     Running   0          2m39s   172.16.158.5   k8s-w1   <none>           <none>
pod2   1/1     Running   0          2m39s   172.16.184.1   k8s-w2   <none>           <none>

호스트 라우팅 정보 확인

각 노드에 해당하는 대역은 tunl0 인터페이스와 연결된 것을 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
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    0.0.0.0         255.255.255.0   U     0      0        0 *
172.16.116.1    0.0.0.0         255.255.255.255 UH    0      0        0 calic04819f12a9
172.16.116.2    0.0.0.0         255.255.255.255 UH    0      0        0 cali357b53e100c
172.16.116.3    0.0.0.0         255.255.255.255 UH    0      0        0 cali76abd27fd49
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

ping 통신 진행

1
2
kubectl exec pod1 -it -- zsh
ping {pod2 ip}

통신된 핑을 tcpdump를 통해 캡처하여 wireshark를 통해 확인했다.

  • Ipv4 Layer가 2개 있는 것을 확인할 수 있다.
  • 바깥쪽이 Node IP 대역, 안쪽이 파드 IP 대역을 확인할 수 있다.

image.png

패킷을 눌러 자세하게 살펴보면 IPIP 프로토콜도 확인할 수 있다.

image.png

외부 통신

Iptables를 통해 해당 노드의 IP 주소로 NAT되어 연결된다. 이때 사용하는 MASQUERADE는 iptables에서 사용하는 NAT(Network Address Translation)의 한 형태라고 한다.

테스트 파드 배포

1
2
3
4
5
6
7
8
9
10
11
12
13
cat node1-pod1.yaml
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

인터페이스 정보 확인

1
2
3
root@k8s-m:~# calicoctl get workloadEndpoint
WORKLOAD   NODE     NETWORKS          INTERFACE
pod1       k8s-w1   172.16.158.4/32   calice0906292e2

NAT 정보 확인 “MASQUERADE” Rule

1
2
3
4
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 정보 확인

pod CIDR 대역임을 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
ipset list cali40masq-ipam-pools
Name: cali40masq-ipam-pools
Type: hash:net
Revision: 7
Header: family inet hashsize 1024 maxelem 1048576 bucketsize 12 initval 0x65107aa4
Size in memory: 504
References: 1
Number of entries: 1
Members:
172.16.0.0/16

ping 통신 진행

1
2
k exec pod1 -it -- zsh
ping {pod2 ip}
  • cali# 인터페이스 사용유무 확인

image.png

  • 호스트 eth 인터페이스 사용유무 확인

image.png

calico 설정을 natOutgoing: false 로 변경하면 외부와의 통신이 막힌다. 아래의 코드를 통해 확인해볼 수 있다.

1
calicoctl get ippool default-ipv4-ippool -o yaml | sed -e "s/natOutgoing: true/natOutgoing: false/" | calicoctl apply -f -

변경 후 NAT Rule이 없어진 것 확인

image.png

ping을 통해 외부와 통신이 불가능한 것을 아래와 같이 확인할 수 있다.

image.png

This post is licensed under CC BY 4.0 by the author.