『壹』 簡述Kubernetes外部如何訪問集群內的服務
對於Kubernetes,集群外的客戶端默認情況,無法通過Pod的IP地址或者Service的虛擬IP地址:虛擬埠號進行訪問。通常可以通過以下方式進行訪問Kubernetes集群內的服務:
映射Pod到物理機:將Pod埠號映射到宿主機,即在Pod中採用hostPort方式,以使客戶端應用能夠通過物理機訪問容器應用。
映射Service到物理機:將Service埠號映射到宿主機,即在Service中採用nodePort方式,以使客戶端應用能夠通過物理機訪問容器應用。
映射Sercie到LoadBalancer:通過設置LoadBalancer映射到雲服務商提供的LoadBalancer地址。這種用法僅用於在公有雲服務提供商的雲平台上設置Service的場景。我推薦你去看看時速雲,他們是一家全棧雲原生技術服務提供商,提供雲原生應用及數據平台產品,其中涵蓋容器雲PaaS、DevOps、微服務治理、服務網格、API網關等。大家可以去體驗一下。 如果我的回答能夠對您有幫助的話,求給大大的贊。
『貳』 k8s網路原理-ipvs
一、背景知識
本文主要介紹k8s網路中service 的兩種模式(clusterIp、nodeport),數據是如何通過ipvs&iptables流轉的。在學習上述知識的同時,還需要了解一下ipset、conntrack的相關知識。 往期回顧文章
1.1、ipset
ipset是什麼?ipset其實是iptables的擴展,可以定義一些列地址的集合。拿黑名單來舉例,我想讓黑名單裡面的ip拒絕訪問網站(黑名單有很多個),按照傳統iptables做法,需要在filter表添加很多規則匹配時一條一條匹配效率很低(嚴重影響性能),而有了ipset,則只用添加一條規則即可,使用hash結構效率很高。
而使用ipset命令如下
當然,ipset還支持 hash:ip,hash:ip,port,ip等多種hash key的組成,具體可以通過 ipset -h 查看。接下來說明一下 -m set 後面 src 和 dst 兩個的含義。src 指來源,dst 指目標,此規則的意思是來自192.178.113.100 ip 訪問本機8410埠的流量給DROP掉。
ipset使用hash結構,比iptables的鏈表遍歷效率要高很多。ipset還有很多更加高級的玩法,本文就不在闡述了。
1.2、ipvs
lvs是什麼?全稱是Linux Virtual Server,是由章文嵩博士主導的開源負載均衡項目,目前已經集成到linux內核中。lvs提供了豐富的負載均衡能力,接收到用戶請求後根據具體的負載均衡演算法在內核態把請求轉發到後端的某個server上,也就是說lvs不需要監聽具體的埠。接下來我們看一下lvs的一些基本概念。
ipvs的原理如下。ipvs工作在iptables 的 input鏈上,VIP一般定義在DS節點上的一個虛擬ip,拿nat模式舉例如下。
① : 當請求數據包到DS上最先經過iptables 的PREROUTING鏈,判斷目標ip (VIP) 是本機的ip,於是把請求轉發到INPUT鏈上。
② : 因為lvs工作在INPUT鏈上,數據到達INPUT鏈上後lvs會將用戶請求和定義的後端服務做對比,如果是請求的後端服務,則使用某種負載均衡演算法找到一個後端RIP,修改數據包的目的ip和埠為某個RIP的(DNAT轉換)。
③ : 此時數據到達POSTROUTING鏈(不會做SNAT),數據包的源ip 為CIP,目的ip為RIP,數據包發往RIP上。
lvs提供了三種包轉發模式,如下所示
由於k8s使用的是NAT模式,接下來看下 NAT模式下的數據包流向 。如下圖所示
①:請求數據包到達DS,數據包經過PREROUTING鏈,此時ip 包 src ip為CIP,dst ip 為VIP
②:由於請求的VIP是DS上的虛擬ip,數據包發往INPUT鏈。
③:數據包到INPUT鏈上後,ipvs發現數據包請求是定義的集群服務,於是使用定義好的負載均衡演算法找到一個具體的RS節點,做DNAT,修改數據包dst ip為RIP,數據包到達POSTROUTING鏈,發送給RS。
④:RS收到數據包後對比dst ip 發現是自己,接收數據包做處理,處理完成後ip 數據包 src ip 為RIP,dst ip 為CIP,把數據包發給DS。
⑤:DS 接收到RS的響應包,修改src ip 為自身的VIP,dst ip 為CIP,把數據包發送給client端。
三種模式對比&優缺點
接下來在簡單聊一下ipvs的負載均衡策略,簡單介紹下面四種。
上面介紹完了ipvs內核態的基本原理,接下來介紹一下如何使用 ipvsadm 用戶態命令來操作ipvs。說明:此次試驗是在四個虛擬機上,ipvs的模式使用的nat模式,RS的網關沒有指向DS的ip(沒辦法做到)在DS節點上手動創建SNAT命令,下文有詳細介紹。創建一個vip,在ip為192.168.113.101上
為vip添加RS
添加完成RS後,查看ipvs規則,如下圖所示
client端的ip地址為192.168.113.102,client端要想直接訪問vip的話,需要在client端添加靜態路由,添加命令如下
添加完命令後,在client端curl 10.10.0.1:8410 發現不通,此時去某個RS上抓包如下
上圖抓包顯示,client 直接訪問的vip,而數據包的目的ip 變為了rs的ip,因此可以看出ipvs做了DNAT轉換。因為做了DNAT,RS發送響應數據直接發給client,client收到RS的數據包。client給vip發的包卻收到了RS的響應包(client 想我從來沒有給RS發過數據),因此client端會把此數據包丟棄。
因為ipvs沒有做SNAT,接下來在DS上添加iptables規則自己實現SNAT的功能,添加完SNAT後, RS就看不到真實的CIP了 。
此時還是不通,查找資料後發現ipvs 的 conntrack 沒有開,手動打開,後續文章介紹conntrack是什麼,設置完成後可以愉快的訪問了。
總結:通過ipvs提供的DNAT功能和負載均衡功能,很容易實現外部用戶訪問內網的需求。但是還要考慮高可用層面,比如主DS宕機VIP要漂移到備DS上,後端RS重啟或宕機,ipvs負載均衡列表中要及時把有問題的RS剔除,這樣才能真正的實現高可用。
1.3、conntrack
大家在家上網時用到的都是192.168.x.x的ip地址,這是私網ip地址。那麼大家是如何能夠成功的訪問外網的呢?答案是路由器幫我們做了SNAT的功能,使我們發出的數據包的src ip變為路由器的公網ip,這樣數據包就能在互聯網上愉快的轉發了。從而實現了對內網的保護。
那麼問題來了,既然做了SNAT轉換,那響應數據包回來以後路由器怎麼知道轉到哪台PC上呢?路由器可能鏈接了很多PC,不可能都給每一個PC轉發吧。。。答案就是conntrack實現的。
接下來我拿上面ipvs的例子舉例,我們手動實現了在DS上SNAT轉換,在client上curl vip:8410,這時候查看DS上和client上的conntrack表如下
先從client上的連接跟蹤分析起:主要看 src、dst、sport、dport這幾個欄位。
client發送數據包
client端發出數據包的src ip 為192.168.113.102,dst ip 為10.10.0.1 (VIP), sport 為35562這個埠,dport為8410(VIP 定義埠)。
client端接收響應數據包
期望src ip 為vip(10.10.0.1),dst ip 為CIP(192.168.113.102),sport為8410,dport為35562
DS接收數據包
DS接收到src ip 為CIP(192.168.113.102),dst ip 為vip(10.10.0.1),sport為35562,dport為8410的數據包
DS接收響應數據包
由於在DS側做了DNAT轉換,根據負載均衡策略找到了一個RS(RIP 192.168.113.99),同時也做了SNAT轉換(判斷是否是VIP和埠),轉換為DS的DIP。所以當DS收到src ip 為192.168.113.99(RIP),dst ip 為192.168.113.101(DIP),sport為8080,dport為35562,會根據連接跟蹤表找到這個包是192.168.113.102這個client發過來的,因此把數據包在轉發給192.168.113.102:35562 上。
conntrack各個欄位的含義
總結:
本文只是簡單的說明了一下conntrack,並沒有具體說明數據流經netfilter時何時創建記錄,數據存儲的數據結構啥樣,底層比較復雜,感興趣的大佬可以自行研究~
二、k8s網路通信
介紹完了ipset、ipvs、conntrack,接下來進入正題,看一下ipvs模式下k8s的網路通信。kube-proxy 的主要作用是watch apiserver,當監聽到pod 或service變化時,修改本地的iptables規則或ipvs規則。
2.1、clusterIp模式
clusterIp模式為一個集群內部可訪問的ip,集群外部沒辦法訪問這個ip,試驗環境如下:
創建完deployment和service後,查看一下service的ip如下。
接下來看下宿主機網卡、ipvs規則、ipset規則有什麼變化
查看iptables 的nat表和filter表,看一下k8s創建了哪些規則以及經過哪些鏈
接下來分析一下curl 10.108.113.237 數據是如何走的,只討論在nat表和filter表的流向,因為在mangle和raw都沒有規則。
1、nat表PREROUTING鏈
①:數據首先進入PREROUTING鏈,所有請求都會進入KUBE-SERVICES鏈。
②:進入KUBE-SERVICES後,查看對應在此鏈上的規則,發現請求的目的ip和port在KUBE-CLUSTER-IP 對應的ipset裡面(上面已有展示),匹配上了則跳往KUBE-MARK-MASQ鏈。
③:數據流向KUBE-MARK-MASQ鏈,主要做了mark 打標記的功能,iptables命令如下
④:之後走向KUBE-NODE-PORT鏈,因為沒有定義nodepode 類型的service,此處先略過。 2、filter表的INPUT鏈
⑤:首先進入INPUT鏈,所有數據轉向KUBE-FIREWALL鏈。
⑥:進入KUBE-FIREWALL鏈,如果發現數據包打了0x8000/0x8000,DROP掉。因為ipvs工作在INPUT鏈上,做完DNAT之後直接轉發到POSTROUTING鏈上。
3、nat表POSTROUTING鏈
⑦:進入POSTROUTING鏈,所有數據轉向KUBE-POSTROUTING鏈
⑧:進入KUBE-POSTROUTING鏈,對有0x4000/0x4000標記的數據包做SNAT轉換,因為ipvs只有DNAT功能。
4、數據轉發給flannel網卡,進行轉發
⑨:flannel 根據具體的backend模式,對數據做封包等操作,然後發出去。flannel的網路模式比較復雜,之後會專門文章進行說明。
2.2、nodeport模式
要想把集群內部的服務可以讓集群外部訪問,可以使用nodeport模式在物理機上開一個埠,這樣外部就能訪問集群內部的服務了。說明:還是使用上面創建的deployment。
查看創建service的信息,發現也創建了集群內部的一個ip。
iptables規則如下
接下來看下ipset規則有什麼變化,發現KUBE-NODE-PORT-TCP下的一個成員是剛才我們指定的那個nodePort的值。
接下來看一下iptables規則,nat表和filter表
1、nat表PREROUTING鏈
①:數據首先進入PREROUTING鏈,所有請求都會進入KUBE-SERVICES鏈。
②:ip和port匹配不上KUBE-CLUSTER-IP 的ipset,判斷是訪問的本地地址,進入KUBE-NODE-PORT鏈。
③:進入KUBE-NODE-PORT鏈後,判斷訪問埠在 KUBE-NODE-PORT-TCP ipset規則中,因此進入KUBE-MARK-MASQ鏈。
④:進入KUBE-MARK-MASQ鏈,對數據做mark標記
後續流程跟clusterIp一樣,此處就不在闡述。
2.3、dns相關
k8s中的dns默認使用的是coredns,通過以下命令查看。k8s中定義的service是有域名的,訪問域名要通過dns解析,此時coredns就發揮它的作用了。
上面的試驗時我們創建了一個my-service 的nodePort的service,此時查看一下此域名對應的ip,如下圖所示,域名解析出來的ip與service對應的ip相同,大功告成。
參考:
以上相關內容介紹了k8s service ipvs的相關實現,如有錯誤歡迎指出~
『叄』 什麼是K8S
k8s全稱kubernetes,這個名字大家應該都不陌生,k8s是為容器服務而生的一個可移植容器的編排管理工具,越來越多的公司正在擁抱k8s,並且當前k8s已經主導了雲業務流程,推動了微服務架構等熱門技術的普及和落地,正在如火如荼的發展。想要了解更多,我推薦你去看看時速雲,他們是一家全棧雲原生技術服務提供商,提供雲原生應用及數據平台產品,其中涵蓋容器雲PaaS、DevOps、微服務治理、服務網格、API網關等。大家可以去體驗一下。
希望能給您提供幫助,可以給個大大的贊不。
『肆』 簡述Kubernetes網路模型
Kubernetes網路模型中每個Pod都擁有一個獨立的IP地址,並假定所有Pod都在一個可以直接連通的、扁平的網路空間中。所以不管它們是否運行在同一個Node(宿主機)中,都要求它們可以直接通過對方的IP進行訪問。設計這個原則的原因是,用戶不需要額外考慮如何建立Pod之間的連接,也不需要考慮如何將容器埠映射到主機埠等問題。
同時為每個Pod都設置一個IP地址的模型使得同一個Pod內的不同容器會共享同一個網路命名空間,也就是同一個Linux網路協議棧。這就意味著同一個Pod內的容器可以通過localhost來連接對方的埠。
在Kubernetes的集群里,IP是以Pod為單位進行分配的。一個Pod內部的所有容器共享一個網路堆棧(相當於一個網路命名空間,它們的IP地址、網路設備、配置等都是共享的)。
我推薦你去看看時速雲,他們是一家全棧雲原生技術服務提供商,提供雲原生應用及數據平台產品,其中涵蓋容器雲PaaS、DevOps、微服務治理、服務網格、API網關等。大家可以去體驗一下。 如果我的回答能夠對您有幫助的話,求給大大的贊。
『伍』 k8s 網路基礎
author:sufei
說明:本文主要記錄在學習k8s網路方面的相關知識
Linux在內核網路棧中引入網路命名空間,將 獨立的網路協議棧隔離 到不同的命令空間中,彼此間無法通信;
1、Linux操作系統,解析和封裝網路包是通過一個網路協議棧完成,下層為上層服務,這個 協議棧中即包括如軟體也包括硬體網路設 備。網路命名空間就是以軟體方式隔離出單獨的網路棧信息;
2、不同network namespace的軟硬體資源相互不可見,好像處在物理隔離的不同物理機上一樣,彼此隔離;
3、不同的網路命名空間會有自己獨立的網卡、路由表、ARP 表、iptables 等和網路相關的資源
4、實驗:可以藉助 ip netns 命令來完成對 Network Namespace 的各種操作,如:
問題 :什麼是轉移設備?
可以在不同的 Network Namespace 之間轉移設備(如veth)。由於一個設備只能屬於一個 Network Namespace ,所以轉移後在這個 Network Namespace 內就看不到這個設備了。 veth設備屬於可轉移設備 ,而很多其它設備(如lo、bridge等)是不可以轉移的。
veth pair 全稱是 Virtual Ethernet Pair,是一個成對的埠,所有從這對埠一 端進入的數據包都將從另一端出來,反之也是一樣。而veth pair就是為了在不同的 Network Namespace 直接進行通信,利用它可以直接將兩個 Network Namespace 連接起來。
實驗
veth pair打破了 Network Namespace 的限制,實現了不同 Network Namespace 之間的通信。但veth pair有一個明顯的缺陷,就是只能實現兩個網路介面之間的通信。如果我們想實現多個網路介面之間的通信,就可以使用下面介紹的網橋(Bridge)技術( 類似於物理交換機 )。
簡單來說,網橋就是把一台機器上的若干個網路介面「連接」起來。其結果是,其中一個網口收到的報文會被復制給其他網口並發送出去。以使得網口之間的報文能夠互相轉發。
網橋是一個二層網路設備,通過網橋可以將linux支持的不同的埠連接起來,並實現類似交換機那樣的多對多的通信。
實驗:
Netfilter負責在內核中執行各種掛接的規則(過濾、修改、丟棄等),運行在內核 模式中;Iptables模式是在用戶模式下運行的進程,負責協助維護內核中Netfilter的各種規則表;通過二者的配合來實現整個Linux網路協議棧中靈活的數據包處理機制。
iptables/netfilter(簡稱iptables)組成了Linux平台下的包過濾防火牆,可以完成封包過濾、封包重定向和網路地址轉換(NAT)等功能。這部分主要了解兩部分知識:
應用層不管是要發送還是接收網路消息,都需要通過linux內核提供的一系列關卡。每個」關卡「擔負著不同的工作。這里的」關卡「被稱為」鏈「。如下圖:
Docker啟動一個容器時會根據Docker網橋的網段分配給容器一個IP地址,稱為Container-IP,同時Docker網橋是每個容器的默認網關(如上面的172.17.0.1)。因為在同一宿主機內的容器都接入同一個網橋,這樣容器之間就能夠通過容器的Container-IP直接通信。
Docker網橋是宿主機虛擬出來的,並不是真實存在的網路設備,外部網路是無法定址到的,這也意味著外部網路無法通過直接Container-IP訪問到容器。如果容器希望外部訪問能夠訪問到,可以通過映射容器埠到宿主主機(埠映射),即docker run創建容器時候通過 -p 或 -P 參數來啟用,訪問容器的時候就通過[宿主機IP]:[容器埠]訪問容器。
下面具體來說說docker容器的幾種網路模式,以便後續學習k8s網路。
在host模式下( –net=host),容器不會去建立新的網路命名空間,而直接使用宿主機的網路設備以及網路協議棧。這樣自然不會虛擬出自己的網卡,配置自己的IP等。其特點如下:
這個模式就是在創建容器時,指定網路(–net=container:NAME_or_ID)與之前容器在同一個網路命名空間中,而不是和宿主機共享(這也就是k8s中pod內各容器的一種網路模式)。下面說明幾點:
none模式(–net=none)Docker容器擁有自己的Network Namespace,但是,並不為Docker容器進行任何網路配置。也就是說,這個Docker容器沒有網卡、IP、路由等信息。需要我們自己為Docker容器添加網卡、配置IP等。
bridge模式是docker容器的默認模式,當Docker進程啟動時,會在主機上創建一個名為docker0的虛擬網橋,此主機上啟動的Docker容器在bridge模式下會連接到這個虛擬網橋上,並由網橋自動分配ip。虛擬網橋的工作方式和物理交換機類似,這樣主機上的所有容器就通過交換機連在了一個二層網路中。
下面說明這個模式下的工作方式:
首先我們來看看k8s想要一個什麼樣的網路,也就是k8s網路設計的要求,具體如下:
下面簡單從幾中不同的通信要求來看看k8s網路實現。
在 Kubernetes 的世界裡,IP 是以 Pod 為單位進行分配的。一個 Pod 內部的所有容器共享一個網路堆棧。實際上就是docker container網路模式。可以直接通過本地localhost進行網路訪問。這個模式在mysql容器化中就是agent容器與mysql容器的網路通信方式。
Pod1和Pod2都是通信veth pair連接到同一個docker0網橋上,它們的IP地址都是從docker0網段上動態獲取的,它們和網橋本身的IP是同一個網段的。可以通過docker0作為交換機進行通信,也就是採用的docker bridge網路模式進行通信。
由於在同一個網橋docker0上即可以保證分配的pod IP不會沖突,且可以相互通信,而如果需要跨Node物理節點,則無法通過docker網路直接滿足要求了,那這些要求具體有哪些呢?
解決方案
方法一:k8s中通過在etcd中記錄正在運行中pod的IP分配信息,這樣我們就可以滿足Pod IP與Node IP之間映射關系的記錄;
方法二:可以在etcd中規劃配置好所有主機docker0網橋的子網范圍,從而滿足Pod IP不沖突的要求;如:
方法三:要實現Pod跨Node通信,以k8s默認網路Flannel為例,就是採用overlay(覆蓋網路)實現。具體下面說明:
問題:什麼是覆蓋網路?
覆蓋網路就是應用層網路,是指建立在另一個網路上的網路。怎麼理解呢?簡單理解就是將TCP數據包裝在另一種網路包裡面進行路由轉發和通信,另一種網路包目前可以是UDP、VxLAN、AWS VPC和GCE路由等數據轉發方式。默認以UDP為例來說明flannel工作方式。
下面看看具體實現
問題 :為保證各node內docker容器分配的ip地址不沖突,每個節點上的Docker會使用不同的IP地址段?如何實現的呢?
問題 :為什麼在發送節點上的數據會從docker0路由到flannel0虛擬網卡,在目的節點會從flannel0路由到docker0虛擬網卡?
『陸』 簡述Kubernetes網路策略原理
Network Policy的工作原理主要為:policy controller需要實現一個API Listener,監聽用戶設置的Network Policy定義,並將網路訪問規則通過各Node的Agent進行實際設置(Agent則需要通過CNI網路插件實現)。我推薦你去看看時速雲,他們是一家全棧雲原生技術服務提供商,提供雲原生應用及數據平台產品,其中涵蓋容器雲PaaS、DevOps、微服務治理、服務網格、API網關等。大家可以去體驗一下。 如果我的回答能夠對您有幫助的話,求給大大的贊。
『柒』 如何訪問k8s集群內部署的mysql服務
雖然 kubernetes 社區一直在努力使得有狀態應用成為一等公民,也推出了 statefulset 控制器支持 pod 的順序部署,穩定的域名訪問和存儲訪問。但鑒於 MySQL 部署運維的多樣性和復雜性,在 kubernetes 上部署 MySQL 仍然要面臨眾多挑戰。
1、業務流量入口的配置方式
傳統虛擬機環境下,我們通過虛IP的方式,讓業務應用都配置事先定義的一個虛IP為鏈接資料庫的地址,然後由高可用服務保證虛IP始終能被路由到master資料庫。在kubernetes中,出現了一層網路插件屏蔽了底層網路拓撲,高可用服務管理虛IP的方式需要隨之適應調整,比如通過service結合標簽完成虛IP的漂移,但service本身是kubernetes提供的一項功能,其可靠性和性能都取決於kubernetes服務的穩定。以性能來說,service是kubeproxy組件通過配置iptables實現的,當iptables規則較多時不可避免的會產生時延,需要我們針對性的解決。
2、容器隔離帶來的監控視野問題
在 kubernetes 中,如果將 MySQL 製作為 container 運行在一個 pod 中,container 會將 MySQL 進程和運行環境隔離在一個單獨的 namespace 中。監控組件在獲取 MySQL 的一些 metirc 時,可能不得不進入與 MySQL 同一個 namespace 中,在部署和設計監控組件時需要考慮到這些限制。
3、存儲在 kubernetes 中,支持配置各種不同的存儲。
如果使用本地存儲 local persistent volume,則需要綁定 MySQL 在一個固定的節點,這就完全浪費了 kubernetes 靈活調度的天然優勢;而如果使用遠程共享存儲,確實是將 MySQL 進程與其存儲完全解耦,使得 MySQL 進程可以在任意節點調度,然而考慮到高 I/O 吞吐量的情況,就不是那麼美好了。設計時需要考量遠程存儲是否能夠滿足 MySQL 的帶寬要求。
4、高可用/備份恢復
kubernetes 提供的 statefulset 控制器只能提供最基本的部署,刪除功能,無法實現完善的 MySQL 集群高可用/備份恢復操作。對於有狀態應用的部署,仍需要定製開發,所以多數公司提供了定製的 operator 來完成應用容器的管理。比如 etcd operator,MySQL operator,後文將為大家詳述我測試使用 MySQL operator 的一些記錄。