service 2 暴露服務(wù)的 3種 方式
【k8s 系列】k8s 學(xué)習(xí)十九,service 2
之前我們簡單的了解一下 k8s 中 service 的玩法,今天我們來分享一下 service 涉及到的相關(guān)細(xì)節(jié),我們開始吧
為什么要有 服務(wù) Service?
因為服務(wù)可以做到讓外部的客戶端不用關(guān)心服務(wù)器的數(shù)量,服務(wù)內(nèi)部有多少個 pod,也可以正常連接到服務(wù)器,并可以正常進行業(yè)務(wù)處理
咱們可以舉一個例子,客戶端 --> 前端 --> 后臺
客戶端將流量打到前端的 Service 上,前端的 Service 會將流量給到任意一個 pod 上面,然后 流量進而打到后臺服務(wù)的 Service 上,最終請求到后臺服務(wù)的任意 pod 上面
這個時候,客戶端無需知道到底是哪個 pod 提供的服務(wù),也無需知道提供 pod 的地址,只需要知道前端服務(wù)的 地址和端口即可
新建一個 demo 服務(wù)
咱們可以簡單些一個 Service 的 yaml 文件,然后部署起來,對于 Service 資源管控哪一些 pod ,我們?nèi)匀皇鞘褂?標(biāo)簽來進行管控的
例如我們的 minikube 環(huán)境中有這樣 3 個 標(biāo)簽為 appxmt-kubia
的 pod
我們可以這樣寫 Service 清單:
kubia-service.yaml
apiVersion:?v1
kind:?Service
metadata:
??name:?kubia-service
spec:
??ports:
??-?port:?80
????targetPort:?8080
??selector:
????app:?xmt-kubia
此處的 selector 選擇器,和前面我們說到的 ReplicaSet 的做法是一致的,此處是 Service 暴露一個 80 端口,映射到 pod 的 8080 端口
我們也可以暴露多個端口,但是暴露多個端口的話,必須要寫 name ,例如這樣
運行 kubectl create -f kubia-service.yaml ,部署一個 Service 資源
kubectl get svc 可以看到如下 svc 的資源列表
可以通過在 pod 內(nèi)部訪問 svc 的 ip 來查看是否可以請求成功
通過命令選中任意 pod,在 pod 中執(zhí)行 curl 命令,請求 http 接口
kubectl exec kubia-rs-sxgcq -- curl -s 10.106.228.254
果然是可以請求通過的
當(dāng)然,我們也是可以通過完全進入到 pod 內(nèi)部,來訪問 Service 的地址
kubectl exec -it kubia-rs-sxgcq -- /bin/sh
此處的 Cluster IP , 意思是集群內(nèi)部的 IP,只用于在集群內(nèi)部進行訪問的,當(dāng)前我們創(chuàng)建的服務(wù)的目的就是,集群內(nèi)部的其他 pod ,能夠通過訪問這個 Service 的 IP 10.106.228.254 來訪問 該 Service 管控的一組 pod
通過日志,我們可以看出實際上請求成功了的,我們使用任意一個 pod,來請求 Service,然后 Service 來將流量打到自己管控的一組 pod 中,最終得到響應(yīng),可以畫個圖理解一波
Endpoint
看了上面 Service 和 pod 的關(guān)系,給人的感覺是不是 Service 和 pod 好像是直連的,其實并不是這樣的,其實 他倆之間還有一個關(guān)鍵的資源,那就是 Endpoint
Endpoints 這個資源就是暴露一個服務(wù)的 IP 地址和端口的列表
kubectl get endpoints kubia-service
Endpoints: ? ? ? ? 172.17.0.6:8080,172.17.0.7:8080,172.17.0.8:8080
如上我們可以看到 Endpoints ?暴露了服務(wù)的 IP 地址和端口列表
當(dāng)有客戶端連接到服務(wù)的時候,服務(wù)代理就會選擇這些 IP 和 端口 對中的一個發(fā)送請求
暴露服務(wù)
上面的做法都是在 k8s 集群內(nèi)部暴露服務(wù)的 IP ,這個 IP 是虛擬 IP ,只能在集群內(nèi)部訪問,且需要訪問對應(yīng)的端口才行
那么,我們?nèi)绾伪┞斗?wù)的端口,供外部的客戶端,或者是外部的服務(wù)進行調(diào)用呢?
類似于這樣的請求
關(guān)于 Service 資源暴露的方式有如下 3 種:
NodePort
LoadBalance
Ingress
三種方式各有優(yōu)劣,下面我們來詳細(xì)的看看
service 之 NodePort
NodePort ,看到命名我們就可以知道是在每個集群節(jié)點都會打開一個端口,外部客戶端可以訪問集群節(jié)點的 IP + PORT 就可以訪問到我們暴露的服務(wù),進而可以將流量請求到 服務(wù)管控的一組任意 pod 上
我們可以看看當(dāng)前我的實驗環(huán)境的 service 類型
上述 service 類型都是 Cluster IP 的,因此,我們需要將現(xiàn)有 svc 修改成 NodePort 或者重新創(chuàng)建一個新的 service ,就可以把這里的 TYPE 設(shè)置為 NodePort
編寫 NodePort 類型的 Service
kubia-service-nodeport.yaml
apiVersion:?v1
kind:?Service
metadata:
??name:?kubia-svc
spec:
??type:?NodePort
??ports:
??-?port:?80
????targetPort:?8080
????nodePort:?31200
??selector:
????app:?xmt-kubia
編寫基本的 NodePort 類型的 Service 資源清單
指定服務(wù)類型為 NodePort
注意此處是 ports , 也就是說可以配置多個端口映射,我們也可以暴露多個端口,之前的文章有說到,暴露多個端口的時候,是需要寫 name 的,name 記得需要符合 k8s 的命名規(guī)范
指定暴露的端口為 31200 ?(外部客戶端通過 IP + 31200 就能夠訪問到服務(wù)管理的一組 pod 的,pod 的端口是 8080)
注意,如果這里不指定 nodePort端口,那么 k8s 會隨機分配一個端口,默認(rèn)端口范圍是 30000 - 32767, 我們也可以修改 k8s 默認(rèn)端口范圍,修改位置為:
/etc/kubernetes/manifests/kube-apiserver.yaml
運行后查看效果
這個時候,該服務(wù)已經(jīng)暴露了 31200 端口了,我們可以在我們的 window 上通過 telnet ip port
的方式來訪問我們這臺云服務(wù)實驗環(huán)境,但是請記得在云服務(wù)器的防火墻處打開 31200 端口
我們通過外部客戶端請求工作節(jié)點的 IP + 暴露的 port,是這樣的流程:
外部客戶端流量從節(jié)點的 31200 端口打入,會被重定向到 service 管控的一組任意 pod 上
service 之 ?LoadBalance
我們可以想一下上面的 NodePort 的方式有什么缺點?
上面暴露了服務(wù)的端口,但是我們訪問的時候需要指定工作節(jié)點的 ip + port,如果我們指定的工作節(jié)點出現(xiàn)了故障,那么外部客戶端請求服務(wù)就會出現(xiàn)無響應(yīng),除非客戶端知道其他正常工作節(jié)點的 IP
因此,這個時候,負(fù)載均衡器就上場了
創(chuàng)建 LoadBalance 類型的 服務(wù),只需要將上述 NodePort 的資源清單中 type: NodePort
修改成 type: LoadBalance
即可
LoadBalance
LoadBalance 負(fù)載均衡器,我們可以放在節(jié)點的前面,確保外部客戶端發(fā)送的請求能夠發(fā)送到健康的節(jié)點上,并且絕對不會將外部的請求發(fā)送到狀態(tài)異常的工作節(jié)點上
使用 LoadBalance 之后,上述的流程就變成了這個樣子的:
這個時候,對于客戶端,只需要訪問固定的 IP + port 就可以輕松的訪問到健康的工作節(jié)點上的 pod 了
service 之 Ingress
現(xiàn)在我們一起來看看暴露服務(wù)的第三種方法,使用 ingress 控制器
為什么要有 ingress ?
往上面看,使用 LoadBalance 的時候,LoadBalance 需要一個公網(wǎng)的 IP,且只能提供給一個 Service
那么如果是有多個 Service 的時候,我們就要部署多個 LoadBalance ?負(fù)載均衡器 了,因此 ingress 就出馬了
ingress 可以做什么呢?
ingress 可以做到只需要一個公網(wǎng) IP,就可以為多個 Service 提供準(zhǔn)入和訪問,我們可以理解為 ingress 像 nginx 一樣通過路由來識別給多個服務(wù)的請求
簡單流程可以是這個樣子的:
這樣,使用 ingress 就比使用 LoadBalance 要方便多了,但是具體使用的時候,還是看自己的需求是什么,來選擇合適的方式
寫一個 ingress 的demo
寫 ingress demo 之前,我們先確認(rèn)我們實驗環(huán)境中是否開啟了 ingress 控制器
minikube addons list
我的環(huán)境是開啟的,如果沒有開啟的話,可以執(zhí)行命令開啟 ingress 控制
minikube addons enable ingress
開啟時候,我們可以查看到有關(guān)于 ingress 的 pod
kubectl get po --all-namespaces
開始創(chuàng)建 ingress 資源
apiVersion:?networking.k8s.io/v1
kind:?Ingress
metadata:
??name:?kubia-ingress
spec:
??ingressClassName:?nginx
??rules:
??-?host:?hello.example.com
????http:
??????paths:
??????-?path:?/
????????pathType:?Prefix
????????backend:
??????????service:
????????????name:?kubia-nodeport-svc
????????????port:
??????????????number:?80
ingress 資源,填寫的 apiVersion 為
networking.k8s.io/v1
,如果 k8s 是 1.17 之前的,那么 apiVersion 需要填寫extensions/v1beta1
ingressClassName: nginx
指定規(guī)則會加入到 nginx 中rules ,我們可以看出這個規(guī)則是可以添加多條的,這也證明了 ingress 是可以通過多個路由來給多個服務(wù)提供訪問的
創(chuàng)建 ingress 資源,查看效果
現(xiàn)在,我們就可以在任意客戶端(前提是能夠訪問的通 k8s 這臺機器或集群),配置一下本地 host,hello.example.com 指向 ingress 的 ip 即可
配置完成后,客戶端可以向 hello.example.com
發(fā)起請求了,可以愉快地玩耍
咱最后來看看外部客戶端訪問 ingress 地址后原理是怎樣的?
如上圖,我們可以看出,外部客戶端訪問域名:hello.example.com
外部客戶端先去找 DNS 拿到 hello.example.com 對應(yīng)的 IP(ingress 控制器的 ip)
客戶端向 ingress 控制器 發(fā)送 http 請求,host 中會帶上 域名,ingress 會去查詢 該域名對應(yīng)的服務(wù)(找 ingress 資源查),進而找到 endpoint ip 和 port 映射列表
最終 ingress 控制器,直接把流量打到 service 管控的一組任意 pod 上面
這里的流量是 ingress 控制器直接打到 pod 上,而不是通過 service 轉(zhuǎn)發(fā)
今天就到這里,學(xué)習(xí)所得,若有偏差,還請斧正
歡迎點贊,關(guān)注,收藏
朋友們,你的支持和鼓勵,是我堅持分享,提高質(zhì)量的動力
好了,本次就到這里
技術(shù)是開放的,我們的心態(tài),更應(yīng)是開放的。擁抱變化,向陽而生,努力向前行。
我是阿兵云原生,歡迎點贊關(guān)注收藏,下次見~