《Kubernetes》,你需要掌握的 Service 和 Ingress
本文轉(zhuǎn)載自微信公眾號「小菜良記」,作者蔡不菜丶 。轉(zhuǎn)載本文請聯(lián)系小菜良記公眾號。
k8s 我們已經(jīng)從 NameSpace、Pod、PodController到Volumn都介紹過了,相信看完的小伙伴們也會(huì)很有收獲的~那么今天我們繼續(xù)來到k8s的課堂,這節(jié)我們將要來說下 k8S 搭建完服務(wù)后如何訪問!
首先我們要清楚什么是Service 和 Ingress。簡單來說,這兩個(gè)組件都是用來做流量負(fù)載的。那么什么又是流量負(fù)載呢?當(dāng)我們在集群內(nèi)部已經(jīng)通過 pod 部署了我們的應(yīng)用服務(wù),那么下一步要干啥?那就是讓用戶訪問到我們的應(yīng)用服務(wù),這個(gè)才是最重要的,不然你部署完了,用戶卻訪問不了,那豈不是無用功~
一、Service
在 k8s 中,pod 是應(yīng)用程序的載體,我們可以通過 pod的 IP 來訪問我們的應(yīng)用程序,但是我們已經(jīng)清楚了 pod 是具有生命周期的,一旦 pod 出現(xiàn)問題,pod控制器將會(huì)將pod銷毀進(jìn)行重新創(chuàng)建。那么這個(gè)時(shí)候 pod 的Ip就會(huì)發(fā)生變化,因此利用 pod IP 訪問應(yīng)用程序的方式直接 pass了,那么為了解決這個(gè)問題,k8s 引入了 Service 的資源概念,通過這個(gè)資源,可以整合多個(gè)pod,提供一個(gè)統(tǒng)一的入口地址,通過訪問 Service 的入口地址就能訪問到后面的 pod服務(wù)!
Service不是憑空出現(xiàn)的,不知道你是否還記得 Node 節(jié)點(diǎn)上的關(guān)鍵組件 kube-proxy!關(guān)鍵點(diǎn)來了哦~我們看個(gè)老圖回憶一下:
這張圖有看過之前的博文都不會(huì)陌生,是的!kube-proxy 在這里面起到了關(guān)鍵性的作用,每個(gè) Node 節(jié)點(diǎn)上都運(yùn)行著一個(gè) kube-proxy 服務(wù)進(jìn)程,當(dāng)創(chuàng)建 Service 的時(shí)候會(huì)通過 api-server 向 etc寫入創(chuàng)建的 service 的信息,而 kube-proxy 會(huì)基于監(jiān)聽的機(jī)制發(fā)現(xiàn)這種 Service 的變動(dòng),然后 它會(huì)將最新的Service信息轉(zhuǎn)換成對應(yīng)的訪問規(guī)則
到這里,應(yīng)該對Service有個(gè)大概的概念,起碼知道了它的用處,接下來我們不妨更加深入的了解一下~
1)工作模式
kube-proxy 支持 3 種工作模式,如下:
1. userSpace
這個(gè)模式比較穩(wěn)定,但是效率比較低!在 userSpace 模式下,kube-proxy 會(huì)為每一個(gè) Service 創(chuàng)建一個(gè)監(jiān)聽端口,當(dāng)有請求發(fā)往Cluster IP 的時(shí)候,會(huì)被 Iptables 規(guī)則重定向到 kube-proxy 監(jiān)聽的端口上,kube-proxy 會(huì)根據(jù) LB 算法選擇一個(gè) Pod 提供服務(wù)并建立起連接。
這個(gè)模式下,kube-proxy 充當(dāng)?shù)慕巧且粋€(gè) 四層負(fù)責(zé)均衡器,由于 kube-proxy 運(yùn)行在 userSpace 模式下,在進(jìn)行轉(zhuǎn)發(fā)處理的時(shí)候會(huì)增加內(nèi)核和用戶空間之間的數(shù)據(jù)拷貝,因此效率比較低。
2. iptables
在 iptables 模式下,kube-proxy 會(huì)為 Service 后端的每個(gè) pod 都創(chuàng)建對應(yīng)的 iptable 規(guī)則,直接將發(fā)往 Cluster IP 的請求重定向到一個(gè) pod IP 上。該模式下 kube-proxy 不承擔(dān)四層負(fù)載均衡器的角色,只負(fù)責(zé)創(chuàng)建 iptables 的規(guī)則。該模式的優(yōu)點(diǎn)便是較 userspace 模式來說效率更高,但是不能提供靈活的 LB 策略。當(dāng)后端Pod不可用的時(shí)候也無法進(jìn)行重試。
3. ipvs
這種模式與 iptables 模式形似,kube-proxy 會(huì)監(jiān)控pod的變化并且創(chuàng)建相應(yīng)的 ipvs 規(guī)則。但是 ipvs 規(guī)則相對于 iptables 來說轉(zhuǎn)發(fā)效率更高,而且支持更多的 LB 算法。
實(shí)踐
上面了解到3種工作模式。我們來簡單試一下 ipvs 的作用。首先準(zhǔn)備一份資源清單:
這份清單上半部分是創(chuàng)建一個(gè) Pod控制器,下半部分是創(chuàng)建一個(gè) Service。
然后我們輸入 ipvsadm -Ln命令即可看到 ipvs規(guī)則策略:
10.108.230.12 是 service 提供的訪問入口,當(dāng)訪問這個(gè)入口的時(shí)候,可以發(fā)現(xiàn)后面有三個(gè) pod 的服務(wù)在等待調(diào)用,kube-proxy 會(huì)基于 rr(輪詢)的策略,將請求分發(fā)到其中一個(gè)pod上去,這個(gè)規(guī)則會(huì)同時(shí)在集群內(nèi)的所有節(jié)點(diǎn)上都生成,所以在任何一個(gè)節(jié)點(diǎn)上訪問都可以!
此模式必須安裝 ipvs 內(nèi)核模塊,否則會(huì)降低為 iptables
開啟 ipvs:
- kubectl edit cm kube-proxy -n kube-system
編輯后保存(:wq) 退出
- kubectl delete pod -l k8s-app=kube-proxy -n kube-system
- ipvsadm -Ln
2)Service 使用
上面已經(jīng)介紹完了 Service 的幾種工作模式。下面我們進(jìn)入Service 的使用階段。我們上面已經(jīng)做了簡單的實(shí)踐,創(chuàng)建了一個(gè) Deploy ,一個(gè) Service ,然后我們可以通過 serviceIp + targetPort 或 nodeIp + nodePort訪問資源
但是在學(xué)習(xí) Service 的使用,僅僅這個(gè)是不夠的,Service又分為5種類型,下面將一一介紹。
1. ClusterIP
我們先看下 ClusterIP 類型的Service的資源清單:
通過創(chuàng)建后測試訪問 clusterIp + port
我們再查看下 ipvs 規(guī)則,可以看到該service已經(jīng)可以轉(zhuǎn)發(fā)到對應(yīng)的3個(gè)pod上
接下來我們可以通過 describe 指令查看該service有哪些信息:
掃了一遍發(fā)現(xiàn) Endpoints 和 Session Affinity 都是我們之間沒有見過的。那這個(gè)又是個(gè)什么東西呢?
Endpoint
Endpoint 是 k8s 中的一個(gè)資源對象,存儲在etcd中,用來記錄一個(gè) service 對應(yīng)的所有Pod 的訪問地址,它是根據(jù) service 配置文件中 selector 描述產(chǎn)生的。一個(gè)Service由一組Pod組成,這些Pod通過 Endpoint 暴露出來,可以說 Endpoint 是實(shí)際實(shí)現(xiàn)服務(wù)的端口的集合。通俗來說,Endpoint 是 service 和 pod 之間的橋梁
既然是一個(gè)資源,那么我們就可以獲取到
負(fù)載分發(fā)
我們上面已經(jīng)成功的實(shí)現(xiàn)了通過 Service 訪問到Pod 資源,那么我們再做一些修改,分別進(jìn)入3個(gè)pod編輯 usr/share/nginx/index.html 文件:
- # pod01
- Pod01 : ip - 10.244.1.73
- # pod02
- Pod01 : ip - 10.244.1.73
- # pod03
- Pod03 : ip - 10.244.2.63
然后我們再次嘗試通過 curl 10.96.10.10:80命令查看結(jié)果:
眼尖的你是否有發(fā)現(xiàn),這種負(fù)載分發(fā)策略不就是輪詢嗎!對于 Service 的訪問,k8s提供了兩種負(fù)載分發(fā)策略:
- 如果未定義分發(fā)策略,默認(rèn)使用 kube-proxy 的策略,比如隨機(jī)、輪詢
- 基于客戶端地址的會(huì)話保持模式,即來自同一個(gè)客戶端發(fā)起的所有請求都會(huì)轉(zhuǎn)發(fā)到固定的一個(gè)pod上。而這里就需要用到我們上面提到的沒有見過的東西 sessionAffinity
之前我們用 ipvsadm -Ln 命令查看分發(fā)策略的時(shí)候,里面有個(gè) rr 字段不知道你有沒有注意到,沒錯(cuò),這個(gè) rr 值得就是輪詢的意思
如果我們想要開啟會(huì)話保持的分發(fā)策略,那么只需要在spec中添加 sessionAffinity:ClientIP 選項(xiàng)
再次通過 ipvsadm -Ln 命令查看分發(fā)策略就可以發(fā)現(xiàn)結(jié)果已經(jīng)發(fā)生變化了
我們簡單測試一下:
這樣子就已經(jīng)實(shí)現(xiàn)了會(huì)話保持的分發(fā)策略!
注意:ClusterIp 的 Service,不支持外部訪問,也就是說通過瀏覽器訪問是不生效的,只能在集群內(nèi)部訪問
2. HeadLiness
很多服務(wù)都需要支持定制化,如果將產(chǎn)品定位為服務(wù),那么這個(gè)產(chǎn)品毋庸是成功。在某些場景中,開發(fā)人員并不想要使用 service 提供的負(fù)載均衡功能,而是希望自己來控制負(fù)載均衡策略。針對這種情況的發(fā)生,k8s也是很好的支持了,引入了 HeadLiness Service,這類 Service 不會(huì)分配 ClusterIp,如果想要訪問 service,只能通過 Service 域名進(jìn)行查詢。
我們來看下 HeadLiness 的資源清單模板:
唯一跟 ClusterIp 不同的便是 clusterIP: None 屬性的變化。
通過創(chuàng)建后可以發(fā)現(xiàn),ClusterIP并未分配,我們繼續(xù)查看 Service 的詳情
通過詳情我們可以發(fā)現(xiàn) Endpoints 已經(jīng)生效了,然后我們?nèi)我膺M(jìn)入到一個(gè)pod中,查看域名解析情況:
可以看到域名也已經(jīng)解析完成,默認(rèn)域名為service名稱.命名空間.svc.cluster.local
3. NodePort
上面的兩個(gè)service類型,都是只能在集群內(nèi)部才能訪問,但是我們部署服務(wù)肯定是想讓用戶通過集群外部可以使用的。那么這個(gè)時(shí)候就需要用到我們開頭創(chuàng)建的service類型,那就是 NodePort service。
這種類型的Service的工作原理也不難,其實(shí) 就是將 service的端口映射到 Node 的一個(gè)端口上,然后通過 NodeIp+NodePort進(jìn)行訪問
看了原理圖是不是感覺豁然開朗啦。那么來看看是怎么通過資源清單創(chuàng)建的:
我們通過以上資源清單創(chuàng)建service,然后訪問:
可以看出通過兩種方式都是可以訪問的,我們也可以在瀏覽器試試看:
這結(jié)果也是如我們所愿!
不要感覺到這里就已經(jīng)心滿意足了哦,雖然說已經(jīng)可以成功讓用戶訪問到了~我們趁熱打鐵繼續(xù)再了解剩下的兩種類型~
4. LoadBalancer
LoadBalancer 聽名字就知道跟負(fù)載均衡有關(guān)。這個(gè)類型與 NodePort 很相似,目的都是向外部暴露一個(gè)端口,主要的區(qū)別在于 LoadBalancer 會(huì)在集群的外部再做一個(gè)負(fù)載均衡器,而這個(gè)設(shè)備是需要外部環(huán)境支持的,外部環(huán)境發(fā)送到這個(gè)設(shè)備的請求,會(huì)被設(shè)備負(fù)載之后轉(zhuǎn)發(fā)到集群中。
圖中有個(gè)Vip的概念,這里的Vip指的是 Vitual IP,也就是虛擬IP,外部用戶通過訪問這個(gè)虛擬IP,可以負(fù)載到我們不同的service上,達(dá)到負(fù)載均衡和高可用的特點(diǎn)
5. ExternalName
ExternalName 類型的service 是用于引入集群外部的服務(wù),它通過 externalName 屬性指定外部一個(gè)服務(wù)的地址,然后在集群內(nèi)部訪問此service就可以訪問到外部服務(wù)了。
資源清單:
創(chuàng)建后我們可以查看域名解析,發(fā)現(xiàn)已經(jīng)解析成功:
- dig @10.96.0.10 svc-externalname.cbuc-test.svc.cluster.local
二、Ingress
1)工作模式
上面我們已經(jīng)講完了 Service幾種類型的用法,我們已經(jīng)知曉了想讓外部用戶訪問到我們pod中的服務(wù)有兩種類型的service是支持的,分別是:NodePort和LoadBalancer,但是其實(shí)認(rèn)真分析一下,我們不難發(fā)現(xiàn)這兩種service 的缺點(diǎn):
NodePort:會(huì)占用集群機(jī)器的很多端口,當(dāng)集群服務(wù)變多的時(shí)候,這個(gè)缺點(diǎn)就越發(fā)明顯
LoadBalancer:每個(gè)Service都需要一個(gè)LB,比較麻煩和浪費(fèi)資源,并且需要 k8s之外的負(fù)載均衡設(shè)備支持
這種缺點(diǎn)當(dāng)然不只是我們能夠發(fā)現(xiàn),作為k8s的啟動(dòng)者早已意識到了,緊接著便推出了 Ingress 的概念。Ingress 僅需要一個(gè) NodePort或 LB 就可以滿足暴露多個(gè)Service的需求:
實(shí)際上,Ingress就相當(dāng)于一個(gè)7層的負(fù)載均衡器,是 K8s 對反向代理的一個(gè)抽象,它的工作原理類似于 Nginx,可以理解成在 Ingress 里 建立諸多的隱射規(guī)則,然后 Ingress Controller通過監(jiān)聽這些配置規(guī)則轉(zhuǎn)化成 Nginx 的反向代理配置,然后對外提供該服務(wù)。這邊涉及到了兩個(gè)重要的概念:
- Ingress:K8s 中的一個(gè)資源對象,作用是定義請求如何轉(zhuǎn)發(fā)到 service 的規(guī)則
- Ingress Controller:具體實(shí)現(xiàn)反向代理及負(fù)載均衡的程序,對Ingress定義的規(guī)則進(jìn)行解析,根據(jù)配置的規(guī)則來實(shí)現(xiàn)請求轉(zhuǎn)發(fā),有很多種實(shí)現(xiàn)方式,如 Nginx、Contor、Haproxy等
Ingress 控制器 有很多中可以實(shí)現(xiàn)請求轉(zhuǎn)發(fā)的方式,我們通常上也會(huì)選擇我們比較熟悉的 Nginx 作為負(fù)載,接下來我們就以 Nginx 為例,我們先來了解一下其工作原理:
- 用戶編寫 Ingress Service規(guī)則, 說明每個(gè)域名對應(yīng) K8s集群中的哪個(gè)Service
- Ingress控制器會(huì)動(dòng)態(tài)感知到 Ingress 服務(wù)規(guī)則的變化,然后生成一段對應(yīng)的Nginx反向代理配置
- Ingress控制器會(huì)將生成的Nginx配置寫入到一個(gè)運(yùn)行中的Nginx服務(wù)中,并動(dòng)態(tài)更新
- 然后客戶端通過訪問域名,實(shí)際上Nginx會(huì)將請求轉(zhuǎn)發(fā)到具體的Pod中,到此就完成了整個(gè)請求的過程
了解了工作原理,我們就來落地實(shí)現(xiàn)~
2)Ingress使用
1. 環(huán)境搭建
在使用 Ingress之前,我們需要先搭建一個(gè) Ingress 環(huán)境
步驟一:
- # 拉取我們需要的資源清單
- wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
- wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
步驟二:
- # 創(chuàng)建資源
- kubectl apply -f ./
步驟三:
查看資源是否創(chuàng)建成功
到這里我們就已經(jīng)準(zhǔn)備好了 Ingress 環(huán)境,接下來來到測試環(huán)節(jié)~
我們準(zhǔn)備了兩個(gè)Service,兩個(gè) Deployment,和創(chuàng)建了6個(gè)副本的Pod
如果到現(xiàn)在還準(zhǔn)備不出這些資源的小伙伴得回頭做功課了哦~
大致結(jié)構(gòu)圖如下:
那我們現(xiàn)在就準(zhǔn)備一個(gè) Ingress 來達(dá)到以下的結(jié)果
準(zhǔn)備 Ingress 的資源清單:
- apiVersion: extensions/v1beta1
- kind: Ingress
- metadata:
- name: ingress-htpp
- namespace: cbuc-test
- spec:
- rules:
- - host: dev.cbuc.cn
- http:
- paths:
- - path: /
- backend:
- serviceName: svc-nodeport-dev
- servicePort: 80
- - host: pro.cbuc.cn
- http:
- paths:
- - path: /
- backend:
- serviceName: svc-nodeport-pro
- servicePort: 80
通過創(chuàng)建后我們還需要在我們電腦的本地 hosts 添加域名映射:
然后在網(wǎng)頁上通過 域名+nodePort 的方式就可以訪問到了
到這里我們就實(shí)現(xiàn)了Ingress 的訪問方式!