天天看點

DockOne微信分享(一二二):探索Kubernetes的網絡原理及方案

本文講的是<b>DockOne微信分享(一二二):探索Kubernetes的網絡原理及方案</b>【編者的話】2016年ClusterHQ容器技術應用調查報告顯示,一年來容器技術應用于生産的比例增長了96%,Kubernetes的使用率達到了40%,成為了最受歡迎的容器編排工具;那麼Kubernetes到底是什麼呢?它是一個用于容器叢集的自動化部署、擴容以及運維的開源平台;那麼通過Kubernetes能幹什麼呢?它能快速而有預期地部署你的應用,極速地擴充你的應用,無縫對接新的應用功能,節省資源,優化硬體資源的使用。随着Kubernetes王者時代的到來,計算、網絡、存儲、安全是Kubernetes繞不開的話題,本次交流與大家分享下Kubernetes網絡原理及方案。

<a href="http://dockone.io/article/2376">【3 天燒腦式 Docker 訓練營 | 上海站】随着Docker技術被越來越多的人所認可,其應用的範圍也越來越廣泛。本次教育訓練我們理論結合實踐,從Docker應該場景、持續部署與傳遞、如何提升測試效率、存儲、網絡、監控、安全等角度進行。</a>

在Kubernetes網絡中存在兩種IP(Pod IP和Service Cluster IP),Pod IP 位址是實際存在于某個網卡(可以是虛拟裝置)上的,Service Cluster IP它是一個虛拟IP,是由kube-proxy使用Iptables規則重新定向到其本地端口,再均衡到後端Pod的。下面講講Kubernetes Pod網絡設計模型:

每個Pod都擁有一個獨立的IP位址(IPper Pod),而且假定所有的Pod都在一個可以直接連通的、扁平的網絡空間中。

使用者不需要額外考慮如何建立Pod之間的連接配接,也不需要考慮将容器端口映射到主機端口等問題。

所有的容器都可以在不用NAT的方式下同别的容器通訊;所有節點都可在不用NAT的方式下同所有容器通訊;容器的位址和别人看到的位址是同一個位址。

網絡的命名空間:Linux在網絡棧中引入網絡命名空間,将獨立的網絡協定棧隔離到不同的指令空間中,彼此間無法通信;Docker利用這一特性,實作不同容器間的網絡隔離。

Veth裝置對:Veth裝置對的引入是為了實作在不同網絡命名空間的通信。

Iptables/Netfilter:Netfilter負責在核心中執行各種挂接的規則(過濾、修改、丢棄等),運作在核心模式中;Iptables模式是在使用者模式下運作的程序,負責協助維護核心中Netfilter的各種規則表;通過二者的配合來實作整個Linux網絡協定棧中靈活的資料包處理機制。

網橋:網橋是一個二層網絡裝置,通過網橋可以将Linux支援的不同的端口連接配接起來,并實作類似交換機那樣的多對多的通信。

路由:Linux系統包含一個完整的路由功能,當IP層在處理資料發送或轉發的時候,會使用路由表來決定發往哪裡。

下圖展示了Docker網絡在整個Docker生态技術棧中的位置:

<a href="http://dockerone.com/uploads/article/20170602/3177d13c624766fb083364c8ba346290.png" target="_blank"></a>

單機網絡模式:Bridge 、Host、Container、None,這裡具體就不贅述了。

多機網絡模式:一類是Docker在1.9版本中引入Libnetwork項目,對跨節點網絡的原生支援;一類是通過插件(plugin)方式引入的第三方實作方案,比如 Flannel,Calico 等等。

同一個Pod的容器共享同一個網絡命名空間,它們之間的通路可以用localhost位址 + 容器端口就可以通路。

<a href="http://dockerone.com/uploads/article/20170602/1cc09776d4763ac110d05bc020891397.png" target="_blank"></a>

同一Node中Pod的預設路由都是docker0的位址,由于它們關聯在同一個docker0網橋上,位址網段相同,所有它們之間應當是能直接通信的。

<a href="http://dockerone.com/uploads/article/20170602/4948427648dcf8e5cca4e01007669de1.png" target="_blank"></a>

不同Node中Pod間通信要滿足2個條件: Pod的IP不能沖突; 将Pod的IP和所在的Node的IP關聯起來,通過這個關聯讓Pod可以互相通路。

<a href="http://dockerone.com/uploads/article/20170602/91d104d73c960651e2133569afc7abfc.png" target="_blank"></a>

Service是一組Pod的服務抽象,相當于一組Pod的LB,負責将請求分發給對應的Pod;Service會為這個LB提供一個IP,一般稱為ClusterIP。

<a href="http://dockerone.com/uploads/article/20170602/25146c13d30b8297651bd1a0e3d2d830.png" target="_blank"></a>

<a href="http://dockerone.com/uploads/article/20170602/c812c265ab2f0c7db75dacbccd04ee62.png" target="_blank"></a>

<a href="http://dockerone.com/uploads/article/20170602/569f79face8e975593859a5f56c30389.png" target="_blank"></a>

<a href="http://dockerone.com/uploads/article/20170602/c236daf6dfd029a1048c9382416dcc1a.png" target="_blank"></a>

Kube-proxy是一個簡單的網絡代理和負載均衡器,它的作用主要是負責Service的實作,具體來說,就是實作了内部從Pod到Service和外部的從NodePort向Service的通路。

實作方式:

User space是在使用者空間,通過kuber-proxy實作LB的代理服務,這個是kube-proxy的最初的版本,較為穩定,但是效率也自然不太高。

Iptables是純采用Iptables來實作LB,是目前kube-proxy預設的方式。

下面是Iptables模式下kube-proxy的實作方式:

<a href="http://dockerone.com/uploads/article/20170602/3f6fcc547129d28e8034530ce1cfc092.png" target="_blank"></a>

在這種模式下,kube-proxy監視Kubernetes主伺服器添加和删除服務和端點對象。對于每個服務,它安裝iptables規則,捕獲到服務的clusterIP(虛拟)和端口的流量,并将流量重定向到服務的後端集合之一。對于每個Endpoints對象,它安裝選擇後端Pod的iptables規則。

預設情況下,後端的選擇是随機的。可以通過将service.spec.sessionAffinity設定為“ClientIP”(預設為“無”)來選擇基于用戶端IP的會話關聯。

與使用者空間代理一樣,最終結果是綁定到服務的IP:端口的任何流量被代理到适當的後端,而用戶端不知道關于Kubernetes或服務或Pod的任何資訊。這應該比使用者空間代理更快,更可靠。然而,與使用者空間代理不同,如果最初選擇的Pod不響應,則Iptables代理不能自動重試另一個Pod,是以它取決于具有工作準備就緒探測。

Kube-dns用來為Kubernetes Service配置設定子域名,在叢集中可以通過名稱通路Service;通常kube-dns會為Service賦予一個名為“service名稱.namespace.svc.cluster.local”的A記錄,用來解析Service的ClusterIP。

Kube-dns元件:

在Kubernetes v1.4版本之前由“Kube2sky、Etcd、Skydns、Exechealthz”四個元件組成。

在Kubernetes v1.4版本及之後由“Kubedns、Dnsmasq、exechealthz”三個元件組成。

<a href="http://dockerone.com/uploads/article/20170602/35cc6933f09fdd6cbcb738e4d8d6c99e.png" target="_blank"></a>

KubeDNS

接入SkyDNS,為dnsmasq提供查詢服務。

替換etcd容器,使用樹形結構在記憶體中儲存DNS記錄。

通過Kubernetes API監視Service資源變化并更新DNS記錄。

服務10053端口。

Dnsmasq

Dnsmasq是一款小巧的DNS配置工具。

在kube-dns插件中的作用是:

通過kubedns容器擷取DNS規則,在叢集中提供DNS查詢服務

提供DNS緩存,提高查詢性能

降低kubedns容器的壓力、提高穩定性

Dockerfile在GitHub上Kubernetes組織的contrib倉庫中,位于dnsmasq目錄下。

在kube-dns插件的編排檔案中可以看到,dnsmasq通過參數--server=127.0.0.1:10053指定upstream為kubedns。

Exechealthz

在kube-dns插件中提供健康檢查功能。

源碼同樣在contrib倉庫中,位于exec-healthz目錄下。

新版中會對兩個容器都進行健康檢查,更加完善。

IPAM:IP位址管理;這個IP位址管理并不是容器所特有的,傳統的網絡比如說DHCP其實也是一種IPAM,到了容器時代我們談IPAM,主流的兩種方法: 基于CIDR的IP位址段配置設定地或者精确為每一個容器配置設定IP。但總之一旦形成一個容器主機叢集之後,上面的容器都要給它配置設定一個全局唯一的IP位址,這就涉及到IPAM的話題。

Overlay:在現有二層或三層網絡之上再建構起來一個獨立的網絡,這個網絡通常會有自己獨立的IP位址空間、交換或者路由的實作。

IPSesc:一個點對點的一個加密通信協定,一般會用到Overlay網絡的資料通道裡。

VXLAN:由VMware、Cisco、RedHat等聯合提出的這麼一個解決方案,這個解決方案最主要是解決VLAN支援虛拟網絡數量(4096)過少的問題。因為在公有雲上每一個租戶都有不同的VPC,4096明顯不夠用。就有了vxLAN,它可以支援1600萬個虛拟網絡,基本上公有雲是夠用的。

網橋Bridge:連接配接兩個對等網絡之間的網絡裝置,但在今天的語境裡指的是Linux Bridge,就是大名鼎鼎的Docker0這個網橋。

BGP:主幹網自治網絡的路由協定,今天有了網際網路,網際網路由很多小的自治網絡構成的,自治網絡之間的三層路由是由BGP實作的。

SDN、Openflow:軟體定義網絡裡面的一個術語,比如說我們經常聽到的流表、控制平面,或者轉發平面都是Openflow裡的術語。

隧道方案( Overlay Networking )

隧道方案在IaaS層的網絡中應用也比較多,大家共識是随着節點規模的增長複雜度會提升,而且出了網絡問題跟蹤起來比較麻煩,大規模叢集情況下這是需要考慮的一個點。

Weave:UDP廣播,本機建立新的BR,通過PCAP互通

Open vSwitch(OVS):基于VXLAN和GRE協定,但是性能方面損失比較嚴重

Flannel:UDP廣播,VxLan

Racher:IPsec

路由方案

路由方案一般是從3層或者2層實作隔離和跨主機容器互通的,出了問題也很容易排查。

Calico:基于BGP協定的路由方案,支援很細緻的ACL控制,對混合雲親和度比較高。

Macvlan:從邏輯和Kernel層來看隔離性和性能最優的方案,基于二層隔離,是以需要二層路由器支援,大多數雲服務商不支援,是以混合雲上比較難以實作。

容器網絡發展到現在,形成了兩大陣營,就是Docker的CNM和Google、CoreOS、Kuberenetes主導的CNI。首先明确一點,CNM和CNI并不是網絡實作,他們是網絡規範和網絡體系,從研發的角度他們就是一堆接口,你底層是用Flannel也好、用Calico也好,他們并不關心,CNM和CNI關心的是網絡管理的問題。

CNM(Docker LibnetworkContainer Network Model)

Docker Libnetwork的優勢就是原生,而且和Docker容器生命周期結合緊密;缺點也可以了解為是原生,被Docker“綁架”。

Docker Swarm overlay

Macvlan &amp; IP networkdrivers

Calico

Contiv

Weave

CNI(Container NetworkInterface)

CNI的優勢是相容其他容器技術(e.g. rkt)及上層編排系統(Kubernetes &amp; Mesos),而且社群活躍勢頭迅猛,Kubernetes加上CoreOS主推;缺點是非Docker原生。

Kubernetes

Macvlan

Flannel

Mesos CNI

Flannel之是以可以搭建kubernets依賴的底層網絡,是因為它可以實作以下兩點:

它給每個node上的docker容器配置設定互相不想沖突的IP位址;

它能給這些IP位址之間建立一個覆寫網絡,同過覆寫網絡,将資料包原封不動的傳遞到目标容器内。

Flannel介紹

Flannel是CoreOS團隊針對Kubernetes設計的一個網絡規劃服務,簡單來說,它的功能是讓叢集中的不同節點主機建立的Docker容器都具有全叢集唯一的虛拟IP位址。

在預設的Docker配置中,每個節點上的Docker服務會分别負責所在節點容器的IP配置設定。這樣導緻的一個問題是,不同節點上容器可能獲得相同的内外IP位址。并使這些容器之間能夠之間通過IP位址互相找到,也就是互相ping通。

Flannel的設計目的就是為叢集中的所有節點重新規劃IP位址的使用規則,進而使得不同節點上的容器能夠獲得“同屬一個内網”且”不重複的”IP位址,并讓屬于不同節點上的容器能夠直接通過内網IP通信。

Flannel實質上是一種“覆寫網絡(overlaynetwork)”,也就是将TCP資料包裝在另一種網絡包裡面進行路由轉發和通信,目前已經支援UDP、VXLAN、host-gw、aws-vpc、GCE和Alloc路由等資料轉發方式,預設的節點間資料通信方式是UDP轉發。

<a href="http://dockerone.com/uploads/article/20170602/9e2eb815c6c1c705cf70e272d02be270.png" target="_blank"></a>

Calico介紹

Calico是一個純3層的資料中心網絡方案,而且無縫內建像OpenStack這種IaaS雲架構,能夠提供可控的VM、容器、裸機之間的IP通信。Calico不使用重疊網絡比如Flannel和Libnetwork重疊網絡驅動,它是一個純三層的方法,使用虛拟路由代替虛拟交換,每一台虛拟路由通過BGP協定傳播可達資訊(路由)到剩餘資料中心。

Calico在每一個計算節點利用Linux Kernel實作了一個高效的vRouter來負責資料轉發,而每個vRouter通過BGP協定負責把自己上運作的workload的路由資訊像整個Calico網絡内傳播——小規模部署可以直接互聯,大規模下可通過指定的BGP route reflector來完成。

Calico節點組網可以直接利用資料中心的網絡結構(無論是L2或者L3),不需要額外的NAT,隧道或者Overlay Network。

Calico基于iptables還提供了豐富而靈活的網絡Policy,保證通過各個節點上的ACLs來提供Workload的多租戶隔離、安全組以及其他可達性限制等功能。

Calico架構圖:

<a href="http://dockerone.com/uploads/article/20170602/e273517b3ba658a78c4cfb3b2e152090.png" target="_blank"></a>

<a href="http://dockerone.com/uploads/article/20170602/0ba794cf296220e086df037e7f24c4f3.png" target="_blank"></a>

性能對比分析:

<a href="http://dockerone.com/uploads/article/20170602/73e1025d22145583b113e7165fbda164.png" target="_blank"></a>

性能對比總結:

CalicoBGP方案最好,不能用BGP也可以考慮Calico ipip tunnel方案;如果是CoreOS系又能開UDP Offload,Flannel是不錯的選擇;Docker原生Overlay還有很多需要改進的地方。

<a href="http://dockerone.com/uploads/article/20170602/e16554a12547624a43b0c7b1b8697448.png" target="_blank"></a>

Q:A的Pod如何連接配接B的Pod? kube-dns起到什麼作用? kube-dns如果調用kube-proxy?

A:這裡說的A和B應當是指Service,A Service中Pod與B Service Pod之間的通信,可以在其容器的環境變量中定義Service IP或是Service Name來實作;由于Service IP提前不知道,使用引入kube-dns做服務發現,它的作用就是監聽Service變化并更新DNS,即Pod通過服務名稱可以查詢DNS;kube-proxy是一個簡單的網絡代理和負載均衡器,它的作用主要是負責service的實作,具體來說,就是實作了内部從Pod到Service和外部的從NodePort向Service的通路,可以說kube-dns和kube-proxy都是為Service服務的。

Q:網絡問題docker default是網橋模式(NAT) 如果用路由的模式,是以Pod的網關都會是docker 0 IP ? 那Pod 1與Pod 2之間也走路由 ,這會使路由表很大? Flannel 網絡是不是可以把所有的Node上,相當于一個分布式交換機?

A:Docker實作跨主機通信可以通過橋接和路由的方式,橋接的方式是将docker0橋接在主機的網卡上,而路由直接通過主機網口轉發出去;Kubernetes網絡有Pod和Server,Pod網絡實作的方式很多,可以參考CNI網絡模型,Flannel實質上是一種“覆寫網絡(Overlay Network)”,也就是将TCP資料包裝在另一種網絡包裡面進行路由轉發和通信。

Q:大規模容器叢集如何保證安全? 主要從幾個方面考慮?

A:一個大規模容器叢集從安全性考慮來講,可以分為幾個方面:1、叢集安全,包括叢集高可用;2、通路安全,包括認證、授權、通路控制等;3、資源隔離,包括多租戶等;4、網絡安全,包括網絡隔離、流量控制等;5、鏡像安全,包括容器漏洞等;6、容器安全,包括端口暴露、privileged權限等。

Q:SVC如何進行用戶端分流,A網段的通路Pod1 ,B網段的通路Pod2,C網段的通路Pod3,3個Pod都在SVC的Endpoint中?

A:内部從Pod到Service的實作是由kube-proxy(簡單的網絡代理和負載均衡器)來完成,kube-proxy預設采用輪詢方法進行配置設定,也可以通過将service.spec.sessionAffinity設定為“ClientIP”(預設為“無”)來選擇基于用戶端IP的會話關聯,目前還不能進行網段的指定。

Q:對于Ingress+HAProxy這種實作Service負載均衡的方式,Ingress controller輪詢Service後面的Pods狀态,并重新生成HAProxy配置檔案,然後重新開機HAProxy,進而達到服務發現的目的。這種原理對于HAProxy來講是不是服務會暫時間斷。有沒有好的替代方案?之前看到Golang實作的Træfik,可無縫對接Kubernetes,同時不需要Ingress了。方案可行麼?

A:由于微服務架構以及Docker技術和Kubernetes編排工具最近幾年才開始逐漸流行,是以一開始的反向代理伺服器比如Nginx/HAProxy并未提供其支援,畢竟他們也不是先知,是以才會出現IngressController這種東西來做Kubernetes和前端負載均衡器如Nginx/HAProxy之間做銜接,即Ingress Controller的存在就是為了能跟Kubernetes互動,又能寫 Nginx/HAProxy配置,還能 reload 它,這是一種折中方案;而最近開始出現的Traefik天生就是提供了對Kubernetes的支援,也就是說Traefik本身就能跟Kubernetes API互動,感覺後端變化,是以在使用Traefik時就不需要Ingress Controller,此方案當然可行。

Q:1、一個POD裡面的多個Container是同一個Service的?還是由不同的Service的組成? 是啥樣的配置設定邏輯? 2、Flannel 是實作多個主控端上的N多的Service以及Pod裡面的各個Container的IP的唯一性麼? 3、Kubernetes具備負載均衡的效果 。那是否就不用在考慮Nigix?

A:Pod是Kubernetes的基本操作單元,Pod包含一個或者多個相關的容器,Pod可以認為是容器的一種延伸擴充,一個Pod也是一個隔離體,而Pod内部包含的一組容器又是共享的(包括PID、Network、IPC、UTS);Service是Pod的路由代理抽象,能解決Pod之間的服務發現問題;Flannel的設計目的就是為叢集中的所有節點重新規劃IP位址的使用規則,進而使得不同節點上的容器能夠獲得“同屬一個内網”且”不重複的”IP位址,并讓屬于不同節點上的容器能夠直接通過内網IP通信;Kubernetes kube-proxy實作的是内部L4層輪詢機制的負載均衡,要支援L4、L7負載均衡,Kubernetes也提供了Ingress元件,通過反向代理負載均衡器(Nginx/HAProxy)+Ingress Controller+Ingress可以實作對外服務暴露,另外使用Traefik方案來實作Service的負載均衡也是一種不錯的選擇。

Q:kube-proxy是怎樣進行負載? Service虛拟IP存在哪裡?

A:kube-proxy有2個模式實作負載均衡,一種是userspace,通過Iptables重定向到kube-proxy對應的端口上,然後由kube-proxy進一步把資料發送到其中的一個Pod上,另一種是Iptables,純采用Iptables來實作負載均衡,kube-proxy預設采用輪詢方法進行配置設定,也可以通過将service.spec.sessionAffinity設定為“ClientIP”(預設為“無”)來選擇基于用戶端IP的會話關聯;Service Cluster IP它是一個虛拟IP,是由kube-proxy使用Iptables規則重新定向到其本地端口,再均衡到後端Pod的,通過 apiserver的啟動參數--service-cluster-ip-range來設定,由kubernetes叢集内部維護。

Q:Kubernetes網絡複雜,如果要實作遠端調試,該怎麼做,端口映射的方式會有什麼樣的隐患?

A:Kubernetes網絡這塊采用的是CNI規範,網絡插件化,非常靈活,不同的網絡插件調試的方法也是不一樣的;端口映射方式的最大隐患就是很容易造成端口沖突。

Q:RPC的服務注冊,把本機IP注冊到注冊中心,如果在容器裡面會注冊那個虛拟IP,叢集外面沒法調用,有什麼好的解決方案嗎?

A:Kubernetes Service到Pod的通信是由kube-proxy代理分發,而Pod中容器的通信是通過端口,不同Service間通信可以通過DNS,不一定要使用虛拟IP。

Q:我現在才用的是CoreOS作為底層,是以網絡采用的是Flannel 但是上層用Calico作為Network Policy,最近有一個Canal的結構和這個比較類似,能介紹一下麼,可以的話,能詳細介紹一下CNI原理和Callico的Policy實作麼?

A:Canal不是很了解;CNI并不是網絡實作,它是網絡規範和網絡體系,從研發的角度它就是一堆接口,關心的是網絡管理的問題,CNI的實作依賴于兩種Plugin,一種是CNI Plugin負責将容器connect/disconnect到host中的vbridge/vswitch,另一種是IPAM Plugin負責配置容器Namespace中的網絡參數;Calico 的policy是基于Iptables,保證通過各個節點上的 ACLs 來提供workload 的多租戶隔離、安全組以及其他可達性限制等功能。

Q:CNI是怎麼管理網絡的?或者說它跟網絡方案之間是怎麼配合的?

A:CNI并不是網絡實作,它是網絡規範和網絡體系,從研發的角度它就是一堆接口,你底層是用Flannel也好、用Calico也好,它并不關心,它關心的是網絡管理的問題,CNI的實作依賴于兩種plugin,一種是CNI Plugin負責将容器connect/disconnect到host中的vbridge/vswitch,另一種是IPAM Plugin負責配置容器Namespace中的網絡參數。

Q:Service是個實體元件麼?那些個Service配置檔案,什麼部件來執行呢?

A:Services是Kubernetes的基本操作單元,是真實應用服務的抽象,Service IP範圍在配置kube-apiserver服務的時候通過--service-cluster-ip-range參數指定,由Kubernetes叢集自身維護。

以上内容根據2017年5月18日晚微信群分享内容整理。分享人陽運生,有容雲産品經理。有着多年的系統、存儲、網絡、虛拟化、容器等雲計算技術相關的工作經驗,現主要負責容器平台(Rancher /Kubernetes)及其相關存儲、網絡、安全、日志、監控等解決方案工作。DockOne每周都會組織定向的技術分享,歡迎感興趣的同學加微信:liyingjiesz,進群參與,您有想聽的話題或者想分享的話題都可以給我們留言。

原文釋出時間為:2017-06-02

本文作者:陽運生

本文來自雲栖社群合作夥伴Dockerone.io,了解相關資訊可以關注Dockerone.io。

原文标題:DockOne微信分享(一二二):探索Kubernetes的網絡原理及方案

繼續閱讀