多環境下的Kubernetes網絡打通方案研究

更多關注: https://mknight.cn/

前言

本文中的Kubernetes集群統稱為集群。

現實的工作環境中,我們可能會在開發環境使用Kubernetes,也會在測試和開發環境使用Kubernetes。而一般來說,大部分人不會直接去連接或訪問生產環境的集群,但是對于開發環境就不一樣了。很多開發人員需要經常訪問開發環境,而不是在本地起一堆依賴的服務。而且真的只有這么一個問題嗎?

常見問題

整理了若干常見的問題:

  1. 開發人員本地服務訪問開發環境
  2. 新集群和舊集群的網絡互通,或者遷移
  3. 域名訪問

因此,我們需要解決以上問題,才能更安心的使用Kubernetes。

網絡互通

首先來解決最主要的問題,如何實現不同網絡環境下的互通問題?

眾所周知,集群暴露服務的方式有以下幾種:

  1. NodePort 每個服務維護一個端口,服務越多端口越多
  2. LoadBalancer 在nodePort的基礎上使用公有云的負載均衡器
  3. ClusterIP 每個service有一個虛擬IP
  4. Ingress 一個服務暴露多個service的服務,本質是一種路由轉發機制

場景一、注冊中心eureka的應用

首先ureka可以使用StatefulSet的方式,實現一個集群的部署。以下文件可以直接使用:

1. 辦公網訪問應用

開發人員本地訪問的時候可以使用NodePort的方式訪問,也可以使用Ingress的方式訪問。

[圖片上傳失敗...(image-9ee49c-1659432853998)]

如圖所示,創建了兩個Python的應用,并注冊到eureka。代碼如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@time:2022/04/27
@file:test_eureka.py
@author:medivh
@IDE:PyCharm 
"""
from flask import Flask
import py_eureka_client.eureka_client as eureka_client

app = Flask(__name__)


def setEureka():
    eureka_client.init(eureka_server="http://192.168.1.217:31331/eureka",
                       app_name="flask_server-2",
                       # 當前組件的主機名,可選參數,如果不填寫會自動計算一個,如果服務和 eureka 服務器部署在同一臺機器,請必須填寫,否則會計算出 127.0.0.1
                       instance_host='10.1.3.141',
                       instance_port=5001,
                       # 調用其他服務時的高可用策略,可選,默認為隨機
                       ha_strategy=eureka_client.HA_STRATEGY_RANDOM)


setEureka()


@app.route('/')
def hello_world():
    return 'Hello World!'


@app.route('/info')
def hello_info():
    return 'Hello Info!'


if __name__ == '__main__':
    app.run(debug=True, threaded=True, port=5001, host="0.0.0.0")

另外一個測試腳本:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@time:2022/04/27
@file:test_eureka-service.py
@author:medivh
@IDE:PyCharm 
"""
import py_eureka_client.eureka_client as eureka_client
import json

eureka_client.init(eureka_server="http://192.168.1.109:31331/eureka", app_name='do_service', instance_host="10.1.3.141",
                   instance_port=5011)
# get請求的調用
res = eureka_client.do_service("flask_server-2", "/info",
                               # 返回類型,默認為 `string`,可以傳入 `json`,如果傳入值是 `json`,那么該方法會返回一個 `dict` 對象
                               return_type="string")
print(res)
res = eureka_client.do_service("O2O-SERVICE", "/env-path/actuator/info",
                               # 返回類型,默認為 `string`,可以傳入 `json`,如果傳入值是 `json`,那么該方法會返回一個 `dict` 對象
                               return_type="string")
print(res)
## post請求的調用
# d = {'a': 1}
# res = eureka_client.do_service('helloindex', '/user', return_type='string', method='POST', data=json.dumps(d))
# print(res)
res = eureka_client.do_service("O2O-SERVICE", "/env-path/actuator/info",
                               # 返回類型,默認為 `string`,可以傳入 `json`,如果傳入值是 `json`,那么該方法會返回一個 `dict` 對象
                               return_type="string")
print(res)

調用測試結果:

python test_eureka-service.py
Hello Info!

Traceback (most recent call last):
  File "/Users/medivh/github/box/test_eureka-service.py", line 19, in <module>
    res = eureka_client.do_service("O2O-SERVICE", "/",
  File "/Users/medivh/github/box/venv/lib/python3.8/site-packages/py_eureka_client/eureka_client.py", line 1736, in do_service
    return cli.do_service(app_name=app_name, service=service, return_type=return_type,
  File "/Users/medivh/github/box/venv/lib/python3.8/site-packages/py_eureka_client/eureka_client.py", line 1467, in do_service
    return self.walk_nodes(app_name, service, prefer_ip, prefer_https, walk_using_urllib)
  File "/Users/medivh/github/box/venv/lib/python3.8/site-packages/py_eureka_client/eureka_client.py", line 1415, in walk_nodes
    raise http_client.URLError("Try all up instances in registry, but all fail")
urllib.error.URLError: <urlopen error Try all up instances in registry, but all fail>
[2022-04-27 17:32:39]-[eureka_client]-[line:1409] -WARNING: do service / in node [o2o-service-287077292-hj7q7:o2o-service:8080] error, use next node. Error: <urlopen error timed out>

這個時候說明注冊中心是可以正常使用的,但是如果調用集群的服務就無法訪問了,畢竟不在一個網段,也沒有合適的路由。接下來就去解決這個問題。

2.辦公網訪問集群Pod/Service

在網關和路由器上添加路由,把屬于集群的Pod和Service的子網IP全部轉發給其中某個node,這樣訪問Pod IP和Service IP,網絡包會到達某個node,而集群內的node中,CNI會與這些目的地址互通。

網段:

網段名稱 網段范圍
辦公網段 10.1.3.0/24
Pod地址池 10.200.0.0/16
Svc地址池 10.96.0.0/12

如果不記得當時設置的網段是多少,可以用以下方式查詢:

~ kubectl get cm kubeadm-config -n kube-system -o yaml | grep -i podsub
      podSubnet: 10.200.0.0/16
~ kubectl get cm kubeadm-config -n kube-system -o yaml | grep -i servicesub
      serviceSubnet: 10.96.0.0/12
steps 1

選擇集群中的一個節點進行路由轉發,可以使用一臺配置不高的節點,打上污點不允許調度占用資源。本文中使用的是master節點。

  1. 設置污點 kubectl taint nodes k8s-master forward=k8s-node5:NoSchedule
  2. 開啟路由轉發 echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
  3. 查看是否生效 sysctl -p
# 開啟轉發
~ vim /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
~ sysctl -p
 
# 在k8s-master上設置snat
~ iptables -t nat -A POSTROUTING -s 10.200.0.0/16  -d 10.1.3.0/24   -j MASQUERADE
~ iptables -t nat -A POSTROUTING -s 10.96.0.0/12 -d 110.1.3.0/24   -j MASQUERADE
 
# (可選)查看設置的snat
~ iptables -t nat -L -n --line-numbers | grep -A 10 "Chain POSTROUTING"
Chain POSTROUTING (policy ACCEPT)
num  target     prot opt source               destination        
1    ......
2    ......
3    ......
4    MASQUERADE  all  --  10.1.3.0/24          10.200.0.0/16
5    MASQUERADE  all  --  10.1.3.0/24          10.96.0.0/12

# (可選)如配置失誤可刪除已設置的snat條目
~ iptables -t nat -D POSTROUTING 4
setps 2

在辦公網的出口路由上設置靜態路由,將集群的Pod和Service網段,路由到master節點。

# 在路由器上需要做的配置:
ip route add -net  10.200.0.0/16 gw 192.168.1.109
ip route add -net  10.96.0.0/12 gw 192.168.1.109

[圖片上傳失敗...(image-7dee38-1659432853998)]

setps 3

這個時候在辦公網主機上ping 集群中的Pod或者service的IP,理論上就是通的。

# Pod 
?  ~ traceroute 10.200.96.148
traceroute to 10.200.96.148 (10.200.96.148), 64 hops max, 52 byte packets
 1  10.1.3.1 (10.1.3.1)  2.781 ms  2.422 ms  2.388 ms
 2  bogon (192.168.1.109)  2.723 ms  3.352 ms  3.647 ms
 3  bogon (10.200.96.128)  3.724 ms  3.485 ms  3.417 ms
 4  10.200.96.148 (10.200.96.148)  3.551 ms  3.440 ms  3.390 ms

 # service 

 ?  ~ traceroute 10.96.230.195
traceroute to 10.96.230.195 (10.96.230.195), 64 hops max, 52 byte packets
 1  10.1.3.1 (10.1.3.1)  5.698 ms  2.482 ms  2.375 ms
 2  10.96.230.195 (10.96.230.195)  2.774 ms  2.807 ms  2.834 ms
問題總結

如果以上操作都執行了,但是還是不通,請檢查以下項目:

  1. 轉發是否開啟
  2. iptables的規則是否正確
  3. iptables規則是否有MASQUERADE all -- 192.168.1.0/24 0.0.0.0/0 這么一條

至此,解決了開發人員無法在辦公網訪問集群環境的IP問題。

跨集群訪問

如果我們有多個集群,這個時候如果實現網絡打通呢,比如新舊集群遷移的時候?

以IP形式訪問

其實我們依然可以采用之前的方案,添加靜態路由。

網段:

網段名稱 網段范圍
辦公網段 10.1.3.0/24
集群A Pod地址池 10.200.0.0/16
集群A Svc地址池 10.96.0.0/12
集群B Pod地址池 10.100.0.0/16
集群B Svc地址池 10.254.0.0/16

主要實現邏輯是每個集群選擇一個節點,開啟路由轉發,實現辦公網段可以訪問集群中的IP。

~ iptables -t nat -A POSTROUTING -s 10.1.3.0/24 -d 10.254.0.0/16 -j MASQUERADE -w
~ iptables -t nat -A POSTROUTING -s 10.1.3.0/24 -d 10.100.0.0/16 -j MASQUERADE -w
~ iptables -t nat -L -n --line-numbers | grep -A 10 "Chain POSTROUTING"
Chain POSTROUTING (policy ACCEPT)
num  target     prot opt source               destination
1    MASQUERADE  all  --  10.100.72.0/24       0.0.0.0/0
2    KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
3    MASQUERADE  all  --  10.1.3.0/24          10.254.0.0/16
4    MASQUERADE  all  --  10.1.3.0/24          10.100.0.0/16

Chain DOCKER (2 references)
num  target     prot opt source               destination
1    RETURN     all  --  0.0.0.0/0            0.0.0.0/0

~ iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 0.0.0.0/0  -j MASQUERADE

驗證:

# 辦公網
?  ~ traceroute 10.100.5.7
traceroute to 10.100.5.7 (10.100.5.7), 64 hops max, 52 byte packets
 1  bogon (10.1.3.1)  2.699 ms  2.201 ms  2.140 ms
 2  *.demo.yourdomain.com (192.168.1.243)  2.213 ms  7.957 ms  7.389 ms
 3  bogon (10.100.5.0)  2.902 ms  4.637 ms  2.616 ms
 4  bogon (10.100.5.7)  4.109 ms  3.944 ms  2.782 ms

 # A集群到B集群
~ tracepath 10.100.5.7
 1?: [LOCALHOST]                                         pmtu 1500
 1:  gateway                                               0.365ms
 1:  gateway                                               2.044ms
 2:  192.168.1.243                                         0.767ms
 3:  192.168.1.243                                         0.848ms pmtu 1450
 3:  10.100.5.0                                            1.536ms
 4:  10.100.5.7                                            1.382ms reached

辦公網通過注冊中心調用

[圖片上傳失敗...(image-852dc6-1659432853998)]

以域名形式訪問Service

實現了辦公網和集群的網絡互通后,就可以實現自由訪問Pod和Service了。但是由于Pod IP會經常變化,Service IP也不是很容易記住,所以希望通過內網DNS的形式訪問*.cluser.local時自動解析相應的IP。

steps 1. 獲取coredns的IP

~ kubectl get svc -n kube-system -l k8s-app=kube-dns
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   34d

steps 2. 部署DNS服務dnsmasq

yum install dnsmasq

修改/etc/dnsmasq.conf:

resolv-file=/etc/resolv.dnsmasq.conf   #指定上游dns服務器
strict-order   #嚴格按照resolv-file文件中的順序進行從上到下解析,直到成功為止
server=/cluster.local/10.96.0.10  #指定以cluster.local為后綴的域名,使用coredns的地址解析,這里可以不配直接把coredns配置在/etc/resolv.dnsmasq.conf 里面。
listen-address=192.168.1.109   #指定本地IP地址
addn-hosts=/etc/dnsmasq.hosts   #自定義dns記錄文件
conf-dir=/etc/dnsmasq.d    #所有的解析記錄都會存在此目錄下

修改resolv.dnsmasq.conf

nameserver 61.139.2.69
nameserver 202.106.0.20
nameserver 192.168.1.109

開機并啟動:

systemctl enable dnsmasq && systemctl start dnsmasq

steps 3. 驗證

在其他機器上測試

~ traceroute eureka.default.svc.cluster.local
traceroute to eureka.default.svc.cluster.local (10.200.229.155), 30 hops max, 60 byte packets
 1  192.168.1.1 (192.168.1.1)  0.151 ms  0.145 ms  0.137 ms
 2  new.eureka.com (192.168.1.109)  0.622 ms  0.595 ms *
 3  bogon (10.200.229.128)  1.311 ms  1.972 ms  2.019 ms
 4  bogon (10.200.229.155)  2.075 ms  2.743 ms  2.741 ms

curl -I eureka.default.svc.cluster.local:8761
HTTP/1.1 200
X-Application-Context: DiscoveryServer:8761
Content-Type: text/html;charset=UTF-8
Content-Language: en-US
Content-Length: 7451
Date: Thu, 28 Apr 2022 05:47:08 GMT

后來在其他的服務器上測試可以正常訪問,在Mac下能使用nslookup解析,但是無法訪問,也無法路由跟蹤,以后再解決。

后來發現如果是Mac的話,直接在網絡設置-高級-DNS,添加dns地址并拖到上面即可實現訪問。只是奇怪的是手動修改/etc/resolv.conf 并沒有實現訪問,這種界面的形式反而可以,總之,解決了問題。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,412評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,514評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,373評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,975評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,743評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,199評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,262評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,414評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,951評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,780評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,527評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,218評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,649評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,889評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,673評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容