[클라우드 네이티브 | 처음부터 쿠버네티스 배우기] 20. 서비스 프록시 kube-proxy 컴포넌트에 대한 자세한 설명

이 기사는 "처음부터 k8 배우기" 칼럼에 포함되어 있습니다. 이전 기사
: Kubernetes 핵심 기술 서비스 실제 전투 점프 하려면 클릭하십시오

여기에 이미지 설명 삽입

kube-proxy 구성요소 소개

Kubernetes 서비스는 애플리케이션이 외부 세계에 서비스를 제공하는 방식을 추상화합니다. 실제 애플리케이션은 Pod의 컨테이너에서 실행됩니다. 우리의 요청은 kubernetes 노드에 해당하는 nodePort로 이동한 다음 nodePort의 요청은 어떻게 더 나아가 제공 백그라운드 서비스 Pod는 어떻습니까? kube-proxy를 통해 달성됩니다.

kube-proxy는 k8s의 각 노드 노드에 배포되며 Kubernetes의 핵심 구성 요소입니다.우리가 서비스를 생성할 때 kube-proxy는 라우팅 및 로드 밸런싱 기능을 구현하기 위해 iptables에 몇 가지 규칙을 추가합니다. k8s1.8 이전에는 kube-proxy가 기본적으로 iptables 모드를 사용했고, 각 노드에 대한 iptables 규칙을 통해 서비스의 로드 밸런싱을 구현했지만, 서비스 수가 증가함에 따라 선형 검색 매칭으로 인한 iptables 모드, 전체 업데이트 등의 특성으로 인해 성능이 크게 저하됩니다. kube-proxy는 k8s 1.8 버전부터 IPVS 모드를 도입했습니다.IPVS 모드는 iptables 뿐만 아니라 Netfilter를 기반으로 하지만 해시 테이블을 사용하므로 서비스 수가 일정 규모에 도달하면 해시 테이블의 속도 이점 서비스의 서비스 성능을 향상시키도록 조회가 나타납니다.

kubectl get pods -n kube-system -o wide

서비스는 해당 포드에 요청을 배포하는 책임이 있는 포드 그룹의 LB에 해당하는 포드 그룹에 대한 서비스 추상화입니다. 서비스는 일반적으로 클러스터 IP라고 하는 이 LB에 대한 IP를 제공합니다. kube-proxy의 역할은 주로 서비스 구현을 담당하며, 구체적으로 Pod에서 서비스로의 내부 접근과 노드 포트에서 서비스로의 외부 접근을 구현합니다.

1. kube-proxy는 실제로 클러스터의 Pod에서 서비스로의 액세스 및 클러스터 외부의 서비스에 대한 액세스를 포함하여 서비스를 관리하기 위한 액세스 항목입니다.

2. kube-proxy는 서비스의 끝점을 관리합니다. 서비스는 클러스터 IP라고도 하는 가상 IP를 노출합니다. 클러스터의 클러스터 IP:Port에 액세스하면 해당 서비스의 Pod에 액세스할 수 있습니다. 클러스터.

kube-proxy의 세 가지 작업 모드

1. 사용자 공간 방법:

여기에 이미지 설명 삽입

클라이언트 파드가 서버 파드에 접근하기를 원할 때, 그것은 먼저 커널 공간의 서비스 iptables 규칙에 요청을 보내고, 그런 다음 지정된 소켓에서 수신 대기하는 kube-proxy의 포트로 요청을 전달합니다. 요청을 처리하고 지정된 Server Pod에 요청을 배포한 후 요청을 커널 공간의 서비스 IP로 전달하고 서비스 iptables는 요청을 각 노드의 Server Pod로 전달합니다.

이 모드에는 큰 문제가 있습니다. 클라이언트가 먼저 커널 공간에 들어가도록 요청한 다음 kube-proxy에 액세스하기 위해 사용자 공간에 들어가도록 요청합니다. kube-proxy 패키지가 완료된 후 커널 공간의 iptables에 들어가고 그런 다음 iptables의 규칙에 따라 각 노드에 배포합니다. 사용자 공간과 커널 공간 사이를 오가며 통신해야 하므로 매우 비효율적입니다. Kubernetes 버전 1.1 이전에는 사용자 공간이 기본 프록시 모델이었습니다.

2. iptables 메소드:

여기에 이미지 설명 삽입

클라이언트 IP가 요청하면 로컬 커널 서비스 IP를 직접 요청하고 iptables의 규칙에 따라 요청을 각 Pod에 직접 전달하는데, 전달을 완료하기 위해 iptable NAT를 사용하기 때문에 무시할 수 없는 성능 손실도 있습니다. 또한 클러스터에 수만 개의 서비스/엔드포인트가 있는 경우 노드에 대한 iptables 규칙이 매우 커서 성능이 더욱 저하됩니다. iptables 프록시 모드는 Kubernetes 버전 1.1에서 도입되어 기본값이 되었습니다. 버전 1.2부터 입력합니다.

3. ipvs 방법:

여기에 이미지 설명 삽입

Kubernetes는 버전 1.9-alpha부터 ipvs 프록시 모드를 도입했으며 버전 1.11부터 기본값이 되었습니다. 클라이언트 요청이 커널 공간에 도착하면 ipvs의 규칙에 따라 각 포드에 직접 배포됩니다. kube-proxy는 Kubernetes Service 객체 및 Endpoints를 모니터링하고, netlink 인터페이스를 호출하여 그에 따라 ipvs 규칙을 생성하고, 주기적으로 ipvs 규칙을 Kubernetes Service 객체 및 Endpoints 객체와 동기화하여 ipvs 상태가 예상대로인지 확인합니다. 서비스에 액세스하면 트래픽이 백엔드 포드 중 하나로 리디렉션됩니다. iptables와 유사하게 ipvs는 netfilter의 후크 기능을 기반으로 하지만 기본 데이터 구조로 해시 테이블을 사용하고 커널 공간에서 작동합니다. 이는 ipv가 프록시 규칙을 동기화할 때 트래픽을 더 빠르게 리디렉션하고 더 나은 성능을 제공할 수 있음을 의미합니다. 또한 ipvs는 다음과 같은 로드 밸런싱 알고리즘에 대한 더 많은 옵션을 제공합니다.

rr:轮询调度  

lc:最小连接数  

dh:目标哈希  

sh:源哈希  

sed:最短期望延迟  

nq:不排队调度 

서비스 백엔드 포드가 변경되고 레이블 선택기가 하나 이상의 포드에 적응하면 적응된 정보는 apiserver에 즉시 반영되며 kube-proxy는 등의 정보 변경을 관찰하고 즉시 다음으로 변환할 수 있어야 합니다. ipvs 또는 iptables의 규칙은 모두 동적이며 실시간이며 포드를 삭제할 때도 마찬가지입니다.

여기에 이미지 설명 삽입

위와 상관없이 kube-proxy는 watch를 통해 apiserver가 etcd에 작성한 Pod에 대한 최신 상태 정보를 모니터링하며, Pod 리소스가 삭제되거나 새로 생성되었음을 감지하면 이러한 변경 사항을 iptables 또는 ipvs 규칙에 즉시 반영합니다. iptables와 ipvs는 Clinet Pod 요청을 Server Pod로 예약할 때 Server Pod가 존재하지 않는 상황을 갖지 않습니다. k8s1.11부터 서비스는 기본적으로 ipvs 규칙을 사용합니다.ipvs가 활성화되지 않으면 iptables 규칙을 사용하도록 다운그레이드됩니다.

kube-proxy에서 생성된 iptables 규칙 분석

1. 서비스 유형은 ClusterIp, iptables 규칙 분석입니다.

k8s에서 생성된 서비스는 ip 주소를 가지고 있지만 서비스의 ip는 가상이고 물리적 머신에 존재하지 않으며 iptables 또는 ipvs 규칙에 있습니다.

[root@k8smaster service]# kubectl apply -f pod_test.yaml 
[root@k8smaster service]# kubectl apply -f service_test.yaml 
[root@k8smaster node]# kubectl get svc -l run=my-nginx
NAME       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
my-nginx   ClusterIP   10.105.254.244   <none>        80/TCP    15s
[root@k8smaster node]# kubectl get pods -l run=my-nginx -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE  
my-nginx-5898cf8d98-5trvw   1/1     Running   0          40s   10.244.1.5   k8snode2   <none>          
my-nginx-5898cf8d98-phfqr   1/1     Running   0          40s   10.244.1.4   k8snode2   <none>          
[root@k8smaster node]# iptables -t nat -L | grep 10.105.254.244
KUBE-MARK-MASQ  tcp  -- !10.244.0.0/16        10.105.254.244       /* default/my-nginx: cluster IP */ tcp dpt:http
KUBE-SVC-BEPXDJBUHFCSYIC3  tcp  --  anywhere             10.105.254.244       /* default/my-nginx: cluster IP */ tcp dpt:http

[root@k8smaster node]# iptables -t nat -L | grep KUBE-SVC-BEPXDJBUHFCSYIC3
KUBE-SVC-BEPXDJBUHFCSYIC3  tcp  --  anywhere             10.105.254.244       /* default/my-nginx: cluster IP */ tcp dpt:http			#把service关联的pod做了转发
Chain KUBE-SVC-BEPXDJBUHFCSYIC3 (1 references)		

[root@k8smaster node]# iptables -t nat -L | grep 10.244.1.5
KUBE-MARK-MASQ  all  --  10.244.1.5           anywhere             /* default/my-nginx: */
DNAT       tcp  --  anywhere             anywhere             /* default/my-nginx: */ tcp to:10.244.1.5:80
#DNAT转发 kubesvc接收请求,在过滤podip的时候有个mark也会标记ip,然后做了一个dnat转发到10.244.1.5:80这个pod上

#通过上面可以看到之前创建的 service,会通过 kube-proxy 在 iptables 中生成一个规则,来实现流量路由,有一系列目标为 KUBE-SVC-xxx 链的规则,每条规则都会匹配某个目标 ip 与端口。也就是说访问某个 serivce的ip和端口请求会由 KUBE-SVC-xxx 链来通过DNAT转发到对应的podip和端口上。

2. 서비스 유형은 nodePort, iptables 규칙 분석입니다.

[root@k8smaster node]# kubectl apply -f pod_nodeport.yaml 
deployment.apps/my-nginx-nodeport created
[root@k8smaster node]# kubectl apply -f service_nodeport.yaml 
service/my-nginx-nodeport created

[root@k8smaster node]# kubectl get pods -l run=my-nginx-nodeport -o wide
NAME                                 READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED
my-nginx-nodeport-5fccbb754b-m4csx   1/1     Running   0          34s   10.244.1.7   k8snode2   <none>      
my-nginx-nodeport-5fccbb754b-rg48l   1/1     Running   0          34s   10.244.1.6   k8snode2   <none>
[root@k8smaster node]# kubectl get svc -l run=my-nginx-nodeport 
NAME                TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
my-nginx-nodeport   NodePort   10.105.58.82   <none>        80:30380/TCP   39s
 
[root@k8smaster node]# iptables -t nat -S | grep 30380 
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp --dport 30380 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp --dport 30380 -j KUBE-SVC-6JXEEPSEELXY3JZG
#一个是mark链一个是svc 在访问物理机ip和端口,访问会先经过这两个链

[root@k8smaster node]# iptables -t nat -S | grep KUBE-SVC-6JXEEPSEELXY3JZG
-N KUBE-SVC-6JXEEPSEELXY3JZG
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp --dport 30380 -j KUBE-SVC-6JXEEPSEELXY3JZG
-A KUBE-SERVICES -d 10.105.58.82/32 -p tcp -m comment --comment "default/my-nginx-nodeport: cluster IP" -m tcp --dport 80 -j KUBE-SVC-6JXEEPSEELXY3JZG
-A KUBE-SVC-6JXEEPSEELXY3JZG -m comment --comment "default/my-nginx-nodeport:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-36FBCF7ZW3VDH33Q
-A KUBE-SVC-6JXEEPSEELXY3JZG -m comment --comment "default/my-nginx-nodeport:" -j KUBE-SEP-K2MGI3AJIGBK3IJ5
#会通过iptables的probability机制有0.50的概率进入KUBE-SEP-36FBCF7ZW3VDH33Q这个链,剩下50%还是最后那个GBK3IJ5这个链

[root@k8smaster node]# iptables -t nat -S | grep KUBE-SEP-36FBCF7ZW3VDH33
-N KUBE-SEP-36FBCF7ZW3VDH33Q
-A KUBE-SEP-36FBCF7ZW3VDH33Q -s 10.244.1.6/32 -m comment --comment "default/my-nginx-nodeport:" -j KUBE-MARK-MASQ
-A KUBE-SEP-36FBCF7ZW3VDH33Q -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp -j DNAT --to-destination 10.244.1.6:80
-A KUBE-SVC-6JXEEPSEELXY3JZG -m comment --comment "default/my-nginx-nodeport:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-36FBCF7ZW3VDH33Q

#-A KUBE-SEP-36FBCF7ZW3VDH33Q -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp -j DNAT --to-destination 10.244.1.6:80 是做了一个dnat把请求给10.244.1.6这个pod的80端口了 下面可以看到ip是相同的
[root@k8smaster node]# kubectl get pods -l run=my-nginx-nodeport -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED
my-nginx-nodeport-5fccbb754b-m4csx   1/1     Running   0          8m24s   10.244.1.7   k8snode2   <none>    
my-nginx-nodeport-5fccbb754b-rg48l   1/1     Running   0          8m24s   10.244.1.6   k8snode2   <none>    

 
[root@k8smaster node]# iptables -t nat -S | grep KUBE-SEP-K2MGI3AJIGBK3IJ5
-N KUBE-SEP-K2MGI3AJIGBK3IJ5
-A KUBE-SEP-K2MGI3AJIGBK3IJ5 -s 10.244.1.7/32 -m comment --comment "default/my-nginx-nodeport:" -j KUBE-MARK-MASQ
-A KUBE-SEP-K2MGI3AJIGBK3IJ5 -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp -j DNAT --to-destination 10.244.1.7:80
-A KUBE-SVC-6JXEEPSEELXY3JZG -m comment --comment "default/my-nginx-nodeport:" -j KUBE-SEP-K2MGI3AJIGBK3IJ5
#也是一个dnat,把请求分给另外一个pod,通过这两个链50%的概率来转发到两个pod上

끝에 쓰다

만들기가 쉽지 않습니다. 컨텐츠가 도움이 된다고 생각하시면 3링크 팔로우를 통해 저를 지원해 주세요! 틀린 부분이 있으면 댓글로 지적해주시면 시간이 지나면 수정하겠습니다!
현재 업데이트 중인 시리즈: k8s 처음부터 배우세요
시청해주셔서 감사합니다 개인적인 이해가 섞인 글입니다 오류가 있으면 연락주시고 지적해주세요~
여기에 이미지 설명 삽입

추천

출처blog.csdn.net/qq_45400861/article/details/126850632