一、kube-proxy 開啟 ipvs
1、環境准備:
測試環境為kubernetes集群,一台master節點,一台node節點。集群網絡使用flanneld搭建。
注意:master節點上也需要進行kubelet配置。因為ipvs在有些情況下是依賴iptables的,iptables中KUBE-POSTROUTING,KUBE-MARK-MASQ, KUBE-MARK-DROP這三條鏈是被 kubelet創建和維護的, ipvs不會創建它們。
2、建議關閉SELinux,firewall
firewall是Linux 的一個安全子系統,SELinux 主要作用就是最大限度地減小系統中服務進程可訪問的資源。
關閉SELinux
docker1.node ➜ ~ cat /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of three two values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
重啟驗證:
[root@master140 ~]# sestatus
SELinux status: disabled
關閉firewall
systemctl stop firewalld
systemctl disable firewalld
3、開啟路由轉發功能:
[root@master140 ~]# cat /etc/sysctl.conf
# sysctl settings are defined through files in
# /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/.
#
# Vendors settings live in /usr/lib/sysctl.d/.
# To override a whole file, create a new file with the same in
# /etc/sysctl.d/ and put new settings there. To override
# only specific settings, add a file with a lexically later
# name in /etc/sysctl.d/ and put new settings there.
#
# For more information, see sysctl.conf(5) and sysctl.d(5).
net.ipv4.ip_forward=1
必須有net.ipv4.ip_forward=1,有了它,ipvs才能進行轉發
執行 sysctl -p 使之生效
[root@node147 ~]# sysctl -p
net.ipv4.ip_forward = 1
4、內核模塊加載
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
ipvs_modules="ip_vs ip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_sh ip_vs_fo ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack_ipv4"
for kernel_module in \${ipvs_modules}; do
/sbin/modinfo -F filename \${kernel_module} > /dev/null 2>&1
if [ $? -eq 0 ]; then
/sbin/modprobe \${kernel_module}
fi
done
EOF
chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep ip_vs
檢查測試:
[root@master140 ~]# lsmod | grep ip_vs
ip_vs_ftp 13079 0
nf_nat 26787 3 ip_vs_ftp,nf_nat_ipv4,nf_nat_masquerade_ipv4
ip_vs_sed 12519 0
ip_vs_nq 12516 0
ip_vs_sh 12688 0
ip_vs_dh 12688 0
ip_vs_lblcr 12922 0
ip_vs_lblc 12819 0
ip_vs_wrr 12697 0
ip_vs_rr 12600 17
ip_vs_wlc 12519 0
ip_vs_lc 12516 0
ip_vs 141092 39 ip_vs_dh,ip_vs_lc,ip_vs_nq,ip_vs_rr,ip_vs_sh,ip_vs_ftp,ip_vs_sed,ip_vs_wlc,ip_vs_wrr,ip_vs_lblcr,ip_vs_lblc
nf_conntrack 133387 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
5、修改kube-proxy配置
Node:
KUBE_PROXY_ARGS="--bind-address=0.0.0.0 \
--hostname-override=node147 \
--kubeconfig=/etc/kubernetes/kube-proxy.conf \
--logtostderr=true \
--v=2 \
--feature-gates=SupportIPVSProxyMode=true \
--proxy-mode=ipvs"
如果kubelet設置了–hostname-override選項,則kube-proxy也需要設置該選項,並且名字一致否則會出現找不到Node的情況。
Master:
KUBE_PROXY_ARGS="--proxy-mode=ipvs \
--ipvs-scheduler=rr \
--kubeconfig=/etc/kubernetes/kube-proxy.conf \
--logtostderr=true \
--v=2"
二、ipvs原理:
ipvs的模型中有兩個角色:
調度器:Director,又稱為Balancer。 調度器主要用於接受用戶請求。
真實主機:Real Server,簡稱為RS。用於真正處理用戶的請求。
IP地址類型分為三種:
Client IP:客戶端請求源IP,簡稱CIP。
Director Virtual IP:調度器用於與客戶端通信的IP地址,簡稱為VIP。
Real Server IP: 后端主機的用於與調度器通信的IP地址,簡稱為RIP。
工作過程:
1、當用戶請求到達Director Server,此時請求的數據報文會先到內核空間的PREROUTING鏈。 此時報文的源IP為CIP,目標IP為VIP。
2、PREROUTING檢查發現數據包的目標IP是本機,將數據包送至INPUT鏈。
3、ipvs會監聽到達input鏈的數據包,比對數據包請求的服務是否為集群服務,若是,修改數據包的目標IP地址為后端服務器IP,然后將數據包發至POSTROUTING鏈。 此時報文的源IP為CIP,目標IP為RIP。
4、POSTROUTING鏈通過選路,將數據包發送給Real Server
5、Real Server比對發現目標為自己的IP,開始構建響應報文發回給Director Server。 此時報文的源IP為RIP,目標IP為CIP。
6、Director Server在響應客戶端前,此時會將源IP地址修改為自己的VIP地址,然后響應給客戶端。 此時報文的源IP為VIP,目標IP為CIP。
三 ipvs在kube-proxy中的使用
開啟ipvs后,本機里面的一些信息會改變。
1、網卡
明顯的變化是,多了一個綁定很多cluster service ip的kube-ipvs0網卡
[root@master140 ~]# ip addr
5: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default
link/ether d2:b0:08:01:3e:52 brd ff:ff:ff:ff:ff:ff
inet 172.18.13.31/32 brd 172.18.13.31 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 172.18.13.1/32 brd 172.18.13.1 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 172.18.13.187/32 brd 172.18.13.187 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 172.18.13.113/32 brd 172.18.13.113 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 172.18.13.222/32 brd 172.18.13.222 scope global kube-ipvs0
valid_lft forever preferred_lft forever
2、router
查看router時候,會發現多了一下一些route信息。這些route信息是和上面的網卡信息對應的。
[root@master140 ~]# ip route show table local
local 172.18.13.1 dev kube-ipvs0 proto kernel scope host src 172.18.13.1
local 172.18.13.31 dev kube-ipvs0 proto kernel scope host src 172.18.13.31
local 172.18.13.113 dev kube-ipvs0 proto kernel scope host src 172.18.13.113
local 172.18.13.187 dev kube-ipvs0 proto kernel scope host src 172.18.13.187
local 172.18.13.222 dev kube-ipvs0 proto kernel scope host src 172.18.13.222
3、ipvs 規則
[root@master140 ~]# ipvsadm -ln
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:30001 rr
TCP 127.0.0.1:30002 rr
-> 10.0.3.5:8080 Masq 1 0 0
-> 10.0.3.7:8080 Masq 1 0 0
TCP 127.0.0.1:30094 rr
-> 10.0.3.2:80 Masq 1 0 0
TCP 172.17.0.1:30001 rr
TCP 172.17.0.1:30002 rr
-> 10.0.3.5:8080 Masq 1 0 0
-> 10.0.3.7:8080 Masq 1 0 0
TCP 172.17.0.1:30094 rr
-> 10.0.3.2:80 Masq 1 0 0
TCP 172.18.13.1:443 rr
-> 192.168.204.142:6443 Masq 1 0 0
TCP 172.18.13.31:80 rr
TCP 172.18.13.113:8082 rr
-> 10.0.3.5:8080 Masq 1 0 0
-> 10.0.3.7:8080 Masq 1 0 0
TCP 172.18.13.187:3306 rr
-> 10.0.3.4:3306 Masq 1 0 0
TCP 172.18.13.222:80 rr
-> 10.0.3.2:80 Masq 1 0 0
TCP 192.168.204.142:30001 rr
TCP 192.168.204.142:30002 rr
-> 10.0.3.5:8080 Masq 1 0 0
-> 10.0.3.7:8080 Masq 1 0 0
TCP 192.168.204.142:30094 rr
-> 10.0.3.2:80 Masq 1 0 0
TCP 10.0.1.0:30001 rr
TCP 10.0.1.0:30002 rr
-> 10.0.3.5:8080 Masq 1 0 0
-> 10.0.3.7:8080 Masq 1 0 0
TCP 10.0.1.0:30094 rr
-> 10.0.3.2:80 Masq 1 0 0
4、新增網卡和route的作用
由於 IPVS 的 DNAT 鈎子掛在 INPUT 鏈上,因此必須要讓內核識別 VIP 是本機的 IP。這樣才會過INPUT 鏈,要不然就通過OUTPUT鏈出去了。k8s 通過設置將service cluster ip 綁定到虛擬網卡kube-ipvs0。
5、使用ipvs的kube-proxy的工作原理

①因為service cluster ip 綁定到虛擬網卡kube-ipvs0上,內核可以識別訪問的 VIP 是本機的 IP.
②數據包到達INPUT鏈.
③ipvs監聽到達input鏈的數據包,比對數據包請求的服務是為集群服務,修改數據包的目標IP地址為對應pod的IP,然后將數據包發至POSTROUTING鏈.
④數據包經過POSTROUTING鏈選路,將數據包通過flannel網卡發送出去。從flannel虛擬網卡獲得源IP.
⑤pod接收到請求之后,構建響應報文,改變源地址和目的地址,返回給客戶端。
四、實例-集群內部通過clusterIP訪問到pod的流程
本例子中有兩台機器,master和node,pod都在node機器上運行。訪問命令為curl 172.18.13.222:80,對應的pod的ip為10.0.7.7。

1、本機接受請求
內核通過本機的路由和虛擬網卡,可以識別訪問的 VIP 是本機的 IP
//路由
local 172.18.13.222 dev kube-ipvs0 proto kernel scope host src 172.18.13.222
//網卡
inet 172.18.13.222/32 brd 172.18.13.222 scope global kube-ipvs0
valid_lft forever preferred_lft forever
2、將數據包送至INPUT鏈。
驗證是否經過INPUT鏈
首先、我們在INPUT鏈中加入一條如下過濾規則。該規則的意思是當有目的地址為172.18.13.222時,都拒絕掉。
iptables -t filter -I INPUT -d 172.18.13.222 -j DROP
查看INPUT鏈,確實多了此條規則。
之后,我們watch INPUT鏈
watch -n 0.1 "iptables --line-number -nvxL INPUT"
當我們訪問172.18.13.222時
curl 172.18.13.222
發現無法訪問,並且watch到INPUT確實有拒絕的包。驗證成功后。
3、ipvs對請求做轉發
ipvs會監聽到達input鏈的數據包,比對數據包請求的服務是為集群服務,所以修改數據包的目標IP地址為真實服務器IP,然后將數據包發至POSTROUTING鏈。 此時報文的源IP為CIP,目標IP為RIP(真實ip)
4、通過網卡發出數據包
數據包經過POSTROUTING鏈選路,將數據包通過flannel網卡發送出去,pod所在機器也通過flannel網卡進行接收。數據包經過master上的flannel網卡第一次被賦予源IP。此時源IP,目的IP分別是10.0.6.0,10.0.7.7
驗證是否通過flnanel網卡進行通信:
首先:master上flannel網卡信息是10.0.6.0/16。
node上flannel網卡信息是10.0.7.0/16。
當我們從master上進行curl命令時
對pod所在機器node的flannel網卡進行監聽,發現是請求從10.0.6.0發送過來的。10.0.6.0正是master上的網卡信息。
5、pod接收到請求,處理,返回
pod接收到請求之后,開始構建響應報文返回給客戶端。 此時報文的源IP為pod的IP:10.0.7.7,目標IP為10.0.6.0。最終又通過flannel網絡將響應報文發回master。
注意:
我們上文所說的通過flannel網絡進行通信,最終還是要過機器的真實網卡,因為flannel網絡設置的網卡也是虛擬的。
例如我們監聽機器的真實網卡eth0
tcpdump -nn -i eth0 src port not 22 and dst port not 22
我們是能夠發現通過flannel網絡進行通信還是會經過真實網卡eth0