久久国产乱子伦精品免费M,亚洲一区二区三区91,欧美国产在线视频,国产精品视频久久

記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南

最近排查了一個 kubernetes 中使用了 hostport 后遇到比較坑的問題,奇怪的知識又增加了。

問題背景

集群環(huán)境為 K8s v1.15.9,cni 指定了 flannel-vxlan 跟 portmap, kube-proxy 使用 mode 為 ipvs,集群 3 臺 master,同時也是 node,這里以 node-1,node-2,node-3 來表示。
集群中有 2 個 mysql, 部署在兩個 ns 下,mysql 本身不是問題重點,這里就不細(xì)說,這里以 mysql-A,mysql-B 來表示。
mysql-A 落在 node-1 上,mysql-B 落在 node-2 上, 兩個數(shù)據(jù)庫 svc 名跟用戶、密碼完全不相同
出現(xiàn)詭異的現(xiàn)象這里以一張圖來說明會比較清楚一些:
記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南
其中綠線的表示訪問沒有問題,紅線表示連接 Mysql-A 提示用戶名密碼錯誤
特別詭異的是,當(dāng)在 Node-2 上通過 svc 訪問 Mysql-A 時,輸入 Mysql-A 的用戶名跟密碼提示密碼錯誤,密碼確認(rèn)無疑,但當(dāng)輸入 Mysql-B 的用戶名跟密碼,居然能夠連接上,看了下數(shù)據(jù),連上的是 Mysql-B 的數(shù)據(jù)庫,給人的感覺就是請求轉(zhuǎn)到了 Mysql-A, 最后又轉(zhuǎn)到了 Mysql-B,當(dāng)時讓人大跌眼鏡
碰到詭異的問題那就排查吧,排查的過程倒是不費什么事,最主要的是要通過這次踩坑機(jī)會挖掘一些奇怪的知識出來。

排查過程

既然在 Node-1 上連接 Mysql-A/Mysql-B 都沒有問題,那基本可以排查是 Mysql-A 的問題
經(jīng)實驗,在 Node-2 上所有的服務(wù)想要連 Mysql-A 時,都有這個問題,但是訪問其它的服務(wù)又都沒有問題,說明要么是 mysql-A 的 3306 這個端口有問題,通過上一步應(yīng)該排查了 mysql-A 的問題,那問題只能出在 Node-2 上
k8s 中像這樣的請求轉(zhuǎn)發(fā)出現(xiàn)詭異現(xiàn)象,當(dāng)排除了一些常見的原因之外,最大的嫌疑就是 iptables 了,作者遇到過多次
這次也不例外,雖然當(dāng)前集群使用的 ipvs, 但還是照例看下 iptables 規(guī)則,查看 Node-2 上的 iptables 與 Node-1 的 iptables 比對,結(jié)果有蹊蹺, 在 Node-2 上發(fā)現(xiàn)有以下的規(guī)則在其它節(jié)點上沒有
記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南
其中 10.224.0.222 為 Mysql-B 的 pod ip, xxxxxxxxxxxxx 經(jīng)查實為 Mysql-B 對應(yīng)的 pause 容器的 id
從上面的規(guī)則總結(jié)一下就是目的為 3306 端口的請求都會轉(zhuǎn)發(fā)到 10.224.0.222 這個地址,即 Mysql-B
看到這里,作者明白了為什么在 Node-2 上去訪問 Node-1 上 Mysql-A 的 3306 會提示密碼錯誤而輸入 Mysql-B 的密碼卻可以正常訪問
雖然兩個 mysql 的 svc 名不一樣,但上面的 iptables 只要目的端口是 3306 就轉(zhuǎn)發(fā)到 Mysql-B 了,當(dāng)請求到達(dá) mysql 后,使用正確的用戶名密碼自然可以登錄成功
原因是找到了,但是又引出來了更多的問題?
  1. 這幾條規(guī)則是誰入到 iptables 中的?
  2. 怎么解決呢,是不是刪掉就可以?

問題復(fù)現(xiàn)

同樣是 Mysql,為何 Mysql-A 沒有呢? 那么比對一下這兩個 Mysql 的部署差異

比對發(fā)現(xiàn), 除了用戶名密碼,ns 不一樣外,Mysql-B 部署時使用了 hostPort=3306, 其它的并無異常

難道是因為 hostPort?

作者日常會使用 NodePort,倒卻是沒怎么在意 hostPort,也就停留在 hostPort 跟 NodePort 的差別在于 NodePort 是所有 Node 上都會開啟端口,而 hostPort 只會在運行機(jī)器上開啟端口,由于 hostPort 使用的也少,也就沒太多關(guān)注,網(wǎng)上短暫搜了一番,描述的也不是很多,看起來大家也用的不多

那到底是不是因為 hostPort 呢?

Talk is cheap, show me the code

通過實驗來驗證,這里簡單使用了三個 nginx 來說明問題, 其中兩個使用了 hostPort,這里特意指定了不同的端口,其它的都完全一樣,發(fā)布到集群中,yaml 文件如下

記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南

Finally,問題復(fù)現(xiàn):

記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南

可以肯定,這些規(guī)則就是因為使用了 hostPort 而寫入的,但是由誰寫入的這個問題還是沒有解決?

罪魁禍?zhǔn)?/span>

作者開始以為這些 iptables 規(guī)則是由 kube-proxy 寫入的, 但是查看 kubelet 的源碼并未發(fā)現(xiàn)上述規(guī)則的關(guān)鍵字

再次實驗及結(jié)合網(wǎng)上的探索,可以得到以下結(jié)論:

首先從 kubernetes 的官方發(fā)現(xiàn)以下描述:

The CNI networking plugin supports hostPort. You can use the official portmap[1] plugin offered by the CNI plugin team or use your own plugin with portMapping functionality.

If you want to enable hostPort support, you must specify portMappings capability in your cni-conf-dir. For example:

記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南

也就是如果使用了 hostPort, 是由 portmap 這個 cni 提供 portMapping 能力,同時,如果想使用這個能力,在配置文件中一定需要開啟 portmap,這個在作者的集群中也開啟了,這點對應(yīng)上了

另外一個比較重要的結(jié)論是:

The CNI ‘portmap’ plugin, used to setup HostPorts for CNI, inserts rules at the front of the iptables nat chains; which take precedence over the KUBE- SERVICES chain. Because of this, the HostPort/portmap rule could match incoming traffic even if there were better fitting, more specific service definition rules like NodePorts later in the chain

參考:?https://ubuntu.com/security/CVE-2019-9946

翻譯過來就是使用 hostPort 后,會在 iptables 的 nat 鏈中插入相應(yīng)的規(guī)則,而且這些規(guī)則是在 KUBE- SERVICES 規(guī)則之前插入的,也就是說會優(yōu)先匹配 hostPort 的規(guī)則,我們常用的 NodePort 規(guī)則其實是在 KUBE- SERVICES 之中,也排在其后

從 portmap 的源碼中果然是可以看到相應(yīng)的代碼

記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南

所以,最終是調(diào)用 portmap 寫入的這些規(guī)則。

端口占用

進(jìn)一步實驗發(fā)現(xiàn),hostport 可以通過 iptables 命令查看到, 但是無法在 ipvsadm 中查看到

使用 lsof/netstat 也查看不到這個端口,這是因為 hostport 是通過 iptables 對請求中的目的端口進(jìn)行轉(zhuǎn)發(fā)的,并不是在主機(jī)上通過端口監(jiān)聽

記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南

既然 lsof 跟 netstat 都查不到端口信息,那這個端口相當(dāng)于沒有處于 listen 狀態(tài)?

如果這時再部署一個 hostport 提定相同端口的應(yīng)用會怎么樣呢?

結(jié)論是: 使用 hostPort 的應(yīng)用在調(diào)度時無法調(diào)度在已經(jīng)使用過相同 hostPort 的主機(jī)上,也就是說,在調(diào)度時會考慮 hostport

如果強(qiáng)行讓其調(diào)度在同一臺機(jī)器上,那么就會出現(xiàn)以下錯誤,如果不刪除的話,這樣的錯誤會越來越多,嚇的作者趕緊刪了.

記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南

如果這個時候創(chuàng)建一個 nodePort 類型的 svc, 端口也為 31123,結(jié)果會怎么樣呢?

記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南

記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南

可以發(fā)現(xiàn),NodePort 是可以成功創(chuàng)建的,同時監(jiān)聽的端口也出現(xiàn)了.

從這也可以說明使用 hostposrt 指定的端口并沒有 listen 主機(jī)的端口,要不然這里就會提示端口重復(fù)之類

那么問題又來了,同一臺機(jī)器上同時存在有 hostPort 跟 nodePort 的端口,這個時候如果 curl 31123 時, 訪問的是哪一個呢?

經(jīng)多次使用 curl 請求后,均是使用了 hostport 那個 nginx pod 收到請求

原因還是因為 KUBE-NODE-PORT 規(guī)則在 KUBE-SERVICE 的鏈中是處于最后位置,而 hostPort 通過 portmap 寫入的規(guī)則排在其之前

記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南

因此會先匹配到 hostport 的規(guī)則,自然請求就被轉(zhuǎn)到 hostport 所在的 pod 中,這兩者的順序是沒辦法改變的,因此無論是 hostport 的應(yīng)用發(fā)布在前還是在后都無法影響請求轉(zhuǎn)發(fā)

另外再提一下,hostport 的規(guī)則在 ipvsadm 中是查詢不到的,而 nodePort 的規(guī)則則是可以使用 ipvsadm 查詢得到

問題解決

要想把這些規(guī)則刪除,可以直接將 hostport 去掉,那么規(guī)則就會隨著刪除,比如下圖中去掉了一個 nginx 的 hostport

記一次 K8S HostPort 引發(fā)的服務(wù)故障排錯指南

另外使用較多的 port-forward 也是可以進(jìn)行端口轉(zhuǎn)發(fā)的,它又是個什么情況呢? 它其實使用的是 socat 及 netenter 工具,網(wǎng)上看到一篇文章,原理寫的挺好的,感興趣的可以看一看

參考:?https://vflong.github.io/sre/k8s/2020/03/15/how-the-kubectl-port-forward-command-works.html

生產(chǎn)建議

一句話,生產(chǎn)環(huán)境除非是必要且無他法,不然一定不要使用 hostport,除了會影響調(diào)度結(jié)果之外,還會出現(xiàn)上述問題,可能造成的后果是非常嚴(yán)重的

來源:https://izsk.me/2021/08/01/Kubernetes-hostport/

文章轉(zhuǎn)載:高效運維
(版權(quán)歸原作者所有,侵刪)

相關(guān)新聞

歷經(jīng)多年發(fā)展,已成為國內(nèi)好評如潮的Linux云計算運維、SRE、Devops、網(wǎng)絡(luò)安全、云原生、Go、Python開發(fā)專業(yè)人才培訓(xùn)機(jī)構(gòu)!

    1. 主站蜘蛛池模板: 巴林左旗| 怀化市| 佛山市| 庆阳市| 华蓥市| 噶尔县| 西宁市| 元氏县| 通化县| 三河市| 鸡西市| 菏泽市| 贺兰县| 墨竹工卡县| 延长县| 瑞丽市| 蒙自县| 郎溪县| 肃北| 沅江市| 房山区| 崇义县| 綦江县| 昌图县| 吉安县| 普安县| 皮山县| 广德县| 兴山县| 获嘉县| 灵武市| 吉隆县| 新昌县| 定襄县| 综艺| 师宗县| 樟树市| 延长县| 南通市| 会泽县| 香港|