1、背景
近期工作中出現了一個問題:某個舊服務中用到了redis
,但是在前期項目容器化改造部署階段研發同事並沒有說明需要用到redis
,直至部署生產prod
環境出現問題。
那么疑問來了,為什么在qa
環境沒有問題呢?經溝通排查發現,源碼中也就是qa
環境連接的是一個古老的虛擬機運行的redis
,所以自然研發測試環境都沒問題,至於為什么會連接到這個地址,不得而知!
第一想法:關掉這個redis
服務,讓研發“被迫”主動告知;規范要求,在k8s
集群內部部署該項目的redis
服務集群,保證環境一致性,減少不必要麻煩。
項目多數屬於微服務應用模塊,研發本地無法完整運行全部依賴,希望在本地運行某個服務后,能夠注冊到qa
容器環境的依賴服務中進行調試。
例如在k8s
中運行的redis
、rabbitmq
等服務,研發在當前環境下無法直接通過客戶端工具連接進行訪問,給研發測試進行聯調帶來了很大麻煩,且k8s
內部通過cni
插件創建pod
和service
的內部網絡,這類服務無法通過ingress
進行7層暴露,如果通過NodePort
模式暴露給研發,不僅使用有限而且會導致端口管理困難從而工作量加大。因此打通開發和測試環境k8s
集群內網和辦公局域網絡是有很大必要性的。
2、環境說明
相關網絡拓撲如下

ip
地址情況如下
- 辦公子網:172.16.0.0/24
DMZ
區域服務器子網:172.16.1.0/24、172.16.2.0/24k8s pod
子網:172.20.0.0/16k8s service
子網:10.68.0.0/16
其他涉及到的相關服務及ip
說明
-
k8s
網絡插件:flannel
,對應網絡模式為host-gw
-
k8s kube-dns service ip
:10.68.0.2 -
內網
dns
服務:ms(windows) server dns -
內網
dns ip
:172.16.2.3 -
FortiGate ip
:172.16.2.254
3、總體思路
k8s
集群部署在測試機房,整個局域網鏈路、外網、防火牆由飛塔防火牆FortiGate
設備統一控制,除k8s
集群內部網絡外,其他網絡均已通過FortiGate
打通,所以目前面臨的問題就是網絡打通和dns
解析打通。
-
網絡打通
於是,在網關和路由器上添加靜態路由,把屬於
k8s
的Pod
和Service
的子網IP
包全轉給其中某個k8s node
節點,這樣訪問pod ip
和service ip
這樣的IP
,網絡包會到達某個集群物理節點,而集群內的物理節點或虛擬機,k8s
網絡cni
插件都會與這些目的地址互通。 -
dns
解析打通網絡打通后,就可以在辦公網絡通過
pod
或service
的ip
進行連通了。但是每次更新服務,ip
通常都會發生變化,我們想通過服務名稱(域名)而不是ip
進行通信,解決dns
問題主要有以下兩個方向- 網絡已經打通了,那么就可以把
k8s
的coredns
作為本地的dns
服務器 - 把所有通過辦公網絡請求
k8s
中的服務(域名)的記錄從內網dns
服務器轉發到k8s
的coredns
上述兩種方式都可以實現
dns
的互聯互通。綜合考慮,為了保證兩處dns
服務的穩定性,只將經過k8s
內部服務的dns
請求通過coredns
,且減少了PC
客戶端dns
服務器地址的配置工作,選擇方案二。 - 網絡已經打通了,那么就可以把
4、網絡打通的具體實現
4.1 檢查現有網絡連通情況
4.1.1 辦公網絡和k8s node
在本地pc
電腦上操作
➜ ~ ping 172.16.1.106 -c 4
PING 172.16.1.106 (172.16.1.106): 56 data bytes
64 bytes from 172.16.1.106: icmp_seq=0 ttl=63 time=1.621 ms
64 bytes from 172.16.1.106: icmp_seq=1 ttl=63 time=1.568 ms
64 bytes from 172.16.1.106: icmp_seq=2 ttl=63 time=1.221 ms
64 bytes from 172.16.1.106: icmp_seq=3 ttl=63 time=1.338 ms
--- 172.16.1.106 ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 1.221/1.437/1.621/0.164 ms
4.1.2 k8s node和pod及svc
在k8s
任意一台node
上操作,通過nslookup
同時檢查網絡和dns
功能是否正常,這里以172.16.1.106
這台node
為例
[root@k8s-qa-node-02 ~]# nslookup -q=A kubernetes.default.svc.cluster.local 10.68.0.2
Server: 10.68.0.2
Address: 10.68.0.2#53
Name: kubernetes.default.svc.cluster.local
Address: 10.68.0.1
查看node
的路由
[root@k8s-qa-node-02 ~]# ip route
default via 172.16.1.254 dev eth0
169.254.0.0/16 dev eth0 scope link metric 1002
172.16.1.0/24 dev eth0 proto kernel scope link src 172.16.1.106
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.20.0.0/24 via 172.16.1.100 dev eth0
172.20.1.0/24 via 172.16.1.101 dev eth0
172.20.2.0/24 via 172.16.1.110 dev eth0
172.20.3.0/24 dev cni0 proto kernel scope link src 172.20.3.1
172.20.4.0/24 via 172.16.1.107 dev eth0
172.20.5.0/24 via 172.16.1.108 dev eth0
172.20.6.0/24 via 172.16.1.109 dev eth0
# ...省略部分條目
4.2 添加地址
網絡打通主要在網關和路由器設備上進行操作,這里僅以FortiGate
為例進行記錄。
為了配置流程清晰,通過終端命令行進行配置而不是web
界面操作,首先通過console
或者ssh
連接上FortiGate
的終端
添加k8s pod
和k8s service
兩個子網的地址
FortiGate # config firewall address
FortiGate (address) # edit k8s_SERVICE_CIDR
new entry 'k8s_SERVICE_CIDR' added
FortiGate (clientnet) # set subnet 10.68.0.0 255.255.0.0
FortiGate (clientnet) # next
FortiGate (address) # edit k8s_POD_CIDR
new entry 'k8s_POD_CIDR' added
FortiGate (clientnet) # set subnet 172.20.0.0 255.255.0.0
FortiGate (clientnet) # next
FortiGate (address) # end
FortiGate #
4.3 配置靜態路由
配置到達k8s svc
子網的路由
FortiGate # config router static
# 新增一條靜態路由,id盡量大,不與已有的沖突
FortiGate (static) # edit 10
new entry '10' added
# 配置目標地址和掩碼
FortiGate (2) # set dst 10.68.0.0 255.255.0.0
# 配置網關(下一跳)
FortiGate (2) # set gateway 172.16.1.106
# 配置接口名
FortiGate (2) # set device Test
FortiGate (2) # next
FortiGate (static) # end
FortiGate #
同理,配置到達k8s pod
子網的路由
FortiGate # config router static
FortiGate (static) # edit 11
FortiGate (2) # set dst 172.20.0.0/16 255.255.0.0
FortiGate (2) # set gateway 172.16.1.106
FortiGate (2) # set device Test
FortiGate (2) # next
FortiGate (static) # end
FortiGate #
檢查配置的靜態路由
FortiGate # get router info routing-table static
# ...省略部分條目
S 10.68.0.0/16 [10/0] via 172.16.1.106, Test
S 172.20.0.0/16 [10/0] via 172.16.1.106, Test
4.4 配置策略
配置到達k8s service
網絡放行策略
FortiGate # config firewall policy
# 新增一條網絡策略,id盡量大,不與已有的沖突
FortiGate (policy) # edit 100
# 配置源接口
FortiGate (100) # set srcintf internal
# 配置目的接口
FortiGate (100) # set dstintf Test
# 配置源地址
FortiGate (100) # set srcaddr 172.16.0.0/24
# 配置目的地址
FortiGate (100) # set dstaddr k8s_SERVICE_CIDR
# 配置動作類型
FortiGate (100) # set action accept
# 配置動作時間
FortiGate (100) # set schedule always
# 配置服務(協議類型)
FortiGate (100) # set service ALL_TCP
# 配置是否開啟日志
FortiGate (100) # set logtraffic disable
# 配置是否開啟nat
FortiGate (100) # set nat disable
end
同理,配置到達k8s pod
網絡放行策略
FortiGate # config firewall policy
FortiGate (policy) # edit 101
FortiGate (100) # set srcintf internal
FortiGate (100) # set dstintf Test
FortiGate (100) # set srcaddr 172.16.0.0/24
FortiGate (100) # set dstaddr k8s_POD_CIDR
FortiGate (100) # set action accept
FortiGate (100) # set schedule always
FortiGate (100) # set service ALL_TCP
FortiGate (100) # set logtraffic disable
FortiGate (100) # set nat disable
end
4.5 驗證配置
4.5.1 web界面檢查
登錄到FortiGate
界面,查看配置的靜態路由

網絡策略

4.5.2 pc網絡檢查
在pc
端檢查pod
網絡是否可達並在上文中選取的網關node
上抓包

5、dns解析打通的具體實現
5.1 配置dns條件轉發
上面已經將網絡進行了打通,dns
解析的打通在內網dns服務器上設置dns
轉發即可。
打開ms(windows) server
類型的dns
管理器配置界面,新增條件轉發器,如下所示,dns
域填寫k8s
集群中兼容所有命名空間的搜索域。當然,為了安全,建議單獨設置允許可達的命名空間下的服務,例如default
,則填為default.svc.cluster.local
。

5.2 驗證配置
在本地終端上測試解析k8s service
域名,成功解析
➜ ~ nslookup redis-abc-gns.default.svc.cluster.local
Server: 172.16.2.3
Address: 172.16.2.3#53
Non-authoritative answer:
Name: redis-dkj-gns.default.svc.cluster.local
Address: 172.20.4.222
6、小結
至此,就成功的將辦公網絡和k8s
內網進行打通,研發以后就可以在開發機器上利用和qa
環境一樣配置的svc name
連接對應依賴的redis
等組件了。
此方案主要利用局域網靜態路由,在網關進行配置。透明且高效,且開發測試環境無須再部署其他組件。