Post

Flannel CNI 배포하기 [Cilium Study 1주차]

Flannel CNI 배포하기 [Cilium Study 1주차]
Flannel VXLAN은 node 사이 UDP tunnel로 Pod traffic을 감싼다
Source Pod cni0 bridge를 통해 나갑니다.
local bridge 전달
Source node flannel.1 VTEP가 frame을 encapsulate합니다.
UDP 8472로 전송
VXLAN tunnel 두 node 사이에서 Pod packet을 감쌉니다.
remote node 도착
Remote node VTEP가 frame을 decapsulate합니다.
local bridge 전달
Destination Pod 원래 Pod network로 배달됩니다.

underlay가 보는 것은 node to node UDP입니다. 그래서 underlay에는 destination Pod CIDR 경로가 필요하지 않습니다.

PNG 다운로드 원본 이미지 열기

이번 포스트에서는 Flannel CNI를 Kubernetes Cluster에 배포해보도록 하겠습니다.

TL;DR

  • Flannel을 배포해 NotReady 상태이던 노드를 Ready로 만들고 Pod 간 통신을 확인합니다.
  • 기본값으로 두면 Flannel이 NAT 인터페이스인 eth0를 잡으므로, VM 간 통신용 eth1을 쓰도록 인터페이스를 지정해야 합니다.

1. Flannel 배포 전 확인

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#################################
# 클러스터 네트워크 대역 정보 확인
#################################
❯ kubectl cluster-info dump | grep -m 2 -E "cluster-cidr|service-cluster-ip-range" 
                            "--service-cluster-ip-range=10.96.0.0/16",
                            "--cluster-cidr=10.244.0.0/16",   

#################################
# 코어DNS 파드 상태 및 스케줄링 노드 확인 
#################################
# 현재 cni가 존재하지 않기 때문에 coredns가 pod ip를 할당 받지 못해 Pending 상태
❯ kubectl get pod -n kube-system -l k8s-app=kube-dns -o wide 
NAME                       READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
coredns-674b8bbfcf-mrnbj   0/1     Pending   0          61m   <none>   <none>   <none>           <none>
coredns-674b8bbfcf-mx96v   0/1     Pending   0          61m   <none>   <none>   <none>           <none>

#################################
# 네트워크 확인 명령어들
#################################
# 네트워크 인터페이스 상태 출력
ip -c link   # 모든 네트워크 인터페이스 목록과 상태(UP/DOWN) 확인

# 라우팅 테이블 출력
ip -c route   # 현재 노드의 라우팅 테이블(네트워크 경로) 확인

# Linux 브리지 정보 출력
brctl show   # 브리지 인터페이스 및 연결된 포트 확인

# 현재 iptables 전체 룰 덤프
iptables-save   # filter, nat, mangle 등 모든 테이블의 룰을 일괄 덤프

# NAT 테이블 규칙 확인
iptables -t nat -S   # NAT 테이블의 SNAT/DNAT 규칙 목록 출력

# FILTER 테이블 규칙 확인
iptables -t filter -S   # 필터링 테이블의 INPUT, FORWARD, OUTPUT 체인 룰 출력

# MANGLE 테이블 규칙 확인
iptables -t mangle -S   # 패킷 마킹이나 TTL 조작 등의 MANGLE 테이블 규칙 출력

# CNI 설정 파일 구조 확인
tree /etc/cni/net.d/   # 설치된 CNI 플러그인 설정 파일 목록 및 디렉터리 구조 확인 (비어있음)

2. Flannel CNI 배포하기

이전 글에서 확인한 바와 같이 eth0 Interface는 VirtualBox의 NAT 네트워크 모드로 동작하기 위해 사용되기 때문에, flannel이 eth1을 사용하도록 수정했습니다.

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#################################
# flannel cni 배포 전 네임스페이스 및 privileged 정책을 허용하는 레이블 설정
#################################
kubectl create ns kube-flannel
kubectl label --overwrite ns kube-flannel pod-security.kubernetes.io/enforce=privileged

#################################
# Helm을 Repository 추가 및 최신 버전, value 확인
#################################
helm repo add flannel https://flannel-io.github.io/flannel/
helm repo list
helm search repo flannel
helm show values flannel/flannel

#################################
# k8s 관련 트래픽 통신 동작하는 NIC 지정 (eth1번 지정)
#################################
cat << EOF > flannel-values.yaml
podCidr: "10.244.0.0/16"

flannel:
  args:
  - "--ip-masq"
  - "--kube-subnet-mgr"
  - "--iface=eth1"  
EOF

#################################
# helm 설치
#################################
helm install flannel --namespace kube-flannel flannel/flannel -f flannel-values.yaml
helm list -A

# Pod Status 확인
kubectl get pod -n kube-flannel -l app=flannel
# NIC 지정 Argument와 event 확인
kubectl describe pod -n kube-flannel -l app=flannel

#################################
# flannel 확인 (Control Plane Node 에서)
#################################
tree /opt/cni/bin/ 
tree /etc/cni/net.d/
cat /etc/cni/net.d/10-flannel.conflist | jq
❯ kubectl describe cm -n kube-flannel kube-flannel-cfg
...
net-conf.json:
----
{
  "Network": "10.244.0.0/16",
  "EnableNFTables": false,
  "Backend": {
    "Type": "vxlan"
  }
}

#################################
# 설치 전과 비교
#################################
ip -c link # flannel interface 추가
❯ ip -c route | grep 10.244.
...
10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1 
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink 
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink 

# 통신 확인
ping -c 1 10.244.1.0 
ping -c 1 10.244.2.0

brctl show
iptables-save
iptables -t nat -S
iptables -t filter -S

# k8s-w1, k8s-w2 정보 확인 (NIC & bridge Network 확인)
for i in w1 w2 ; do echo ">> node : cilium-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@cilium-$i ip -c link ; echo; done
for i in w1 w2 ; do echo ">> node : cilium-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@cilium-$i ip -c route ; echo; done
for i in w1 w2 ; do echo ">> node : cilium-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@cilium-$i brctl show ; echo; done
for i in w1 w2 ; do echo ">> node : cilium-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@cilium-$i sudo iptables -t nat -S ; echo; done

3. Sample Application 배포 및 확인

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webpod
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webpod
  template:
    metadata:
      labels:
        app: webpod
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - sample-app
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: webpod
        image: traefik/whoami
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: webpod
  labels:
    app: webpod
spec:
  selector:
    app: webpod
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: ClusterIP
EOF


# cilium-m1 노드에 curl-pod 파드 배포
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: curl-pod
  labels:
    app: curl
spec:
  nodeName: cilium-m1
  containers:
    - name: curl
      image: alpine/curl
      command: ["sleep", "36000"]
EOF

## crictl로 현재 어떤 컨테이너가 떠있는지 확인
crictl ps
for i in w1 w2 ; do echo ">> node : cilium-$i <<"; sshpass -p 'vagrant' ssh vagrant@cilium-$i sudo crictl ps ; echo; done

4. 통신 확인

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
27
28
29
30
31
32
33
34
35
36
37
❯ kubectl get pod -l app=webpod -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP           NODE        NOMINATED NODE   READINESS GATES
webpod-697b545f57-5sx89   1/1     Running   0          10m   10.244.1.4   cilium-w1   <none>           <none>
webpod-697b545f57-gjl4j   1/1     Running   0          10m   10.244.2.2   cilium-w2   <none>           <none>

❯ POD1IP=10.244.1.4
❯ kubectl exec -it curl-pod -- curl $POD1IP
Hostname: webpod-697b545f57-5sx89
IP: 127.0.0.1
IP: ::1
IP: 10.244.1.4
IP: fe80::d0a5:c6ff:fea0:e861
RemoteAddr: 10.244.0.2:53908
GET / HTTP/1.1
Host: 10.244.1.4
User-Agent: curl/8.14.1
Accept: */*

❯ kubectl get svc,ep webpod
❯ kubectl exec -it curl-pod -- curl webpod
❯ kubectl exec -it curl-pod -- curl webpod | grep Hostname
❯ kubectl exec -it curl-pod -- sh -c 'while true; do curl -s webpod | grep Hostname; sleep 1; done'
Hostname: webpod-697b545f57-5sx89
Hostname: webpod-697b545f57-gjl4j
Hostname: webpod-697b545f57-5sx89
Hostname: webpod-697b545f57-5sx89
Hostname: webpod-697b545f57-gjl4j
Hostname: webpod-697b545f57-gjl4j

# Service 동작 처리에 iptables 규칙 활용 확인 >> Service 가 100개 , 1000개 , 10000개 증가 되면???
❯ kubectl get svc webpod -o jsonpath="{.spec.clusterIP}"
10.96.216.5
❯ SVCIP=$(kubectl get svc webpod -o jsonpath="{.spec.clusterIP}")
❯ iptables -t nat -S | grep $SVCIP
-A KUBE-SERVICES -d 10.96.216.58/32 -p tcp -m comment --comment "default/webpod cluster IP" -m tcp --dport 80 -j KUBE-SVC-CNZCPOCNCNOROALA
-A KUBE-SVC-CNZCPOCNCNOROALA ! -s 10.244.0.0/16 -d 10.96.216.58/32 -p tcp -m comment --comment "default/webpod cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
❯ for i in w1 w2 ; do echo ">> node : cilium-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@cilium-$i sudo iptables -t nat -S | grep $SVCIP ; echo; done

5. Reference


궁금하신 점이나 추가해야 할 부분은 댓글이나 아래의 링크를 통해 문의해주세요.
Written with KKamJi

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