成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

新聞 系統(tǒng)運(yùn)維
最近排查了一個(gè) kubernetes 中使用了 hostport 后遇到比較坑的問題,奇怪的知識(shí)又增加了。

 [[418642]]

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

問題背景

集群環(huán)境為 K8s v1.15.9,cni 指定了 flannel-vxlan 跟 portmap, kube-proxy 使用 mode 為 ipvs,集群 3 臺(tái) master,同時(shí)也是 node,這里以 node-1,node-2,node-3 來表示。

集群中有 2 個(gè) mysql, 部署在兩個(gè) ns 下,mysql 本身不是問題重點(diǎn),這里就不細(xì)說,這里以 mysql-A,mysql-B 來表示。

mysql-A 落在 node-1 上,mysql-B 落在 node-2 上, 兩個(gè)數(shù)據(jù)庫 svc 名跟用戶、密碼完全不相同。

出現(xiàn)詭異的現(xiàn)象這里以一張圖來說明會(huì)比較清楚一些:

其中綠線的表示訪問沒有問題,紅線表示連接 Mysql-A 提示用戶名密碼錯(cuò)誤。

特別詭異的是,當(dāng)在 Node-2 上通過 svc 訪問 Mysql-A 時(shí),輸入 Mysql-A 的用戶名跟密碼提示密碼錯(cuò)誤,密碼確認(rèn)無疑,但當(dāng)輸入 Mysql-B 的用戶名跟密碼,居然能夠連接上,看了下數(shù)據(jù),連上的是 Mysql-B 的數(shù)據(jù)庫,給人的感覺就是請(qǐng)求轉(zhuǎn)到了 Mysql-A, 最后又轉(zhuǎn)到了 Mysql-B,當(dāng)時(shí)讓人大跌眼鏡。

碰到詭異的問題那就排查吧,排查的過程倒是不費(fèi)什么事,最主要的是要通過這次踩坑機(jī)會(huì)挖掘一些奇怪的知識(shí)出來。

排查過程

既然在 Node-1 上連接 Mysql-A/Mysql-B 都沒有問題,那基本可以排查是 Mysql-A 的問題。

經(jīng)實(shí)驗(yàn),在 Node-2 上所有的服務(wù)想要連 Mysql-A 時(shí),都有這個(gè)問題,但是訪問其它的服務(wù)又都沒有問題,說明要么是 mysql-A 的 3306 這個(gè)端口有問題,通過上一步應(yīng)該排查了 mysql-A 的問題,那問題只能出在 Node-2 上。

在 k8s 中像這樣的請(qǐng)求轉(zhuǎn)發(fā)出現(xiàn)詭異現(xiàn)象,當(dāng)排除了一些常見的原因之外,最大的嫌疑就是 iptables 了,作者遇到過多次。

這次也不例外,雖然當(dāng)前集群使用的 ipvs, 但還是照例看下 iptables 規(guī)則,查看 Node-2 上的 iptables 與 Node-1 的 iptables 比對(duì),結(jié)果有蹊蹺, 在 Node-2 上發(fā)現(xiàn)有以下的規(guī)則在其它節(jié)點(diǎn)上沒有。

  1. -A CNI-DN-xxxx -p tcp -m tcp --dport 3306 -j DNAT --to-destination 10.224.0.222:3306 
  2.  
  3. -A CNI-HOSTPORT-DNAT -m comment --comment "dnat name": \"cni0\" id: \"xxxxxxxxxxxxx\"" -j CNI-DN-xxx 
  4.  
  5. -A CNI-HOSTPORT-SNAT -m comment --comment "snat name": \"cni0\" id: \"xxxxxxxxxxxxx\"" -j CNI-SN-xxx 
  6.  
  7. -A CNI-SN-xxx -s 127.0.0.1/32 -d 10.224.0.222/32 -p tcp -m tcp --dport 80 -j MASQUERADE 

其中 10.224.0.222 為 Mysql-B 的 pod ip, xxxxxxxxxxxxx 經(jīng)查實(shí)為 Mysql-B 對(duì)應(yīng)的 pause 容器的 id。

從上面的規(guī)則總結(jié)一下就是目的為 3306 端口的請(qǐng)求都會(huì)轉(zhuǎn)發(fā)到 10.224.0.222 這個(gè)地址,即 Mysql-B。

看到這里,作者明白了為什么在 Node-2 上去訪問 Node-1 上 Mysql-A 的 3306 會(huì)提示密碼錯(cuò)誤而輸入 Mysql-B 的密碼卻可以正常訪問。

雖然兩個(gè) mysql 的 svc 名不一樣,但上面的 iptables 只要目的端口是 3306 就轉(zhuǎn)發(fā)到 Mysql-B 了,當(dāng)請(qǐng)求到達(dá) mysql 后,使用正確的用戶名密碼自然可以登錄成功。

原因是找到了,但是又引出來了更多的問題?

這幾條規(guī)則是誰入到 iptables 中的?

怎么解決呢,是不是刪掉就可以?

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

同樣是 Mysql,為何 Mysql-A 沒有呢? 那么比對(duì)一下這兩個(gè) Mysql 的部署差異。

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

難道是因?yàn)?hostPort?

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

那到底是不是因?yàn)?hostPort 呢?

Talk is cheap, show me the code

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

  1. apiVersion: apps/v1 
  2.  
  3. kind: Deployment 
  4.  
  5. metadata: 
  6.  
  7. name: nginx-hostport2 
  8.  
  9. labels: 
  10.  
  11. k8s-app: nginx-hostport2 
  12.  
  13. spec: 
  14.  
  15. replicas: 1 
  16.  
  17. selector: 
  18.  
  19. matchLabels: 
  20.  
  21. k8s-app: nginx-hostport2 
  22.  
  23. template: 
  24.  
  25. metadata: 
  26.  
  27. labels: 
  28.  
  29. k8s-app: nginx-hostport2 
  30.  
  31. spec: 
  32.  
  33. nodeName: spring-38 
  34.  
  35. containers: 
  36.  
  37. - name: nginx 
  38.  
  39. image: nginx:latest 
  40.  
  41. ports: 
  42.  
  43. - containerPort: 80 
  44.  
  45. hostPort: 31123 

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

可以肯定,這些規(guī)則就是因?yàn)槭褂昧?hostPort 而寫入的,但是由誰寫入的這個(gè)問題還是沒有解決?

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

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

再次實(shí)驗(yà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:

  1.  
  2. "name""k8s-pod-network"
  3.  
  4. "cniVersion""0.3.0"
  5.  
  6. "plugins": [ 
  7.  
  8.  
  9. # ...其它的plugin 
  10.  
  11.  
  12.  
  13. "type""portmap"
  14.  
  15. "capabilities": {"portMappings"true
  16.  
  17.  
  18.  

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

另外一個(gè)比較重要的結(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 后,會(huì)在 iptables 的 nat 鏈中插入相應(yīng)的規(guī)則,而且這些規(guī)則是在 KUBE- SERVICES 規(guī)則之前插入的,也就是說會(huì)優(yōu)先匹配 hostPort 的規(guī)則,我們常用的 NodePort 規(guī)則其實(shí)是在 KUBE- SERVICES 之中,也排在其后

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

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

端口占用

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

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

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

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

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

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

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

  1. apiVersion: apps/v1 
  2.  
  3. kind: Deployment 
  4.  
  5. metadata: 
  6.  
  7. name: nginx-nodeport2 
  8.  
  9. labels: 
  10.  
  11. k8s-app: nginx-nodeport2 
  12.  
  13. spec: 
  14.  
  15. replicas: 1 
  16.  
  17. selector: 
  18.  
  19. matchLabels: 
  20.  
  21. k8s-app: nginx-nodeport2 
  22.  
  23. template: 
  24.  
  25. metadata: 
  26.  
  27. labels: 
  28.  
  29. k8s-app: nginx-nodeport2 
  30.  
  31. spec: 
  32.  
  33. nodeName: spring-38 
  34.  
  35. containers: 
  36.  
  37. - name: nginx 
  38.  
  39. image: nginx:latest 
  40.  
  41. ports: 
  42.  
  43. - containerPort: 80 
  44.  
  45. --- 
  46.  
  47. apiVersion: v1 
  48.  
  49. kind: Service 
  50.  
  51. metadata: 
  52.  
  53. name: nginx-nodeport2 
  54.  
  55. spec: 
  56.  
  57. type: NodePort 
  58.  
  59. ports: 
  60.  
  61. - port: 80 
  62.  
  63. targetPort: 80 
  64.  
  65. nodePort: 31123 
  66.  
  67. selector: 
  68.  
  69. k8s-app: nginx-nodeport2 

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

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

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

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

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

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

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

問題解決

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

另外使用較多的 port-forward 也是可以進(jìn)行端口轉(zhuǎn)發(fā)的,它又是個(gè)什么情況呢? 它其實(shí)使用的是 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,除了會(huì)影響調(diào)度結(jié)果之外,還會(huì)出現(xiàn)上述問題,可能造成的后果是非常嚴(yán)重的。

 

 

責(zé)任編輯:張燕妮 來源: 高效運(yùn)維
相關(guān)推薦

2021-11-11 16:14:04

Kubernetes

2023-12-05 08:33:44

滴滴故障k8s

2023-04-30 00:02:40

K8Skubelet數(shù)據(jù)

2022-12-17 19:49:37

GCJVM故障

2020-06-12 13:26:03

線程池故障日志

2022-11-29 21:26:26

跨域配置

2021-12-02 07:50:30

NFS故障內(nèi)存

2024-03-18 15:44:48

K8S故障運(yùn)維

2024-02-20 16:55:14

K8S云計(jì)算

2021-01-08 13:52:15

Consul微服務(wù)服務(wù)注冊(cè)中心

2020-11-02 13:44:56

CentOSK8SLinux

2021-05-26 11:06:06

Kubernetes網(wǎng)絡(luò)故障集群節(jié)點(diǎn)

2021-04-23 08:35:16

k8s故障檢測

2021-11-01 17:29:02

Windows系統(tǒng)Fork

2019-08-12 08:36:33

K8S網(wǎng)絡(luò)Pod

2022-02-23 08:01:04

KubernetesK8sPod

2017-09-01 09:17:51

DNS緩存慘案

2021-12-06 17:21:05

異常報(bào)錯(cuò)故障

2023-01-04 18:32:31

線上服務(wù)代碼

2024-01-07 19:43:50

K8S節(jié)點(diǎn)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 在线国产一区二区三区 | 国产你懂的在线观看 | 91成人午夜性a一级毛片 | 精品精品 | 精品综合久久 | 久久精品二区亚洲w码 | 久久久久国产成人精品亚洲午夜 | 久久久www成人免费精品 | 午夜免费网站 | 一区二区在线不卡 | 欧美成人影院 | www.久久久久久久久久久 | 午夜一级大片 | 日韩精品久久一区二区三区 | 91极品视频 | 亚洲欧洲中文日韩 | 国产男女猛烈无遮掩视频免费网站 | 亚洲视频中文字幕 | 中文字幕亚洲欧美 | 久久99精品国产99久久6男男 | 成人免费在线观看 | 久久久精彩视频 | 3p视频在线观看 | 欧美日韩国产三级 | 精品久久久久久久 | 91精品一区 | 黄色大片视频 | 国产精品福利在线 | 91精品国产欧美一区二区 | 国产线视频精品免费观看视频 | 激情av网站 | 久久在线免费 | 国产yw851.c免费观看网站 | 亚洲精品天堂 | 亚洲精品美女视频 | 亚洲三级av| 久久亚洲国产精品日日av夜夜 | 久久婷婷国产麻豆91 | 国产精品久久久久久久久久免费 | 波多野结衣av中文字幕 | 久久久久久久久久久久91 |