iptables和ipvs


一、service和iptables的關系

service 的代理是 kube-proxy

kube-proxy 運行在所有節點上,它監聽 apiserver 中 service 和 endpoint 的變化情況,創建路由規則以提供服務 IP 和負載均衡功能。簡單理解此進程是Service的透明代理兼負載均衡器,其核心功能是將到某個Service的訪問請求轉發到后端的多個Pod實例上,而kube-proxy底層又是通過iptables和ipvs實現的。

iptables原理

Kubernetes從1.2版本開始,將iptables作為kube-proxy的默認模式。iptables模式下的kube-proxy不再起到Proxy的作用,其核心功能:通過API Server的Watch接口實時跟蹤Service與Endpoint的變更信息,並更新對應的iptables規則,Client的請求流量則通過iptables的NAT機制“直接路由”到目標Pod。

ipvs原理

IPVS在Kubernetes1.11中升級為GA穩定版。IPVS則專門用於高性能負載均衡,並使用更高效的數據結構(Hash表),允許幾乎無限的規模擴張,因此被kube-proxy采納為最新模式。

在IPVS模式下,使用iptables的擴展ipset,而不是直接調用iptables來生成規則鏈。iptables規則鏈是一個線性的數據結構,ipset則引入了帶索引的數據結構,因此當規則很多時,也可以很高效地查找和匹配。

可以將ipset簡單理解為一個IP(段)的集合,這個集合的內容可以是IP地址、IP網段、端口等,iptables可以直接添加規則對這個“可變的集合”進行操作,這樣做的好處在於可以大大減少iptables規則的數量,從而減少性能損耗。

kube-proxy ipvs和iptables的異同

iptables與IPVS都是基於Netfilter實現的,但因為定位不同,二者有着本質的差別:iptables是為防火牆而設計的;IPVS則專門用於高性能負載均衡,並使用更高效的數據結構(Hash表),允許幾乎無限的規模擴張。

與iptables相比,IPVS擁有以下明顯優勢:

  • 為大型集群提供了更好的可擴展性和性能;

  • 支持比iptables更復雜的復制均衡算法(最小負載、最少連接、加權等);

  • 支持服務器健康檢查和連接重試等功能;

  • 可以動態修改ipset的集合,即使iptables的規則正在使用這個集合。

二、k8s集群中分析service和kube-proxy

訪問Service的請求,不論是Cluster IP+TargetPort的方式;還是用Node節點IP+NodePort的方式,都被Node節點的Iptables規則重定向到Kube-proxy監聽Service服務代理端口。kube-proxy接收到Service的訪問請求后,根據負載策略,轉發到后端的Pod。

# kubectl logs  kube-proxy-5clwf  -n kube-system  (查看某一個節點的kube-proxy日志)

W1014 13:25:02.120810       1 server_others.go:559] Unknown proxy mode "", assuming iptables proxy
I1014 13:25:02.137813       1 node.go:136] Successfully retrieved node IP: 192.168.40.133
I1014 13:25:02.137952       1 server_others.go:186] Using iptables Proxier.
I1014 13:25:02.138750       1 server.go:583] Version: v1.18.0
I1014 13:25:02.139344       1 conntrack.go:100] Set sysctl 'net/netfilter/nf_conntrack_max' to 131072

# iptables -vnL     查看所有的規則

Chain INPUT (policy ACCEPT 19577 packets, 3755K bytes)
 pkts bytes target     prot opt in     out     source               destination         
 622K  121M cali-INPUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* cali:Cz_u1IQiXIMmKD4c */
 3017  162K KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate NEW /* kubernetes service portals */
 3017  162K KUBE-EXTERNAL-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate NEW /* kubernetes externally-visible service portals */
 652K  140M KUBE-FIREWALL  all  --  *      *       0.0.0.0/0            0.0.0.0/0   

# iptables-save  > iptables 保存規則,並輸出到屏幕

:cali-OUTPUT - [0:0]
:cali-PREROUTING - [0:0]
:cali-from-host-endpoint - [0:0]
:cali-to-host-endpoint - [0:0]
-A PREROUTING -m comment --comment "cali:6gwbT8clXdHdC1b1" -j cali-PREROUTING
-A OUTPUT -m comment --comment "cali:tVnHkvAo15HuiPy0" -j cali-OUTPUT

第一步:接收流量

NodePort訪問入口規則:

# kubectl get svc
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes    ClusterIP   10.96.0.1        <none>        443/TCP        78d
mydb          ClusterIP   10.108.118.149   <none>        80/TCP         50d
nginx-dns     NodePort    10.103.206.148   <none>        80:30296/TCP   49d
web-service   NodePort    10.111.113.171   <none>        80:32681/TCP   49d
web1          NodePort    10.110.180.143   <none>        80:30746/TCP   12h

# iptables -S -t nat  | grep 30746
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/web1:" -m tcp --dport 30746 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/web1:" -m tcp --dport 30746 -j KUBE-SVC-7YBM6NGNJ6RVLVXL

CLUSTER-IP 訪問入口規則:

# iptables -S -t nat  | grep 10.110.180.143 (cluster IP)
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.110.180.143/32 -p tcp -m comment --comment "default/web1: cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.110.180.143/32 -p tcp -m comment --comment "default/web1: cluster IP" -m tcp --dport 80 -j KUBE-SVC-7YBM6NGNJ6RVLVXL

第二步:按概率(probability)分配

(web1有3個pod副本,負載規則如下)

# iptables -S -t nat  | grep KUBE-SVC-7YBM6NGNJ6RVLVXL
-N KUBE-SVC-7YBM6NGNJ6RVLVXL
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/web1:" -m tcp --dport 30746 -j KUBE-SVC-7YBM6NGNJ6RVLVXL
-A KUBE-SERVICES -d 10.110.180.143/32 -p tcp -m comment --comment "default/web1: cluster IP" -m tcp --dport 80 -j KUBE-SVC-7YBM6NGNJ6RVLVXL
-A KUBE-SVC-7YBM6NGNJ6RVLVXL -m comment --comment "default/web1:" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-IXSCGLPBJ6ROUJNA
-A KUBE-SVC-7YBM6NGNJ6RVLVXL -m comment --comment "default/web1:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-5MMDFR2YQS26JCDP  (概論大,因為有兩個pod在同一節點)
-A KUBE-SVC-7YBM6NGNJ6RVLVXL -m comment --comment "default/web1:" -j KUBE-SEP-DHYUVI6YLCFCEZBW

第三步:根據分配轉發到實際pod中

# kubectl get ep
NAME          ENDPOINTS                                             AGE
kubernetes    192.168.40.132:6443                                   78d
nginx-dns     10.244.166.145:80                                     49d
web-service   10.244.166.139:80                                     49d
web1          10.244.104.9:80,10.244.166.140:80,10.244.166.146:80   12h

# iptables -S -t nat  | grep KUBE-SEP-5MMDFR2YQS26JCDP
-N KUBE-SEP-5MMDFR2YQS26JCDP
-A KUBE-SEP-5MMDFR2YQS26JCDP -s 10.244.166.140/32 -m comment --comment "default/web1:" -j KUBE-MARK-MASQ
-A KUBE-SEP-5MMDFR2YQS26JCDP -p tcp -m comment --comment "default/web1:" -m tcp -j DNAT --to-destination 10.244.166.140:80(ep,到達某一節點的具體pod中)
-A KUBE-SVC-7YBM6NGNJ6RVLVXL -m comment --comment "default/web1:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-5MMDFR2YQS26JCDP

三、kube-proxy 工作原理

kube-proxy當前實現了三種代理模式:userspace, iptables, ipvs

(1)userspace mode:  userspace是在用戶空間,通過kube-proxy來實現service的代理服務

(2)iptables mode, 該模式完全利用內核iptables來實現service的代理和LB, 這是K8s在v1.2及之后版本默認模式

API Server 對內(集群中的其他組件)和對外(用戶)提供統一的 REST API,其他組件均通過 API Server 進行通信

Controller Manager、Scheduler、Kube-proxy 和 Kubelet 等均通過 API Server watch API 監測資源變化情況,並對資源作相應的操作

(3)ipvs mode.  在kubernetes 1.8以上的版本中,對於kube-proxy組件增加了除iptables模式和用戶模式之外還支持ipvs模式

kube-proxy ipvs 是基於 NAT 實現的,通過ipvs的NAT模式,對訪問k8s service的請求進行虛IP到POD IP的轉發。當創建一個 service 后,kubernetes 會在每個節點上創建一個網卡,同時幫你將 Service IP(VIP) 綁定上,此時相當於每個 Node 都是一個 ds,而其他任何 Node 上的 Pod,甚至是宿主機服務(比如 kube-apiserver 的 6443)都可能成為 rs;

與iptables、userspace 模式一樣,kube-proxy 依然監聽Service以及Endpoints對象的變化, 不過它並不創建反向代理, 也不創建大量的 iptables 規則, 而是通過netlink 創建ipvs規則,並使用k8s Service與Endpoints信息,對所在節點的ipvs規則進行定期同步; netlink 與 iptables 底層都是基於 netfilter 鈎子,但是 netlink 由於采用了 hash table 而且直接工作在內核態,在性能上比 iptables 更優。其工作流程大體如下:

k8s的service和endpoine是如何關聯和相互影響的?
1、 api-server創建service對象,與service綁定的pod地址:稱之為endpoints(kubectl get ep可以查看)
2、服務發現方面:kube-proxy監控service后端endpoint的動態變化,並且維護service和endpoint的映射關系

kubernetes服務注冊(dns),服務發現是service

http://www.dockone.io/article/9936   有詳細講解

Kubernetes提供了兩種方式進行服務發現, 即環境變量和DNS

(1)環境變量: 當你創建一個Pod的時候,kubelet會在該Pod中注入集群內所有Service的相關環境變量。需要注意: 要想一個Pod中注入某個Service的環境變量,則必須Service要先比該Pod創建。這一點,幾乎使得這種方式進行服務發現不可用。比如,一個ServiceName為redis-master的Service,對應的ClusterIP:Port為172.16.50.11:6379,則其對應的環境變量為:

REDIS_MASTER_SERVICE_HOST=172.16.50.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://172.16.50.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://172.16.50.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=172.16.50.11

(2)DNS:這是k8s官方強烈推薦的方式!!!  可以通過cluster add-on方式輕松的創建KubeDNS來對集群內的Service進行服務發現。

四、修改kube-proxy模式為ipvs(默認為iptables)

1、加載內核模塊

# lsmod | grep  ip_vs

ip_vs_sh               12688  0
ip_vs_wrr              12697  0
ip_vs_rr               12600  0
ip_vs                 145497  6 ip_vs_rr,ip_vs_sh,ip_vs_wrr
nf_conntrack          139264  7 ip_vs,nf_nat,nf_nat_ipv4,xt_conntrack,nf_nat_masquerade_ipv4,nf_conntrack_netlink,nf_conntrack_ipv4
libcrc32c              12644  4 xfs,ip_vs,nf_nat,nf_conntrack

2、升級內核模塊,ipvs對內核版本有要求

 yum update -y 

3、查看kube-proxy組件

# kubectl get pod -n kube-system  
NAME                                       READY   STATUS    RESTARTS   AGE
kube-proxy-5clwf                           1/1     Running   29         78d
kube-proxy-ht25x                           1/1     Running   30         78d
kube-proxy-x9ml8                           1/1     Running   30         78d
kube-scheduler-master                      1/1     Running   49         78d
metrics-server-584b5f4754-7vlhm            1/1     Running   56         78d

4、產看kube-proxy的配置文件configmaps

# kubectl get configmaps  -n kube-system  
NAME                                 DATA   AGE
calico-config                        4      78d
coredns                              1      78d
extension-apiserver-authentication   6      78d
kube-proxy                           2      78d
kubeadm-config                       2      78d
kubelet-config-1.18                  1      78d

5、編輯kube-proxy的configmaps

# kubectl edit  configmaps  kube-proxy -n kube-system 
mode "ipvs"

刪除舊的kube-proxy,kubelet自動重新拉起,應用ipvs
# kubectl delete pod   kube-proxy-x9ml8   -n kube-system  
pod "kube-proxy-x9ml8" deleted
[root@master ~]# kubectl delete pod   kube-proxy-ht25x   -n kube-system  
pod "kube-proxy-ht25x" deleted

# kubectl logs kube-proxy-4cnbn  -n kube-system 
I1015 14:03:08.402147       1 node.go:136] Successfully retrieved node IP: 192.168.40.132
I1015 14:03:08.402259       1 server_others.go:259] Using ipvs Proxier.
W1015 14:03:08.402618       1 proxier.go:429] IPVS scheduler not specified, use rr by default

6、安裝ipvsadm 

# yum install -y ipvsadm.x86_64 

# ipvsadm -L -n 
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  127.0.0.1:30564 rr  (輪詢規則)
  -> 10.244.104.36:8080           Masq    1      0          0         
  -> 10.244.166.147:8080          Masq    1      0          0         
TCP  127.0.0.1:32618 rr
  -> 10.244.104.20:80             Masq    1      0          0         
TCP  172.17.0.1:30564 rr
  -> 10.244.104.36:8080           Masq    1      0          0    

7、系統生成虛擬網卡kube-ipvs0

#  ip a
6: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default 
    link/ether a2:09:a4:9d:fb:f8 brd ff:ff:ff:ff:ff:ff
    inet 10.110.180.143/32 brd 10.110.180.143 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
inet 10.110.180.143/32專門用於接收svc web1的請求

8、svc的流量被ipvs分發

# kubectl get svc 
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
web1          NodePort    10.110.180.143   <none>        80:30746/TCP   23h

# curl  10.110.180.143
...
<title>Welcome to nginx!</title>
...

# kubectl get ep
NAME          ENDPOINTS                                              AGE
kubernetes    192.168.40.132:6443                                    78d
web1          10.244.104.15:80,10.244.166.143:80,10.244.166.148:80   23h

ipvs捕捉到svc的流量
# ipvsadm -L -n 
TCP  10.110.180.143:80 rr
  -> 10.244.104.15:80             Masq    1      0          0         
  -> 10.244.166.143:80            Masq    1      0          0         
  -> 10.244.166.148:80            Masq    1      0          1   

 

參考   https://www.cnblogs.com/fuyuteng/p/11598768.html



 







 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM