天天看點

Kubernetes網絡一年發展動态與未來趨勢

Kubernetes網絡模型

談到Kubernetes的網絡模型,就不能不提它著名的“單Pod單IP”模型,即每個Pod都有一個獨立的IP,Pod内所有容器共享網絡namespace(同一個網絡協定棧和IP)。“單Pod單IP”網絡模型為我們勾勒了一個Kubernetes扁平網絡的藍圖,在這個網絡世界裡:容器之間直接通信,不需要額外的NAT(網絡位址轉換);Node與容器之間,同樣不需要額外的NAT;在其他容器和容器自身看到的IP也一樣的。扁平化網絡的優點在于:沒有NAT的性能損耗,可追溯源位址進而為後面的網絡政策做鋪墊,易排錯等。

總體而言,如果叢集内要通路Pod,走Service,至于叢集外要通路Pod,走的是Ingress。Service和Ingress是Kubernetes專門的抽象出來的和服務發現相關的概念,後面會做詳細讨論。

類似于CRI之于Kubernetes的Runtime,Kubernetes使用CNI(Container Network Interface)作為Pod網絡配置的标準接口。需要注意的是,CNI并不支援Docker網絡,也就是說docker0網橋會被CNI的各類插件“視而不見”。

上圖描繪了當使用者在Kubernetes裡建立了一個Pod後,CRI和CNI協同建立所有容器并為他們初始化網絡棧的全過程。

具體過程如下:當使用者在Kubernetes的Master那邊建立了一個Pod後,Kubelet觀察到新Pod的建立,于是首先調用CRI(後面的Runtime實作,比如:dockershim,containerd等)建立Pod内的若幹個容器。在這些容器裡面,第一個被建立的Pause容器是比較特殊的,這是Kubernetes系統“贈送”的容器,裡面跑着一個功能十分簡單的Go語言程式,具體邏輯是一啟動就去select一個空的Go語言channel,自然就永遠阻塞在那裡了。一個永遠阻塞而且沒有實際業務邏輯的pause容器到底有什麼用呢?用處大了。我們知道容器的隔離功能利用的是Linux核心的namespace機制,而隻要是一個程序,不管這個程序是否處于運作狀态(挂起亦可),它都能“占”着一個namespace。是以,每個Pod内的第一個系統容器Pause的作用就是為占用一個Linux的network namespace,而Pod内其他使用者容器通過加入到這個network namespace的方式來共享同一個network namespace。使用者容器和Pause容器之間的關系有點類似于寄居蟹和海螺的關系。

是以,Container Runtime建立Pod内所有容器時,調用的都是同一個指令:

$ docker run --net=none
      

意思是隻建立一個network namespace,而不初始化網絡協定棧。如果這個時候通過nsenter方式進入到容器,會看到裡面隻有一個本地回環裝置lo。那麼容器的eth0是怎麼建立出來的呢?答案是CNI。

CNI主要負責容器的網絡裝置初始化工作。Kubelet目前支援兩個網絡驅動,分别是:kubenet和CNI。

Kubenet是一個曆史産物,即将廢棄,是以這裡也不準備過多介紹。CNI有多個實作,官方自帶的插件就有p2p,bridge等,這些插件負責初始化Pause容器的網絡裝置,也就是給eth0配置設定IP等,到時候Pod内其他容器就用這個IP與外界通信。Flanne,Calico這些第三方插件解決Pod之間的跨機通信問題。容器之間的跨機通信,可以通過bridge網絡或overlay網絡來完成。

上圖是一個bridge網絡的示意圖。Node1上Pod的網段是10.1.1.0/24,接的Linux網橋是10.1.1.1,Node2上Pod的網段是10.1.2.0/24,接的Linux網橋是10.1.2.1,接在同一個網橋上的Pod通過區域網路廣播通信。我們發現,Node1上的路由表的第二條是:

10.1.1.0/24 dev cni0
      

意思是所有目的位址是本機上Pod的網絡包,都發到cni0這個Linux網橋去,進而廣播給Pod。

注意看第三條路由規則:

10.1.2.0/24 via 192.168.1.101
      

10.1.2.0/24是Node2上Pod的網段,192.168.1.101又恰好是Node2的IP。意思是,目的位址是10.1.2.0/24的網絡包,發到Node2上。

這時候我們觀察Node2上面的第二條路由資訊:

10.1.2.0/24 dev cni0
      

就會知道這個包會被接着發給Node2上的Linux網橋cni0,然後再廣播給目标Pod。回程封包同理走一條逆向的路徑。是以,我們可以得出一個小小的結論:bridge網絡本身不解決容器的跨機通信問題,需要顯式地書寫主機路由表,映射目标容器網段和主機IP的關系,叢集内如果有N個主機,需要N-1條路由表項。

至于overlay網絡,它是建構在實體網絡之上的一個虛拟網絡,其中VXLAN是目前最主流的overlay标準。VXLAN就是用UDP標頭封裝二層幀,即所謂的MAC in UDP。

上圖即一個典型overlay網絡的拓撲圖。和bridge網路類似,Pod同樣接在Linux網橋上,目的位址是本機Pod的網絡包同樣發給Linux網橋cni0。不一樣的是,目的Pod在其他節點上的路由表規則,例如:

10.1.0.0/16 dev tun0
      

這次是直接發給本機的TAP裝置tun0,而tun0就是overlay隧道網絡的入口。我們注意到,叢集内所有機器都隻需要這麼一條路由表,而不需要像bridge網絡那樣,寫N-1條路由表項。那如何才能将網絡包正确地傳遞到目标主機的隧道口另一端呢?一般情況下,例如flannel的實作,會借助一個分布式的資料庫,用于記錄目的容器IP與所在主機的IP的映射關系,而且每個節點上都會運作一個agent,例如flanneld,會監聽在tun0上,進行封包和解包操作。例如:Node1上的容器發包給Node2上的容器,flanneld會在tun0處将一個目的位址是192.168.1.101:8472的UDP標頭(校驗和置成0)封裝到這個包的外層,然後接着主機網絡的東風順利到達Node2。監聽在Node2的tun0上的flanneld捕獲這個特殊的UDP包(檢驗和為0),知道這是一個overlay的封包,于是解開UDP標頭,将它發給本機的Linux網橋cni0,進而廣播給目的容器。

什麼是CNI

CNI是Container Network Interface的縮寫,是容器網絡的标準化,試圖通過JSON來描述一個容器網絡配置。

從上圖可以看出,CNI是Kubernetes與底層網絡插件之間的一個抽象層,為Kubernetes屏蔽了底層網絡實作的複雜度,同時也解耦了Kubernetes的具體網絡插件實作。

CNI主要有兩類接口,分别是在建立容器時調用的配置網絡接口:AddNetwork(net NetworkConfig, rt RuntimeConf) (types.Result,error)和删除容器時調用的清理網絡接口:DelNetwork(net NetworkConfig, rt RuntimeConf)。

不論是配置網絡接口還是删除網絡接口,都有兩個入參,分别是網絡配置和runtime配置。網絡配置很好了解,Rumtime配置則主要是容器運作時傳入的網絡namespace資訊。符合CNI标準的預設/第三方網絡插件有:

其中CNI-Genie是一個開源的多網絡的容器解決方案,感興趣的讀者可以自行去Github上搜尋。

下面我們将舉幾個CNI網絡插件的例子。

上圖是一個host-local + bridge插件組合的例子,在這麼一個JSON檔案中,我們定義了一個名為mynet的網絡,是一個bridge模型,而IP位址管理(ipam)使用的是host-local(在本地用一個檔案記錄已經配置設定的容器IP位址)且可供配置設定的容器網段是10.10.0.0/16。至于Kubernetes如何使用它們?Kubelet和CNI約好了兩個預設的檔案系統路徑,分别是/etc/cni/net.d用來存儲CNI配置檔案和/opt/cni/bin目錄用來存放CNI插件的二進制檔案,在我們這個例子中,至少要提前放好bridge和host-local這兩個插件的二進制,以及10-mynet.conf配置檔案(叫什麼名字随意,Kubelet隻解析*.conf檔案)。由于主流的網絡插件都內建了bridge插件并提供了各自的ipam功能,是以在實際Kubernetes使用過程中我們并不需要操心上面過程,也無需做額外配置。

再來看一個最近Kubernetes V1.11版本合到社群主幹的帶寬控制插件的使用方法。當我們書寫了以下Pod配置時:

Kubernetes就會自動為我們這個Pod分别限制上傳和下載下傳的帶寬為最高10Mb/s。注意,由于這個特性較新,我們需要自己在/etc/cni/net.d目錄下寫一個配置檔案,例如my-net.conf:

{

"type": "bandwidth",
"capabilities": {"bandwidth": true}

} 
      

這個配置檔案會告訴Kubelet去調用CNI的預設bandwidth插件,然後根據Pod annotation裡面關于帶寬的ingress/egress值進行容器上行/下行帶寬的限制。當然,CNI插件最後調用的還是Linux tc工具。

Kubernetes Service機制

容器網絡模型講完後,我們再看下Kubernetes叢集内通路的Service機制。先從一個簡單的例子講起,用戶端通路容器應用,最簡單的方式莫過于直接容器IP+端口了。

但,簡單的生活總是暫時的。

當有多個後端執行個體,如何做到負載均衡?如何保持會話親和性?容器遷移,IP發生變化如何通路?健康檢查怎麼做?怎麼通過域名通路?

Kubernetes提供的解決方案是在用戶端和後端Pod之間引入一個抽象層:Service。什麼是Kubernetes的Service呢?

Kubernetes的Service有時候也稱為Kubernetes的微服務,代表的是Kubernetes後端服務的入口,它注意包含服務的通路IP(虛IP)和端口,是以工作在L4。既然Service隻存儲服務入口資訊,那如何關聯後端Pod呢?Service通過Label Selector選擇與之比對的Pod。那麼被Service選中的Pod,當它們Running且Ready後,Kubernetes的Endpoints Controller會生成一個新的Endpoints對象,記錄Pod的IP和端口,這就解決了前文提到的後端執行個體健康檢查問題。另外,Service的通路IP和Endpoint/Pod IP都會在Kubernetes的DNS伺服器裡存儲域名和IP的映射關系,是以使用者可以在叢集内通過域名的方式通路Service和Pod。

Kubernetes Service的定義如下所示:

其中,spec.ClusterIP就是Service的通路IP,俗稱虛IP,spec.ports[].port是Service的通路端口,而與之對應的spec.ports[].targetPort是後端Pod的端口,Kubernetes内部會自動做一次映射。

Kubernetes Endpoints的定義如下所示:

其中,subsets[].addresses[].ip是後端Pod的IP,subsets[].ports是後端Pod的端口,與Service的targetPort對應。

下面我們來看下Kubernetes Service的工作原理。

如上圖所示,當使用者建立Service和對應後端Pod時,Endpoints Controller會觀察Pod的狀态變化,當Pod處于Running且Ready狀态時,Endpoints Controller會生成Endpoints對象。運作在每個節點上的Kube-proxy會觀察Service和Endpoints的更新,并調用其load balancer在主機上子產品重新整理轉發規則。目前主流的load balancer實作有iptables和IPVS,iptables因為擴充性和性能不好,越來越多的廠商正開始使用IPVS模式。

Kubernetes Service有這麼幾種類型:ClusterIP,NodePort和Load Balancer。其中,ClusterIP是預設類型,自動配置設定叢集内部可以通路的虛IP——Cluster IP。NodePort為Service在Kubernetes叢集的每個Node上配置設定一個端口,即NodePort,叢集内/外部可基于任何一個NodeIP:NodePort的形式來通路Service。是以NodePort也成為“乞丐版”的Load Balancer,對于那些沒有打通容器網絡和主機網絡的使用者,NodePort成了他們從外部通路Service的首選。LoadBalancer類型的Service需要Cloud Provider的支援,因為Service Controller會自動為之建立一個外部LB并配置安全組,Kubernetes原生支援的Cloud Provider就那麼幾個:GCE,AWS。除了“外用”,Load Balancer還可以“内服”,即如果要在叢集内通路Load Balancer類型的Service,kube-proxy用iptables或ipvs實作了雲服務提供商LB(一般都是L7的)的部分功能:L4轉發,安全組規則等。

Kubernetes Service建立好了,那麼如何使用,即如何進行服務發現呢?Kubernetes提供了兩種方式:環境變量和域名。

環境變量即Kubelet為每個Pod注入所有Service的環境變量資訊,形如:

這種方式的缺點是:容易環境變量洪泛,Docker啟動參數過長影響性能甚至直接導緻容器啟動失敗。

域名的方式是,假設Service(my-svc)在namespace(my-ns)中,暴露名為http的TCP端口,那麼在Kubernetes的DNS伺服器會生成兩種記錄,分别是A記錄:域名(my-svc.my-ns)到Cluster IP的映射和SRV記錄,例如:_http._tcp.my-svc.my-ns到一個http端口号的映射。我們會在下文Kube-dns一節做更詳細的介紹。

前文提到,Service的load balancer子產品有iptables和IPVS實作。下面會一一進行分析。

Iptables是使用者空間應用程式,通過配置Netfilter規則表( Xtables )來建構linux核心防火牆。下面就是Kubernetes利用iptables的DNAT子產品,實作了Service入口位址(10.20.30.40:80)到Pod實際位址(172.17.0.2:8080)的轉換。

IPVS是LVS的負載均衡子產品,亦基于netfilter,但比iptables性能更高,具備更好的可擴充性。

如上所示,一旦建立一個Service和Endpoints,Kube-proxy的IPVS模式會做三樣事情:

  1. 確定一塊dummy網卡(kube-ipvs0)存在。至于為什麼要建立dummy網卡,因為IPVS的netfilter鈎子挂載INPUT chain,我們需要把Service的通路IP綁定在dummy網卡上讓核心“覺得”虛IP就是本機IP,進而進入到INPUT chain。
  2. 把Service的通路IP綁定在dummy網卡上。
  3. 通過socket調用,建立IPVS的virtual server和real server,分别對應Kubernetes的Service和Endpoints。

好了,都說IPVS性能要好于iptables,無圖無真相,上實測資料!

通過上圖我們可以發現,IPVS重新整理規則的時延明顯要低iptables幾個數量級。

從上圖我們又可以發現,IPVS相較于iptables,端到端的吞吐率和平均時延均由不小的優化。注意,這是端到端的資料,包含了底層容器網絡的RTT,還能有30%左右的性能提升。

上圖是iptables和IPVS在資源消耗方面的對比,孰優孰劣,不言而喻。

最後,問個開放性的問題。如何從叢集外通路Kubernetes Service?

前文已經提到,可以使用NodePort類型的Service,但這種“屌絲”的做法除了要求叢集内Node有對外通路IP外,還有一些已知的性能問題(具體請參考本公衆号另外一篇幹貨文章《

記一次Docker/Kubernetes上無法解釋的逾時原因探尋之旅

》)。使用LoadBalancer類型的Service?它又要求在特定的雲服務上跑Kubernetes。而且Service隻提供L4負載均衡功能,而沒有L7功能,一些進階的,L7的轉發功能,比如:基于HTTP header,cookie,URL的轉發就做不了。

在Kubernetes中,L7的轉發功能,叢集外通路Service,這些功能是專門交給Ingress的。

Kubernetes Ingress

何謂Ingress?從字面意思解讀,就是“入站流量”。Kubernetes的Ingress資源對象是指授權入站連接配接到達叢集内服務的規則集合。具體含義看下面這個例子便一目了然:

通常情況下,Service和Pod僅可在叢集内部網絡中通過IP位址通路。所有到達邊界路由的流量或被丢棄或被轉發到其他地方。Ingress就是在邊界路由處開個口子,放你進來。是以,Ingress是建立在Service之上的L7通路入口,它支援通過URL的方式将Service暴露到Kubernetes叢集外;支援自定義Service的通路政策;提供按域名通路的虛拟主機功能;支援TLS通信。

在上面這個例子,Ingress就可以基于用戶端請求的URL來做流量分發,轉發給不同的Service後端。

我們來看下Ingress資源對象的API定義:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
tls:
- secretName: testsecret
backend:
serviceName: testsvc
servicePort: 80
      

把上面這個Ingress對象建立起來後,kubectl get一把,會看到:

其中,ADDRESS即Ingress的通路入口位址,由Ingress Controller配置設定,一般是Ingress的底層實作LB的IP位址,例如:Ingress,GCE LB,F5等;BACKEND是Ingress對接的後端Kubernetes Service IP + Port;RULE是自定義的通路政策,主要是基于URL的轉發政策,若為空,則通路ADDRESS的所有流量都轉發給BACKEND。

下面給出一個Ingress的rules不為空的例子。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
spec:
rules:
- host: foo.bar.com
http:
 paths:
 - path: /foo
 backend:
 serviceName: s1
 servicePort: 80
 - path: /bar
 backend:
 serviceName: s2
 servicePort: 80
      

這個例子和上面那個最明顯的差別在于,rules定義了path分别為/foo和/bar的分發規則,分别轉發給s1:80和s2:80。Kubectl get一把一目了然:

需要注意的是,當底層LB準備就緒時,Ingress Controller把LB的IP填充到ADDRESS字段。而在我們的例子中,這個LB顯然還未ready。

Ingress是一個非常“極客”和需要DIY的産物,Kubernetes隻負責提供一個API定義,具體的Ingress Controller需要使用者自己實作!官方倒是提供了Nginx和GCE的Ingress Controller示例供開發者參考。實作一個Ingress Controller的大緻架構無非是,List/Watch Kubernetes的Service,Endpoints,Ingress對象,重新整理外部LB的規則和配置。

這還不算,如果想要通過域名通路Ingress?需要使用者自己配置域名和Ingress IP的映射關系,比如:host檔案,自己的DNS(不是kube-dns)。下文會講到,“高冷”的kube-dns隻會負責叢集内的域名解析,叢集外的一概不管。

Kubernetes DNS

Kubernetes DNS說,剛剛誰念叨起本宮了?

一言以蔽之,Kubernetes的DNS,就是用來解析Kubernetes叢集内的Pod和Service域名的,而且一般是供Pod内的程序使用的!血統高貴,一般不給外人使用。那可能會有人好奇問一句,Pod到底怎麼使用Kubernetes DNS呢?原來,kubelet配置--cluster-dns把DNS的靜态IP傳遞給每個容器。Kubernetes DNS一般通過插件方式部署到Kubernetes上,并為之綁定一個Service,而Service的Cluster IP往往是固定的。Kubernetes DNS目前有兩個實作,分别是kube-dns和CoreDNS。

對于Service,Kubernetes DNS伺服器會生成兩類DNS記錄,分别是:A記錄和SRV記錄。而A記錄又對普通Service和headless Service有所差別。普通Service的A記錄是:

{service name}.{service namespace}.svc.cluster.local -> Cluster IP

的映射關系。後面域名後面一串子域名:svc.cluster.local是Kubelet通過--cluster-domain配置的僞域名。

Headless Service的A記錄是:

{service name}.{service namespace}.svc.cluster.local -> 後端Pod IP清單

的映射關系。

至于SRV記錄,則是按照一個約定俗稱的規定:

_{port name}._{port protocol}.{service name}.{service namespace}.svc.cluster.local –> Service Port
      

實作了對服務端口的查詢。

對于Pod,A記錄是:

{pod-ip}.{pod namespace}.pod.cluster.local -> Pod IP
      

如果Pod IP是1.2.3.4,上面的{pod-ip}即1-2-3-4。Pod的A記錄其實沒什麼用,因為如果都知道Pod IP了,還用查DNS嗎?

如果在Pod Spec指定hostname和subdomain,那麼Kubernetes DNS會額外生成Pod的A記錄就是:

{hostname}.{subdomain}.{pod namespace}.pod.cluster.local –> Pod IP 
      

同樣,後面那一串子域名pod.cluster.local是kubelet配置的僞域名。

讓我們看下kube-dns的架構吧。

如上圖所示,kube-dns是“三程序”架構。

  • kubedns:List/Watch Kubernetes Service和Endpoints變化。接入SkyDNS,在記憶體中維護DNS記錄,是dnsmasq的上遊。
  • dnsmasq:DNS配置工具,監聽53端口,為叢集提供DNS查詢服務。提供DNS緩存,降低kubedns壓力。
  • exechealthz:健康檢查,檢查kube-dns和dnsmasq的健康。

需要注意的是,dnsmasq是個C++寫的一個小程式,有記憶體洩露的“老毛病”。

雖然kube-dns血統純正,而且早早地進入到Kubernetes的“後宮”,也早有“名分”,但近來CoreDNS卻獨得Kubernetes SIG Network的聖寵。CoreDNS是個DNS伺服器,原生支援Kubernetes,而且居然還是一個CNCF的項目!

與kube-dns的三程序架構不同,CoreDNS就一個程序,運維起來更加簡單。而且采用Go語言編寫,記憶體安全,高性能。值得稱道的是,CoreDNS采用的是“插件鍊”架構,每個插件挂載一個DNS功能,保證了功能的靈活、易擴充。盡管資曆不深,但卻“集萬千寵愛于一身”,自然是有兩把刷子的。

值得一提的是,以上性能測試資料是不帶cache情況下取得的,明顯要高于kube-dns。那麼為什麼建議使用CoreDNS呢?Kubernetes官方已經将CoreDNS扶正,成為了預設模式。除了性能好以外,還有什麼其他優勢嗎?CoreDNS修複了kube-dns的一些“令人讨厭”的“老生常談”的問題:

  • dns#55 - Allow custom DNS entries for kube-dns
  • dns#116 - Missing ‘A’ records for headless service with pods sharing hostname
  • dns#131 - ExternalName not using stubDomains settings
  • dns#167 - Enable round robin A/AAAA records
  • dns#190 - kube-dns cannot run as non-root user
  • dns#232 - Use pod’s name instead of pod’s hostname in DNS SRV records

同時,還有一些吸引人的特性:

  • Zone transfers - list all records, or copy records to another server
  • Namespace and label filtering - expose a limited set of services
  • Adjustable TTL - adjust up/down default service record TTL
  • Negative Caching - By default caches negative responses (e.g. NXDOMAIN)

其中,原生支援基于namespace隔離和過濾Service和Pod的DNS記錄這一條特性,在多租戶場景下格外有用。

Network Policy

Kubernetes預設情況下,底層網絡是“全連通”的。但如果我們需要實作以下願景:

即,隻允許通路default namespace的Label是app=web的Pod,default namespace的其他Pod都不允許外面通路。這個隔離需求在多租戶的場景下十分普遍。Kubernetes的解決方案是Network Policy。

Network Policy說白了就是基于Pod源IP(是以Kubernetes網絡不能随随便便做SNAT啊!)的通路控制清單,限制Pod的進/出流量,用白名單實作了一個通路控制清單(ACL)。Network Policy作為Pod網絡隔離的一層抽象,允許使用Label Selector,namespace selector,端口,CIDR這四個次元限制Pod的流量進出。和Ingress一副德行的是,Kubernetes對Netowrk Policy還是隻提供了API定義,不負責實作!

一般情況下,Policy Controller是由網絡插件提供的。支援Network Policy的網絡插件有Calico,Cilium,Weave Net,Kube-router,Romana。需要注意的是,flannel不在這個名單之列,似乎又找到了一個不用flannel的理由?

讓我們先來見識幾個預設網絡政策:

注:{}代表允許所有,[]代表拒絕所有。

如果要拒絕所有流量進入呢?比如,場景長這樣:

那麼Network Policy對象應該定義成:

如果要限制部分流量進入呢?比如,場景長這樣:

如果隻允許特定namespace的Pod流量進入呢?比如,場景長這樣:

如果限制流量從指定端口進入呢?比如,場景長這樣:

那麼,Network Policy對象應該定義成:

未來工作

最後,暢想下Kubernetes網絡後面的發展趨勢。

首先,kubenet會被廢棄。Kubenet本來就是一個特定時期的産物,那時候CNI尚未成熟,讓Kubernetes親自去幹底層網絡這種“苦差事”,盡管Kubernetes是有一萬個不願意,但如果完全沒有網絡連通方案,又會讓使用者诟病“過于高冷”,“易用性差”,甚至會讓那時的競争對手docker swarm有機可圖。是以Kubernetes寫了一個簡單的網絡插件,即kubenet,一個bridge模型的容器連通性解決方案。但随着CNI強勢崛起,以及kubenet并不支援網絡政策等硬傷,社群已經沒了繼續維護kubenet的熱情,是以廢棄kubenet也就被提上了議程。

IPv4/IPv6雙棧支援。經過大半年社群開發者的齊心協力,Kubernetes總算支援了IPv6。但目前的支援比較初級,IPv6還不能和IPv4混用。IPv4/IPv6的雙棧支援,勢在必行。

Pod Ready++。Pod有Ready和非Ready狀态之分,為何還要搞出個Ready++這種“量子化”的模糊界限呢?原因在于,一個Pod能否真的對外提供服務,除了依賴容器内程序ready(我們會放置探針,檢查程序狀态)這類内部條件外,還依賴諸如:Ingress,Service,網絡政策,外部LB等一系列外部因素。Pod Ready++的提出,就是為了将外部因素一齊納入Pod狀态的考量。

多網絡。也許是Kubernetes的“單Pod單IP”的網絡模型過于深入人心了,以至于在實作過程中都謹遵這一“金科玉律”。但我們知道,網絡的世界紛繁複雜,一塊網卡怎麼可能cover所有場景呢?據最簡單的例子,一般我們會為一個IO密集型的作業配兩塊網絡,一塊網卡作為資料信道,另一塊網卡則作為控制信道。從單網絡到多網絡的遷移,道路并不平坦,甚至是處處荊棘和沼澤,且不說網絡插件,Service,DNS,Ingress等實作要大改,光API相容性就讓你頭疼。好消息是經過整整兩年的拉鋸,社群Network Plumbing WG終于取得了階段性成果,如不出意外的話,應該是CRD + 多網路插件的形式支援Kubernetes的多網絡,保持Kubernetes原生API的穩定。支援多網絡的CNI插件有幾個,但真真落到生産的沒幾個,CNI-genie是其中一個有衆多粉絲基礎和經過生産環境檢驗的Kubernetes多網絡插件,了解一下?

最後,談下Service Mesh。嚴格說來,Service Mesh并不在Kubernetes核心的範圍之内。但是,在Kubernetes的幫助下,應用上雲後,還面臨着服務治理的難題。現在大多數雲原生的應用都是微服務架構,微服務的注冊,服務之間的互相調用關系,服務異常後的熔斷、降級,調用鍊的跟蹤、分析等待一系列現實問題擺在各機構面前。Service Mesh(服務網絡)就是解決這類微服務發現和治理問題的一個概念。在我看來,Service Mesh之于微服務架構就像TCP協定之于web應用。我們大部分人寫Web應用,關心的是RESTful,HTTP等上層協定,很少需要我們自己操心網絡封包逾時重傳、分割組裝、内容校驗等底層細節。正是因為有了Service Mesh,企業在雲原生和微服務架構的實踐道路上隻需根據自己業務做适當的微服務拆分即可,無需過多關注底層服務發現和治理的複雜度。而Istio的出現,使得有些“學院派”的Service Mesh概念真正得到了落地,并且提供了真正可供操作、非侵入式的方案,讓諸如Spring Cloud,Dubbo這些“老古董”第一次有了被淘汰的危機感。

本文轉自DockOne-

Kubernetes網絡一年發展動态與未來趨勢

繼續閱讀