1. 程式人生 > >開發環境下的 Kubernetes 容器網路演進之路

開發環境下的 Kubernetes 容器網路演進之路

馬蜂窩技術原創文章,更多幹貨請搜尋公眾號:mfwtech

使用 Docker+Kubernetes 來簡化開發人員的工作流,使應用更加快速地迭代,縮短髮布週期,在很多研發團隊中已經是常見的做法。

如果說 Docker 提供的是應用級的主機抽象,那麼 Kubernetes 的作用就是應用級的叢集抽象,提供容器叢集執行所需的基礎設施,旨在解決容器化應用的資源排程、部署執行、服務發現、擴容縮容等問題。

一直以來,容器網路設計都被認為是非常重要,但相對複雜的部分。 本文要介紹的 Kubernetes 網路,目前主要為馬蜂窩旅遊網大多數 Java 業務提供開發環境的底層基礎設施。隨著團隊的調整及業務需求升級,整個系統對網路架構的要求也越來越嚴苛。基於這樣的背景,Kubernetes 網路過去一年多經歷了兩次比較重要的改造,以期不斷降低運維除錯成本,提高研發效率。

藉由本文分享我們的實踐經驗,與君共勉。

 

Part.1 Kubernetes 網路原理及挑戰

1. Kubernetes Pod 設計

Pod 是 Kubernetes 的基本排程單元,我們可以將 Pod 認為是容器的一種延伸擴充套件,一個 Pod 也是一個隔離體,而 Pod 內部又包含一組共享的容器。

每個 Pod 中的容器由一個特殊的 Pause 容器,及一個或多個緊密相關的業務容器組成。Pause 容器是 Pod 的根容器,對應的映象屬於 Kubernetes 平臺的一部分,以它的狀態代表整個容器組的狀態。同一個 Pod 裡的容器之間僅需通過 localhost 就能互相通訊。

每個 Pod 會被 Kubernetes 網路元件分配一個唯一的(在叢集內的 IP 地址,稱為 Pod IP,這樣就允許不同 Pod 中的服務可以使用同一埠 (同一個 Pod 中埠只能被一個服務佔用),避免了發生埠衝突的問題。

2. 挑戰

Pod 的 IP 是在 Kubernetes 叢集內的,是虛擬且局域的。這就帶來一個問題,Pod IP 在叢集內部訪問沒有問題,但在實際專案開發中,難免會有真實網路環境下的應用需要訪問 Kubernetes 叢集裡的容器,這就需要我們做一些額外的工作。

本文將結合我們開發環境下基於 K8S 容器網路演進的過程,介紹在 Pod IP 為虛擬或真實 IP 情況下的幾種直接訪問 Pod IP 的解決方案。

 

Part.2 基於 Kubernetes 的容器網路演進

第一階段:Kubernetes + Flannel

最早,我們的網路設計方案只服務於大交通業務。初期大交通的 Java 應用是部署在物理機上的,團隊內部容器相關的底層基礎設施幾乎為 0。為了更加平穩地實現容器化的落地,中間我們沒有直接把服務全部遷移到 K8S 中去,而是經歷了一段混跑。

這個過程中必然會有物理機上的 Java 應用訪問 K8S 裡 Java 容器的情況 (一個註冊中心)。當時我們選用的網路架構是 Flannel VXLAN + Kube-proxy,主要是考慮到 Flannel 的簡潔性。

Flannel 是為 K8S 設計的一個非常簡潔的多節點三層網路方案,主要用於解決容器的跨主機通訊問題,是一個比較大一統的方案。它的設計目的是為叢集中的所有節點重新規劃 IP 地址的使用規則,從而使得不同節點上的容器能夠獲得「同屬一個內網」且「不重複的」IP 地址,並讓屬於不同節點上的容器能夠直接通過內網 IP 通訊。

Flannel 的原理是為每個 host 分配一個 subnet,容器從此 subnet 中分配 IP,這些 IP 可以在 host 間路由,容器間無需 NAT 和 port  mapping 就可以跨主機通訊。每個 subnet 都是從一個更大的 IP 池中劃分的,Flannel 會在每個 host 上面執行一個守護程序 flanneld,其職責就是從大池子中分配 subnet,為了各個主機間共享資訊。Flannel 用 ETCD 存放網路配置、已分配的 subnet、host 的 IP 等資訊。

Flannel 的節點間有三種通訊方式:

  • VXLAN:預設配置,利用核心級別的 VXLAN 來封裝 host 之間傳送的包

  • Host-gw:二層網路配置,不支援雲環境,通過在 host 的路由表中直接建立到其他主機 subnet 的路由條目

  •  UDP:通常用於 debug

我們在所有的業務物理機上都部署了 Flannel,並且啟動 Flanneld 服務,使之加入 K8S 虛擬網路,這樣物理機上的服務與 K8S 裡的容器服務在互相呼叫時,就可以通過 Flannel+Kube-proxy 的虛擬網路。整體結構圖如下:

  • 流量 1 是部署在物理機和 K8S 容器裡的應用註冊服務的線路

  • 流量 2 是兩個物理機節點互相呼叫時的線路

  • 流量 3 是物理機節點呼叫 K8S 容器應用時的線路,反之 app3 呼叫 app1 時就會直接訪問 app1 所在的物理機 IP

第二階段:Kubernetes + Flannel+ VPN-server

為了加速大交通業務微服務和容器化的落地,我們在團隊內部完成了開發環境容器化的改造,並將所有流量全部遷移到 K8S 編排系統上。

大交通整體的微服務改造基於 Dubbo。瞭解的朋友都知道,Dubbo 服務中 Consumer 和 Provider 的通訊很常見,對應到我們的場景就有了本地 Dubbo 服務 (Consumer) 消費開發環境微服務 (Provider),以及本地遠端 debug 開發環境的情況。但是 Dubbo consumer 從註冊中心拿到的都是容器的虛擬網路 IP,在叢集外的真實網路環境里根本訪問不通。

為了解決這個問題,提高開發與聯調效率,我們開始了第一次 K8S 容器網路方案的改造。

我們設想,既然一個公司的員工可以通過撥通 VPN,從公網進入到公司的內網,那如果在 K8S 叢集內部署一個 OpenVPN 的 Server,是不是也可以從叢集外進入到叢集的內網之中?實現思路如下圖所示:

  • 我們在叢集的 middleware 空間下以 nodeport 的方式部署了 VPN Server,並給客戶端分配了 10.140 的網段

  • 當客戶端通過 172.18.12.21:30030 撥通 VPN 時,客戶端與 VPN Server 間的網路被打通

  • 因為 VPN Server 本身處於叢集虛擬網路環境中,所以其他容器的 IP 對於 vpn server 是可見的,因此撥通 VPN 後,VPN 客戶端就可以直接對叢集內的 Pod 進行訪問

改造後開發環境與機房 K8S 叢集之間的網路架構圖如下所示:

通過在 K8S 叢集裡架設 OpenVPN,我們暫時解決了辦公區對機房 K8S 叢集的 RPC 通訊問題。該方案的優缺點如下:

優點:

  • 快速實現

  • 工程量小

  • 網路隔離,證書驗證更安全

不足:

  • 操作略繁瑣,如使用時需要申請證書,安裝客戶端軟體;每次使用前需要先開啟 OpenVPN

  • 是一種中間方案,沒有從本質上解決問題

第三階段:基於 MAC-VLAN 的 Kubernetes CNI

為了更好地支援 Java 業務的微服務改造,避免重複造輪子,我們構建了統一的 Java 基礎平臺,之前的網路方案也面向更多的部門提供服務。

隨著服務的業務和人員越來越多,由人工操作帶來的不便和問題越來越明顯,我們決定對 K8S 網路進行再一次改造。從之前的經驗中我們感到,如果 K8S 的虛擬網路不去除,容器服務的 IP 是不可能直接由叢集外的真實網路到達的。

為了快速滿足不同業務場景下對於 K8S 網路功能的需求,我們開始深入研究 CNI。

關於 CNI

CNI (Conteinre Network Interface) 旨在為容器平臺提供統一的網路標準,由 Google 和 CoreOS 主導制定。它本身並不是一個完整的解決方案或者程式程式碼,而是綜合考慮了靈活性、擴充套件性、IP 分配、多網絡卡等因素後,在 RKT 的基礎上發展起來的一種容器網路介面協議。

CNI 的網路分類和主流的實現工具主要包括:

  • 第⼀類:與宿主機平⾏⽹絡(2 層⽹絡或 3 層⽹絡),⽹絡外掛主要包括 Bridge、MAC-VLAN 、IP-VLAN、Calico BGP、Flannel host-GW 等

  • 第⼆類:利⽤ SDN 技術的虛擬⽹絡,⽹絡外掛主要有:Flannel vxlan、Calico ipip、Weave 等

MAC-VLAN  及其帶來的問題

通過對比測試,考慮到當下需求,我們最終決定基於網路改造、運維成本和複雜度都較低的 MAC-VLAN  方案:

MAC-VLAN 具有 Linux Kernal 的特性,用於給一個物理網路介面(parent)配置虛擬化介面。虛擬化介面與 parent 網路介面擁有不同的 mac 地址,但 parent 介面上收到發給其對應的虛擬化介面的 mac 包時,會分發給對應的虛擬化介面,有點像將虛擬化介面和 parent 介面進行了「橋接」,使虛擬化網路介面在配置了 IP 和路由後就能互相訪問。

在 MAC-VLAN 場景下,K8S 容器訪問可能會遇到一些問題,比如配置 MAC-VLAN 後,容器不能訪問 parent 介面的 IP。

通過調研,發現有以下兩種解決方案:

1. 虛擬網絡卡:開啟網絡卡混雜模式,通過在宿主機上虛擬出一個虛擬網絡卡,將虛擬網絡卡與宿主機真實網絡卡聚合繫結

2. PTP 方案:類似 Bridge 的簡化版,但是網路配置更復雜,並且有一些配置在自測過程中發現並沒有太大用處。與 Bridge 主要的不同是 PTP 不使用網橋,而是直接使用 vethpair+路由配置。

通過對比兩種方案的可實施性,最終我們選擇了第一種方案,但是第一種方案在虛擬機器環境中經過測試發現偶爾會有宿主機與本機容器不通的現象,建議採用第一種方案的同學儘量不要使用虛擬機器環境(懷疑還是網絡卡混雜設定的問題)。

「分割槽而治」的網路改造

K8S 的核心元件 KubeDNS 在啟動時預設會訪問 ClusterIP 段的第一個 IP;如果繼續使用原有的 Nginx-ingress,那麼 Nginx-ingress 的容器在啟動時也是使用 ClusterIP 去連線 KubeDNS。而使用 MAC-VLAN 給 KubeDNS 和 Nginx-ingress 分配的都是真實網路 IP,他們是無法聯通 ClusterIP 的,所以 KubeDNS 和 Nginx-ingress 容器又不能使用 MAC-VLAN 方案,否則容器服務的域名訪問能力將喪失。

綜合考慮之下,最終我們採取了「分割槽而治」的措施,將不同類別的容器排程到不同的區域,使用不同的網路方案,大致的圖解如下:         

      

採用 MAC-VLAN 方案時容器 IP 的分配方案有兩種:DHCP 和 host-local。考慮到公司目前沒有統一的 DHCP 和 IPAM 伺服器為容器分配 IP,開發環境的機器數量不多,我們就採用了人工參與每個節點的網路 IP 段分配。

綜上,此次改造後的網路架構圖大致如下:

效果

可以看到與第一次網路改造的架構圖對比:

  • 宿主機 1 和宿主機 2 上已經拋棄了 Kube-proxy 和 Flannel 這些虛擬網路的元件

  • 宿主機 1 和宿主機 2 這些業務容器節點直接使用了公司公共 DNS 設施

  • 辦公區本地 consumer 服務在註冊中心拿到 provider 的 IP 後,可以直接連線消費,反之亦可

  • K8S 叢集分為了虛擬網路區 (執行 K8S  叢集管理元件) 和真實網路區 (執行業務容器)

此次改造的優勢和不足總結為:

優點:

  • 遠端 debug

  • 辦公網與叢集內服務間的 RPC,TCP 通訊在二層網路中打通

  • 網路延遲大大降低

  • 支援多機房容災部署

缺點:

  • 工程量大

  • 需要耗費大量真實 IP 地址

  • 叢集規模很大時,存在 ARP 廣播風暴和交換機 MAC 表超限風險

 

Part.3 近期優化方向

每一次挑戰都是進步的基石。K8S 網路系統自上線以來,極大提高了 Java 業務容器化的運維效率,降低了運維成本,同時提供了更靈活、更穩定的服務執行環境。

在使用和改造 K8S 網路的過程中, 我們也遇到了很多問題,比如服務的優雅上下線、容器 HPA 的設定規則、容器模版的多樣化支援等等,近期我們將重點針對以下幾方面近一步優化和改進: 

1. 生產環境逐步進行網路改造,並實現叢集多機房部署,提高容災能力

2. 對第二次網路改造中的虛擬網路區中的 Nginx-ingress 二次開發,使其支援使用公司公共 DNS,並且廢棄 SVC,徹底拋棄虛擬網路的使用

本文作者:張小伍,馬蜂窩旅遊網交酒平臺研發工程師。

 

相關推薦

開發環境Kubernetes 容器網路演進

馬蜂窩技術原創文章,更多幹貨請搜尋公眾號:mfwtech 使用 Docker+Kubernetes 來簡化開發人員的工作流,使應用更加快速地迭代,縮短髮布週期,在很多研發團隊中已經是常見的做法。 如果說 Docker 提供的是應用級的主機抽象,那麼 Kubernetes 的作用就是應用級的叢集抽象,提供容

阿里集團八年容器演進

近日,阿里集團內部已經實現 100% 容器化映象化;距離 PouchContainer 開源不到

一文帶你瞭解資料中心大二層網路演進

摘要:傳統的三層資料中心,置身虛擬機器化的浪潮中,其中變革創新,就在此篇文章中一窺究竟吧。 傳統資料中心三層組網架構 政府部門或者金融機構等大型企業的資料中心中伺服器的規模可能會達到2000臺以上。一般情況下,資料中心網路都會進行伺服器的分割槽管理,單個業務分割槽規模不大,此時可以採用下圖所示的標準三層架構。

Kubernetes & Docker 容器網路終極

與 Docker 預設的網路模型不同,Kubernetes 形成了一套自己的網路模型,該網路模型更加適應傳統的網路模式,應用能夠平滑的從非容器環境遷移到 Kubernetes 環境中。 自從 Docker 容器出現,容器的網路通訊一直是眾人關注的焦點,而容器的網路方案又可以分為兩大部分: 單主機的容

Kubernetes & Docker 容器網路終極戰(十四)

目錄 一、單主機 Docker 網路通訊 1.1、host 模式 1.2 Bridge 模式 1.3 Container 模式 1.4、None 模式 二、跨主機 Docker 網路通訊分類 2.1 通訊方案 2.2、容器網路規範

Eclipse開發環境搭建Maven

-1 mage cal 配置文件 pub 添加 apache local 打開 (一)開發環境   Eclipse Mars2(4.5.2) + Maven 3.5.0 (二)配置步驟   1.首先,需要將Maven環境配置好,maven下載地址:http://maven

vue跨域的問題,在開發環境

直接 index 文件 訪問 顯示 vue pat user rewrite 找到config文件夾下的index.js proxyTable: { ‘/api‘: { target: ‘http://訪問網址/‘, //設置調

今日頭條架構演進——高壓的架構演進專題

合服 51cto 還需要 ESS color 壓力 一點 日誌 規劃 今天給大家分享今日頭條架構演進,前面幾位講師講了很多具體的幹貨,我的分享偏重基礎設施及架構思路的介紹,我們想法是通過提供更好的基礎設施,幫助架構做更好的叠代。 從架構的角度,技術團隊應對的壓力最主要來自三

專訪UCloud徐亮:UCloud虛擬網路演進

伺服器虛擬化改變了IT運營方式,隨之而來的是越來越多的網路被虛擬化。 當今,幾乎所有的IT基礎架構都在朝雲的方向發展。在基礎架構中,伺服器和儲存虛擬化已經發展的比較成熟,作為基礎架構中的虛擬網路,為了迎合雲端計算和網際網路發展的需求,迎來了新的挑戰,UCloud虛擬網路平臺負責人徐亮對此進行了梳

python開發環境pip和pip3的區別

在很多教程裡都有遇到的pip和pip3,簡單來說pip和pip3是一樣的,只是為了區別python2和python3之間的呼叫,避免衝突而進行的設定。如果你的電腦只安裝了python3,那麼你使用pip和pip3效果都是一樣的,如果你的電腦只安裝了python,那麼你無法使用pip3。 同時

開發環境PP檔案的建立

開發環境下Provisioning Profile檔案的建立。 當我們在做iOS開發的時候,總是新增很多證書,來保證安全性。Provisioning Profile我們又稱PP檔案。這個檔案將證書、App Id和裝置相關聯。本章節就是教大家如何建立開發環境下的

從零開始學習比特幣開發(九)--P2P 網路建立訊息處理中篇

P2P 網路的建立是在系統啟動的第 12 步,最後時刻呼叫 CConnman::Start 方法開始的。 恭喜你越來越接近比特幣的核心了,在上篇中,我們主要講解了比特幣的訊息處理執行緒,接下來,在下篇中,將以具體的比特幣訊息即比特幣協義分析為主。針對比特幣的協義

Android——離線開發環境的安裝與配置

前提jdk安裝並且配置成功。參考部落格https://blog.csdn.net/t_yoo_csdn/article/details/79726772一, gradle方法1:(驗證可以)在工程目錄\gradle\wrapper\gradle-wrapper.propert

EOS開發環境eosio_assert顯示詳細錯誤資訊

前幾天在本地環境下除錯EOS程式碼時,執行程式碼之後只有簡簡單單的"Error 3050003: eosio_assert_meesage"的輸出,無法定位到哪個eosio_assert報出的錯誤。於是,查找了一番,解決之後記錄下。 首先,在啟動Docker的時候,加上--verbose-htt

kubernetes容器網路介面(CNI) midonet網路外掛的設計與實現_Kubernetes中文社群

相關原理概述 先來講講什麼是CNI? CNI(容器網路介面)是一種操作容器網路規範,包含方法規範,引數規範等。 CNI只關心容器的網路連線,在容器建立時分配網路資源,並在刪除容器時刪除分配的資源。因為這個焦點,CNI有廣泛的支援,規格易於實現。CNI介面只需要實現兩個方法,一個建立容器時呼叫,一個刪除容器時

開發環境未找到 BASE64Encoder及BASE64Decoder的解決辦法

Base64的加密解密都是使用sun.misc包下的BASE64Encoder及BASE64Decoder的sun.misc.BASE64Encoder/BASE64Decoder類這個類是sun公司的

Android正式和開發環境切換操作,BuildConfig幫你一步到位

在Android開發中,正式和測試環境的切換,一般情況下我們都會去設定一個tag,通過此tag來改變開發環境。 以前的寫法一般都是: public class BaseApplication extends Application { public boolean

64位開發環境編譯32位dll檔案

       最近在做PH專案的時候,遇到了一個小問題。我們做的系統,算是在人家基礎上的一個二次開發:我們用到他們裝置,同時需要他們給我們提供介面。我們拿到介面,在32位系統上編譯不會出問題,而在我

在Eclipse開發環境搭建Hadoop2.6.0

Eclipse版本Luna 4.4.1 安裝外掛hadoop-eclipse-plugin-2.6.0.jar,下載後放到eclipse/plugins目錄即可。 2. 配置外掛 2.1 配置hadoop主目錄 解壓縮hadoop-2.6.0.tar.g

window 環境 Caffe 繪製網路結構圖

嘗試 caffe Windows 環境下繪製網路結構圖記錄 首先配置Windows 環境下的python介面 配置完成,測試成功後,如下圖所示 繪製網路結構 1 使用draw_net.p