1. 서비스
1.1 서비스 개념
파드를 통해 사용자에게 서비스를 제공을 할 수 있으나, 파드에 장애가 발생했을 경우 서비스에 가용성을 보장할 수가 없기 때문에, Service를 통해 가용성을 보장합니다
Kubernetes Service를 통해 파드의 로드밸런싱이 가능하며, 파드에 문제가 발생하여 정상적으로 구동시킬 수 없는 경우에는 Service가 자동으로 문제가 발생한 파드는 Service의 EndPoint에서 제외됩니다.
문제가 생겼던 Pod는 Deployment를 통해 다른 IP, Name으로 다시 구동되며, Service의 EndPoint에 자동으로 추가되어, 기존상태를 유지합니다.
1.2 서비스 타입
쿠버네티스 클러스터 외부에서 내부로 트래픽을 받는 방법
Nodeport | |
Load Balancer | |
Ingress |
(1) ClusterIP
서비스를 클러스터 내부 IP에 노출합니다.
클러스터 내에서만 서비스에 도달할 수 있으며, 서비스 타입의 기본값입니다.
apiVersion: v1 kind: Pod metadata: name: nginx labels: app.kubernetes.io/name: proxy spec: containers: - name: nginx image: nginx:stable ports: - containerPort: 80 name: http-web-svc --- apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app.kubernetes.io/name: proxy ports: - name: name-of-service-port protocol: TCP port: 80 targetPort: http-web-svc
(2) NodePort
고정포트로 각 노드의 IP에 서비스를 노출합니다.
NodePort 서비스가 라우팅되는 ClusterIP가 자동으로 생성되며 NodeIP:NodePort를 요청하며, 서비스 외수에서 NodePort 서비스에 접속할 수 있습니다.
--- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-service-nodeport spec: type: NodePort selector: app: nginx ports: # 기본적으로 그리고 편의상 `targetPort` 는 `port` 필드와 동일한 값으로 설정된다. - port: 80 targetPort: 80 # 선택적 필드 # 기본적으로 그리고 편의상 쿠버네티스 컨트롤 플레인은 포트 범위에서 할당한다(기본값: 30000-32767) nodePort: 30007
(3) LoadBalancer
클라우드 공급자의 로드 밸런서를 사용하여 서비스를 외부에 노출시킵니다.
클러스터 외부 IP를 가지고 있기 때문에, 클러스터 외부에서 접근 가능합니다.
외부 로드 밸런서가 라우팅되는 NodePort와 ClusterIP 서비스가 자동으로 생성됩니다.
프라이빗 클라우드 환경에서는 MetalLB를 이용하여 LoadBalancer 타입의 서비스를 이용 할 수 있습니다.
--- apiVersion: apps/v1 kind: Deployment metadata: name: nginx2-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx2-service spec: type: LoadBalancer selector: app: nginx ports: - protocol: TCP port: 8088 targetPort: 80
(4) ExternalName
값과 함께 CNAME 레코드를 리턴하여, 서비스를 externalName 필드의 콘텐츠(ex. foo.bar.example.com) 에 매핑합니다.
2. Ingress
2.1 Ingress Controller
2.2 Ingress
클러스터 내의 서비스에 대한 외부 접근을 관리하는 API 오브젝트이며, 일반적으로 HTTP를 관리합니다.
인그레스는 클러스터 외부에서 클러스터 내부 서비스로 HTTP와 HTTPS 경로를 노출시킵니다.
인그레스 컨트롤러가 있어야 인그레스를 충족할 수 있으며, 인그레스 리소스만 생성한다면 효과가 없습니다.
대표적인 인그레스 컨트롤러: ingress-nginx
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 name: rewrite namespace: default spec: ingressClassName: nginx rules: - host: sllee.com http: paths: - path: / pathType: Prefix backend: service: name: nginx-service port: number: 80
3. 네트워크
3.1 파드 네트워크
문서 상 노드 이름 및 역할
sung-ubuntu01 - Control Plane #1
sung-ubuntu02 - Control Plane #2
sung-ubuntu03 - Control Plane #3
sung-ubuntu04 - Worker Node #1
sung-ubuntu05 - Worker Node #2
(1) 파드 네트워크 흐름
도커에서 POD 네트워크 설명할 경우와 인터페이스 이름이 다릅니다.
도커의 역할
참고1) https://www.docker.com/products/container-runtime/
(2) 파드 네트워크 실습
목표
Pod (Single Container)의 네트워크 설정 확인
root@sung-ubuntu01:~/tmp# cat ubuntu.yaml apiVersion: v1 kind: Pod metadata: name: ubuntu-test spec: containers: - name: ubuntu image: ubuntu:20.04 command: ["/bin/sleep", "3650d"] imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /cache name: cache-volume volumes: - name: cache-volume emptyDir: {} restartPolicy: Always dnsConfig: nameservers: - 8.8.8.8 root@sung-ubuntu01:~/tmp# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES ubuntu-test 1/1 Running 0 6m20s 10.233.99.1 sung-ubuntu04 <none> <none> ###POD 접속 root@sung-ubuntu01:~/tmp# kubectl exec -it ubuntu-test -- bash root@ubuntu-test:/# root@ubuntu-test:/# ping 8.8.8.8 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=54 time=39.6 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=54 time=38.1 ms 64 bytes from 8.8.8.8: icmp_seq=3 ttl=54 time=38.8 ms 64 bytes from 8.8.8.8: icmp_seq=4 ttl=54 time=39.3 ms # apt update # apt install -y net-tools iputils-ping **# 컨테이너의 네트워크 인터페이스 확인** # root@ubuntu-test:/# ifconfig -a eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1480 inet 10.233.99.1 netmask 255.255.255.255 broadcast 0.0.0.0 ether 06:55:84:5a:ac:6b txqueuelen 0 (Ethernet) RX packets 5718 bytes 24026416 (24.0 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3690 bytes 250168 (250.1 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 1000 (Local Loopback) 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 #설명추가 tunl0: flags=128<NOARP> mtu 1480 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 * loopback ip : host 자신을 가리키는 논리적인 인터페이스 **#노드 네트워크 확인** root@sung-ubuntu04:~# ifconfig -a ... tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480 inet 10.233.99.0 netmask 255.255.255.255 tunnel txqueuelen 1000 (IPIP Tunnel) RX packets 60 bytes 8528 (8.5 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 66 bytes 4476 (4.4 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 *mtu 1480인 이유? IPIP 터널을 사용하고 있기 때문에, 캡슐화된 패킷의 크기는 원래 패킷보다 더 크기 때문에 MTU 조절이 필요하다 1480인 이유는 캡슐화된 패킷이 Ethernet 패킷에 포함될 때 전체 크기가 1500을 초과하지 않도록 하기 위해서이다.
1.3 멀티 컨테이너 네트워크 실습
목표
Pod (Multi Container)의 네트워크 설정 확인
root@sung-ubuntu01:~/tmp# cat multi-con.yaml apiVersion: v1 kind: Pod metadata: name: multi-container spec: containers: - name: ubuntu image: ubuntu:20.04 command: ["/bin/sleep", "3650d"] imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /cache name: cache-volume - name: nginx image: nginx ports: - containerPort: 80 volumes: - name: cache-volume emptyDir: {} restartPolicy: Always dnsConfig: nameservers: - 8.8.8.8 root@sung-ubuntu01:~/tmp# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES multi-container 2/2 Running 0 25m 10.233.78.3 sung-ubuntu05 <none> <none> ubuntu-test 1/1 Running 0 57m 10.233.99.1 sung-ubuntu04 <none> <none>
**#ubuntu 컨테이너 접속** root@sung-ubuntu01:~/tmp# kubectl exec -it multi-container -c ubuntu -- bash ### POD 안에서 # apt update # apt install -y net-tools iputils-ping root@multi-container:/# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1480 inet 10.233.78.3 netmask 255.255.255.255 broadcast 0.0.0.0 ether ce:de:b3:90:c1:a7 txqueuelen 0 (Ethernet) RX packets 5206 bytes 23989810 (23.9 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3160 bytes 213900 (213.9 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 1000 (Local Loopback) 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 **# nginx 컨테이너 접속** root@sung-ubuntu01:~/tmp# kubectl exec -it multi-container -c nginx -- bash ### POD 안에서 실행 # apt update # apt install -y net-tools iputils-ping root@multi-container:/# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1480 inet 10.233.78.3 netmask 255.255.255.255 broadcast 0.0.0.0 ether ce:de:b3:90:c1:a7 txqueuelen 0 (Ethernet) RX packets 6287 bytes 33013014 (31.4 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3935 bytes 267591 (261.3 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 1000 (Local Loopback) 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
노드 네트워크 확인
root@sung-ubuntu05:~# ifconfig -a calib4cfe5eb958: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1480 inet6 fe80::ecee:eeff:feee:eeee prefixlen 64 scopeid 0x20<link> ether ee:ee:ee:ee:ee:ee txqueuelen 0 (Ethernet) RX packets 3935 bytes 267591 (267.5 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 6287 bytes 33013014 (33.0 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:6a:17:c5:80 txqueuelen 0 (Ethernet) 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 ens3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.110.104 netmask 255.255.0.0 broadcast 192.168.255.255 inet6 fe80::f816:3eff:fe54:bc4 prefixlen 64 scopeid 0x20<link> ether fa:16:3e:54:0b:c4 txqueuelen 1000 (Ethernet) RX packets 1353299 bytes 1304887824 (1.3 GB) RX errors 0 dropped 88603 overruns 0 frame 0 TX packets 191206 bytes 20789350 (20.7 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 kube-ipvs0: flags=130<BROADCAST,NOARP> mtu 1500 inet 10.233.0.1 netmask 255.255.255.255 broadcast 0.0.0.0 ether 66:2d:b3:6c:50:9a txqueuelen 0 (Ethernet) 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 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 162061 bytes 22298211 (22.2 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 162061 bytes 22298211 (22.2 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 nodelocaldns: flags=130<BROADCAST,NOARP> mtu 1500 inet 169.254.25.10 netmask 255.255.255.255 broadcast 0.0.0.0 ether 16:84:53:46:fe:65 txqueuelen 0 (Ethernet) 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 tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480 #터널 인터페이스 inet 10.233.78.0 netmask 255.255.255.255 tunnel txqueuelen 1000 (IPIP Tunnel) RX packets 69 bytes 9380 (9.3 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 76 bytes 5125 (5.1 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
multi-container 관련 컨테이너 확인
root@sung-ubuntu05:~# docker ps | grep multi-container 64c1938850a2 nginx "/docker-entrypoint.…" 26 minutes ago Up 25 minutes k8s_nginx_multi-container_default_1d0e0776-18b1-4c7f-b05f-20b8c54fb230_0 b4c4045ac777 ubuntu "/bin/sleep 3650d" 26 minutes ago Up 26 minutes k8s_ubuntu_multi-container_default_1d0e0776-18b1-4c7f-b05f-20b8c54fb230_0 1eaedb9c9d55 k8s.gcr.io/pause:3.5 "/pause" 27 minutes ago Up 26 minutes k8s_POD_multi-container_default_1d0e0776-18b1-4c7f-b05f-20b8c54fb230_0
Pause Container
파드 내부의 container들을 위한 일종의 '부모 container' 로서의 역할을 수행합니다.
파드가 실행될 때 Pause Container가 먼저 실행되고 Pause Container의 리눅스 네임스페이스를 파드 내부의 모든 컨테이너들이 상속받아서 사용합니다.
Container들의 부모 프로세스가 Pause Container인 리눅스 네임스페이스에 속하기 때문에 localhost 통신이 가능합니다.
리눅스 namespace
리눅스 커널에서 제공 기능으로 Container의 기반이 되는 기술. 하나의 시스템에서 프로세스를 격리시킬 수 있는 가상화 기술입니다.
1.4 파드 간 통신
Pod 간 route 경로 확인
root@sung-ubuntu01:~/tmp# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES multi-container 2/2 Running 0 25m 10.233.78.3 sung-ubuntu05 <none> <none> ubuntu-test 1/1 Running 0 57m 10.233.99.1 sung-ubuntu04 <none> <none> #ubuntu-test root@ubuntu-test:/# apt install traceroute root@ubuntu-test:/# traceroute 10.233.78.3 traceroute to 10.233.78.3 (10.233.78.3), 30 hops max, 60 byte packets 1 192.168.110.103 (192.168.110.103) 0.202 ms 0.032 ms 0.028 ms #sung-ubuntu04 ens3 2 10.233.78.0 (10.233.78.0) 1.169 ms 0.990 ms 0.928 ms #sung-ubuntu05 tunl0 3 10.233.78.3 (10.233.78.3) 1.096 ms 1.111 ms 1.087 ms #multi-container IP
노드 route table 확인
root@sung-ubuntu04:~# route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface default _gateway 0.0.0.0 UG 100 0 0 ens3 10.233.78.0 sung-ubuntu05.c 255.255.255.0 UG 0 0 0 tunl0 10.233.91.0 sung-ubuntu02.c 255.255.255.0 UG 0 0 0 tunl0 10.233.95.0 sung-ubuntu01.c 255.255.255.0 UG 0 0 0 tunl0 10.233.99.0 0.0.0.0 255.255.255.0 U 0 0 0 * 10.233.99.1 0.0.0.0 255.255.255.255 UH 0 0 0 calie3df4d89b13 10.233.99.2 0.0.0.0 255.255.255.255 UH 0 0 0 calia85a668c715 10.233.112.0 sung-ubuntu03.c 255.255.255.0 UG 0 0 0 tunl0 169.254.169.254 192.168.51.110 255.255.255.255 UGH 100 0 0 ens3 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 192.168.0.0 0.0.0.0 255.255.0.0 U 0 0 0 ens3 root@sung-ubuntu04:~# cat /etc/hosts ... # Ansible inventory hosts BEGIN 192.168.110.100 sung-ubuntu01.cluster.local sung-ubuntu01 192.168.110.101 sung-ubuntu02.cluster.local sung-ubuntu02 192.168.110.102 sung-ubuntu03.cluster.local sung-ubuntu03 192.168.110.103 sung-ubuntu04.cluster.local sung-ubuntu04 192.168.110.104 sung-ubuntu05.cluster.local sung-ubuntu05
참고
https://kubernetes.io/ko/docs/concepts/cluster-administration/networking/
2. kube-proxy
2.1 kube-proxy 개요
노드로 들어오는 네트워크 트래픽을 파드에 로드밸런싱 알고리즘을 사용하여 포워딩합니다.
Network Proxy, Load Balancer 역할을 수행합니다.
kube proxy 특징
각 노드에서 실행됩니다.
UDP, TCP, SCTP를 이용하여 Proxy합니다.
HTTP는 이해하지 못합니다.
로드밸런싱을 제공합니다.
서비스에 도달하는데만 사용됩니다.
출처 - https://kubernetes.io/ko/docs/concepts/cluster-administration/proxies/
2.1.1 쿠버네티스 아키텍처
2.1.2 kube-proxy 파드 확인
root@sung-ubuntu01:~# kubectl -n kube-system get all -o wide | grep kube-proxy pod/kube-proxy-7xwmt 1/1 Running 1 (6d1h ago) 6d3h 192.168.110.101 sung-ubuntu02 <none> <none> pod/kube-proxy-8kdx9 1/1 Running 1 (6d1h ago) 6d3h 192.168.110.103 sung-ubuntu04 <none> <none> pod/kube-proxy-ktr52 1/1 Running 5 6d3h 192.168.110.104 sung-ubuntu05 <none> <none> pod/kube-proxy-l44dw 1/1 Running 1 (6d1h ago) 6d3h 192.168.110.100 sung-ubuntu01 <none> <none> pod/kube-proxy-ssbsg 1/1 Running 1 (6d1h ago) 6d3h 192.168.110.102 sung-ubuntu03 <none> <none> daemonset.apps/kube-proxy 5 5 5 5 5 kubernetes.io/os=linux 6d19h kube-proxy k8s.gcr.io/kube-proxy:v1.22.8 k8s-app=kube-proxy
2.1.3 kube-proxy 모드 옵션 설정
vi kubespray/inventory/sample/group_vars/k8s_cluster/k8s-cluster.yml ... # Kube-proxy proxyMode configuration. # Can be ipvs, iptables kube_proxy_mode: ipvs ...
IPVS(IP Virtual Server): Netfilter Framework 기반으로 구현된 리눅스 커널 레벨에서 동작하는 Layer-4 로드밸런싱 도구입니다. (Netfilter에 포함)
2.1.4 kube-proxy 모드 별 작동방법
iptables 모드 작동 방법
(1) K8s 서비스 생성
(2) control-plane에서 가상 IP주소를 서비스에 할당
(3) 클러스터의 모든 kube-proxy에서 서비스 관찰
(4) 가상IP 주소→서비스로 리다이렉션하는 iptables 규칙 설정
(5) 서비스 규칙과 엔드포인트 규칙 연결
→ 대규모 클러스터(ex. 10,000 서비스)에서 크게 느려집니다.
IPVS 모드 작동 방법
(1) 로드 밸런싱을 위해 설계되었고, 커널-내부 해시 테이블(IPVS 테이블)을 기반으로 합니다.
→ 많은 개수의 서비스에서 일관성 있는 성능을 가질 수 있습니다.
→ 보다 정교한 로드 밸런싱 알고리즘을 가집니다. (least conns, locality, weighted, persistence)
2.1.5 IPVS모드 & iptables 모드 성능 비교
출처 - https://www.tigera.io/blog/comparing-kube-proxy-modes-iptables-or-ipvs/
2.2 kube-proxy 동작방법
가상 IP와 서비스 프록시
쿠버네티스 클러스터의 모든 노드는 kube-proxy를 실행합니다.
kube-proxy는 ExternalName 이외의 유형의 서비스에 대한 가상 IP 형식을 구현합니다.
2.2.1 iptables 모드
kube-proxy iptables 모드 (출처 - https://kubernetes.io/ko/docs/concepts/services-networking/service/ )
2.2.2 ipvs 모드
*hash table로 데이터 저장
2.2.3 IPVS 모드 확인
**kube-proxy IPVS mode를 사용하기 위해서는 OS에서 IPVS를 사용할 수 있는 상태이어야 하며, 클러스터 내 노드에 설치되어야 합니다.** root@sung-ubuntu01:/lib/modules/5.4.0-124-generic/build# systemctl status ipvsadm ● ipvsadm.service - LSB: ipvsadm daemon Loaded: loaded (/etc/init.d/ipvsadm; generated) Active: active (exited) since Thu 2022-08-25 15:29:25 KST; 4 days ago Docs: man:systemd-sysv-generator(8) Tasks: 0 (limit: 9507) Memory: 0B CGroup: /system.slice/ipvsadm.service Aug 25 15:29:24 sung-ubuntu01 systemd[1]: Starting LSB: ipvsadm daemon... Aug 25 15:29:25 sung-ubuntu01 ipvsadm[617]: * ipvsadm is not configured to run. Please edit /etc/default/ipvsadm Aug 25 15:29:25 sung-ubuntu01 systemd[1]: Started LSB: ipvsadm daemon. root@sung-ubuntu01:~# ipvsadm --help ipvsadm v1.31 2019/12/24 (compiled with popt and IPVS v1.2.1) Usage: ipvsadm -A|E virtual-service [-s scheduler] [-p [timeout]] [-M netmask] [--pe persistence_engine] [-b sched-flags] ipvsadm -D virtual-service ipvsadm -C ipvsadm -R ipvsadm -S [-n] ipvsadm -a|e virtual-service -r server-address [options] ipvsadm -d virtual-service -r server-address ipvsadm -L|l [virtual-service] [options] ipvsadm -Z [virtual-service] ipvsadm --set tcp tcpfin udp ipvsadm --start-daemon {master|backup} [daemon-options] ipvsadm --stop-daemon {master|backup} ipvsadm -h ... root@sung-ubuntu01:~# ipvsadm --list IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP kubernetes.default.svc.clust rr -> sung-ubuntu01:6443 Masq 1 0 0 -> sung-ubuntu02:6443 Masq 1 5 0 -> sung-ubuntu03:6443 Masq 1 0 0 TCP coredns.kube-system.svc.clus rr -> 10-233-95-1.coredns.kube-sys Masq 1 0 0 -> 10-233-112-0.coredns.kube-sy Masq 1 1 0 TCP coredns.kube-system.svc.clus rr -> 10-233-95-1.coredns.kube-sys Masq 1 0 0 -> 10-233-112-0.coredns.kube-sy Masq 1 0 0 UDP coredns.kube-system.svc.clus rr -> 10-233-95-1.coredns.kube-sys Masq 1 0 0 -> 10-233-112-0.coredns.kube-sy Masq 1 0 0 * ip로 결과 보기 - ipvsadm -L -n
3. Calico
3.1 CNI
Container Network Interface
컨테이너 간의 네트워킹을 제어할 수 있는 플러그인을 만들기 위한 표준입니다.
3.1.1 CNI 요구사항
veth 페어 생성 및 컨테이너 네트워크 인터페이스와 연결
Pod 네트워크 대역 확인 후 IP 설정
CNI 설정 파일 작성
IP 설정 및 관리
컨테이너 내 기본 라우팅 정보 삽입 (default route rule)
동료 노드들에게 IP 라우팅 정보 전달(advertising the routes)
호스트 서버에 라우팅 정보 삽입
네트워크 정책에 따라 트래픽 처리
…
3.2 칼리코 개요
컨테이너 통신을 자유롭게 해주는 CNI - Calico
root@sung-ubuntu01:~/tmp# calicoctl version Client Version: v3.21.2 Git commit: 17461419 Cluster Version: v3.21.2 Cluster Type: kubespray,bgp,kubeadm,kdd,k8s # 모든 노드가 mesh 형태로 연결되어 있는 것을 확인 root@sung-ubuntu01:~/tmp# calicoctl node status Calico process is running. IPv4 BGP status +-----------------+-------------------+-------+----------+-------------+ | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO | +-----------------+-------------------+-------+----------+-------------+ | 192.168.110.101 | node-to-node mesh | up | 02:45:04 | Established | | 192.168.110.103 | node-to-node mesh | up | 02:40:50 | Established | | 192.168.110.104 | node-to-node mesh | up | 02:41:00 | Established | | 192.168.110.102 | node-to-node mesh | up | 02:44:42 | Established | +-----------------+-------------------+-------+----------+-------------+ root@sung-ubuntu04:~# calicoctl node status Calico process is running. IPv4 BGP status +-----------------+-------------------+-------+----------+-------------+ | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO | +-----------------+-------------------+-------+----------+-------------+ | 192.168.110.100 | node-to-node mesh | up | 02:40:49 | Established | | 192.168.110.101 | node-to-node mesh | up | 02:45:02 | Established | | 192.168.110.104 | node-to-node mesh | up | 02:40:59 | Established | | 192.168.110.102 | node-to-node mesh | up | 02:44:42 | Established | +-----------------+-------------------+-------+----------+-------------+ *master 서버에서만 출력 # 생성된 파드에 대한 위치, 정보 확인 root@sung-ubuntu01:~/tmp# calicoctl get workloadEndpoint WORKLOAD NODE NETWORKS INTERFACE multi-container sung-ubuntu05 10.233.78.3/32 calib4cfe5eb958 multi-container2 sung-ubuntu04 10.233.99.2/32 calia85a668c715 ubuntu-test sung-ubuntu04 10.233.99.1/32 calie3df4d89b13 # BGP 피어링은 179번 포트를 사용합니다. root@k8s-master01:~# netstat -antlp | grep 179 tcp 0 0 0.0.0.0:179 0.0.0.0:* LISTEN 831313/bird tcp 0 0 192.168.110.111:179 192.168.110.115:54063 ESTABLISHED 831313/bird tcp 0 0 192.168.110.111:179 192.168.110.112:40507 ESTABLISHED 831313/bird tcp 0 0 192.168.110.111:179 192.168.110.113:52189 ESTABLISHED 831313/bird tcp 0 0 192.168.110.111:179 192.168.110.114:51323 ESTABLISHED 831313/bird Q. multi-container2 파드를 삭제하면 sung-ubuntu04 노드 인터페이스는 어떻게 변할까요?
BGP(Border Gateway Protocol)
네트워크 BGP, AS(Autonomous System, 자율 시스템)을 설명할 때, 기업의 사내망과 인터넷 또는 국가 간 통신 방법에 비유합니다.
K8s에서는 각 노드 내 파드들과 노드 간의 통신으로 범위를 줄여서 적용할 수 있습니다.
3.3 칼리코 동작방식
3.3.1 Direct 방식
Pod 통신 패킷이 출발지 라우팅 정보를 보고 목적지 노드로 원본 패킷 그대로 전달합니다.
성능적으로 가장 우수합니다.
공식 용어는 아닌 것으로 보이며, Overlay 방식을 사용하지 않는 것을 Direct 방식이라고 칭합니다.
3.3.2 Overlay 방식 (터널링)
Pod의 네트워크 정보를 노드에서 Encapsulation(캡슐화)하여 목적지 노드로 전달합니다.
IP 기반의 터널링 방식으로 파드의 패킷 전달합니다.
각 노드 패킷에 대한 Encapsulation / Decapsulation 과정 실행합니다.
IPIP 모드
IP-in-IP라고 불리우는 Overlay 방식으로, Calico의 기본 모드입니다.
Pod의 네트워크 패킷의 기존 IP헤더 앞에 IP헤더를 하나 더 덧붙여 통신합니다.
다른 노드간 Pod 통신은 tunl0 인터페이스를 통해 IP 헤더에 감싸져서 상대 노드로 도달 후 tunl0 인터페이스에서 Outer 헤더를 제거하고 내부의 파드와 통신합니다.
VXLAN 모드
POD간 통신이 노드 구간에 VXLAN Encapsultation을 통해 이루어 집니다.
#Calico NAT 정책 확인 (true) root@sung-ubuntu01:~/tmp# calicoctl get ippool -o wide NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR default-pool 10.233.64.0/18 true Always Never false false all() #워커 노드에서 iptables nat 확인 root@sung-ubuntu04:~# 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 => cali-nat-outgoing 정책으로 외부로 나가는 패킷은 모두 MASQUERADE하여 처리됩니다. (=외부로 나가는 트래픽은 MASQURADE 정책을 통해 나갈 수 있습니다.)
IP Masquerade
NAT 기술 안에 속한 기술로 가면이라는 의미입니다.
NAT와 다르게 주소변환만 하는것이 아닌 포트번호까지 포트포워딩시켜주는 기능을 가지고 있습니다.
SNAT(Source NAT)와 같다고 합니다.
3.4 칼리코 모듈
3.4.1 칼리코 배포방식
The
calico/node
container is deployed to every node (on Kubernetes, by a DaemonSet), and runs three internal daemons
3.4.2 칼리코 구성요소
Felix(필릭스)
calico-node 파드 안에 위치하며, 모든 노드의 endpoint 제공합니다.
K8s ETCD 정보를 읽습니다.
라우팅 테이블 생성합니다.
kube-proxy가 iptables 모드인 경우, iptables 컨트롤합니다.
kube-proxy가 ipvs 모드인 경우, ipvs 컨트롤합니다.
BIRD(버드)
다른 노드에 있는 BGP 데몬들과 라우팅 정보 교환합니다.
TCP 179를 이용해서 mesh 형태로 연결합니다.
confd
Calico 데이터 저장소의 구성 변경을 감시하고 BIRD의 구성 파일을 업데이트하는 데몬 입니다.
# calico-node는 daemonset으로 배포되어있습니다. root@sung-ubuntu01:/var/lib/cni# kubectl -n kube-system get all | grep cali pod/calico-kube-controllers-6bc8445c8-kptbp 1/1 Running 48 2d23h pod/calico-node-ckvhb 1/1 Running 4 (2d23h ago) 2d23h pod/calico-node-d2pr7 1/1 Running 5 (2d23h ago) 2d23h pod/calico-node-fnmg9 1/1 Running 5 (2d23h ago) 2d23h pod/calico-node-gqr27 1/1 Running 9 (2d23h ago) 2d23h pod/calico-node-gzrt9 1/1 Running 8 (2d23h ago) 2d23h daemonset.apps/calico-node 5 5 5 5 5 kubernetes.io/os=linux 2d23h deployment.apps/calico-kube-controllers 1/1 1 1 2d23h replicaset.apps/calico-kube-controllers-6bc8445c8 1 1 1 2d23h
3.4.3 kube-proxy iptables와 Calico iptables 서비스 개수별 룰 개수 비교
출처 - https://www.tigera.io/blog/comparing-kube-proxy-modes-iptables-or-ipvs/