通過k8s部署集群並提供服務的時候,會部署很多的pod以及pod副本來保證服務的高可用。
這也帶來了一個問題!!
這麼多pod提供服務,外部如何訪問這些服務?
在k8s中,每個pod都會被分配一個ip,即每個pod都唯一的ip。
但調用端是不管你內部有多少個pod 的,它只關心調取什麼地址來進行通信,如下圖:
如果調用端直接訪問某個pod的ip來訪問服務,會帶來兩個問題:
問題1:
pod是有生命周期的,一旦被重啟,pod的ip就會發生變更,而且我們通過deployment進行滾動升級的時候是新建pod,並逐步刪除舊的pod,新舊pod的ip是不一樣的。
問題2:
如果nginx的服務部署了10個pod,直接連接單個pod的ip的話,那剩下的9個pod不就沒用了嗎?怎麼才能如何保證請求均勻打到這個10個pod上呢?
要解決這個問題,k8s內部需要有一個對象來做如下兩件事情:
1、能夠管理一組pod,這組pod有固定的對外訪問的ip
2、能夠管理一組pod,並且對組內的pod進行服務發現和負載均衡
在k8s中,這個對象就是service,簡稱svc。
service是一個抽象概念,它定義了一組服務的多個pod邏輯合集和訪問pod的策略,一般把service稱為微服務。
簡單來說,service就是服務的反向代理,service並不提供服務,他只是提供一個統一的入口,並將接到的請求轉發給pod服務去處理,如下圖:
service管理pod和之前的RC或者RS一樣,通過pod的標籤來管理每一組pod。
service的創建和deployment等資源的創建方式一樣,只需要在yaml中定義service的相關屬性,並執行相應的命令運行這個配置即可。
我們在yaml中定義Serive的時候,需要指定spec.type欄位,分別為以下四個選項:
1、ClusterIP。
這是type的默認選項,此時,k8s會自動給這個service分配虛擬IP,service有了ip,那麼就可以訪問這個service 的ip,而不用關心內部的pod的ip。
2、NodePort。
將Service通過指定的Node上的埠暴露給外部,這樣外部可以訪問node的ip和對應埠,就可以訪問這個服務。
注意:配置成NodePort後,訪問任意一個NodeIP:NodePort都將路由到service的虛擬ip,從而成功獲得該服務。
3、LoadBalancer。
在 NodePort 的基礎上,藉助 cloud provider 創建一個外部的負載均衡器,並將請求轉發到 <NodeIP>:NodePort。
注意:此選項只能在雲伺服器(AWS等)上使用,且需要藉助一些負載均衡的軟體。
4、ExternalName。
將服務通過 DNS CNAME 記錄方式轉發到指定的域名(通過 spec.externlName 設定)。
注意:此選項需要 kube-dns 版本在 1.7 以上。
好了,接下來看看怎麼創建service並如何訪問這個service吧?
這篇文章中,我們演示下ClusterIP和NodePort這兩種方式。
和之前創建其他資源一樣,k8s也是通過配置yaml,然後通過命令行來實現service的創建和管理。
01
—
ClusterIP類型的Service
先創建一個nginx-service.yaml文件,並寫下如下內容,注意這裡沒有定義type為ClusterIP,k8s則會將此service默認為ClusterIP類型:
kind: Service
apiVersion: v1
metadata:
name: my-service
labels:
app: my-service
spec:
selector:
app: nginx-de
ports:
- protocol: TCP
port: 80
targetPort: 80
創建這個service資源:
[root@iZuf64nzsz01vlhaqampj5Z k8s]# kubectl apply -f nginx-service.yaml
service "my-service" created
查看這個service的具體內容:
[root@iZuf64nzsz01vlhaqampj5Z k8s]# kubectl describe service my-service
Name:my-service
Namespace:default
Labels:app=my-service
Selector:app=nginx-de
Type:ClusterIP
IP:10.254.114.224
Port:<unset>80/TCP
Endpoints:172.18.0.3:80,172.18.0.4:80,172.18.0.5:80 + 1 more...
Session Affinity:None
No events.
可以看到,k8s默認給這個名叫my-service的service分配了一個ip為10.254.114.224,通過這個ip以及80埠的請求會被轉發到後端的pod上去。
由於ClusterIP類型的service被分配的虛擬ip,只能在集群內部使用,因此我們進入pod裡面去訪問service看看:
[root@iZuf64nzsz01vlhaqampj5Z k8s]# kubectl exec -it nginx-deployment-2796601259-zcn3s sh
/ # curl 10.254.114.224
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
可以看到,集群內通過service的ClusterIP進行訪問是正常的。
02
—
NodePort類型的Service
外部應該怎麼訪問service呢?通過配置NodePort類型的service來實現。
修改下剛剛的那個nginx-service.yaml,如下:
kind: Service
apiVersion: v1
metadata:
name: my-service
labels:
app: my-service
spec:
selector:
app: nginx-de
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30088 #節點埠,外部通過節點ip加埠可訪問
type: NodePort
在配置文件的最後兩行,分別加上了type類型和nodePort的埠。
然後執行如下命令,使剛剛修改的service的配置生效:
[root@iZuf64nzsz01vlhaqampj5Z k8s]# kubectl apply -f nginx-service.yaml
service "my-service" configured
然後,我們通過node節點ip+埠的方式來訪問,外部訪問正常:
通過節點ip+port的方式看起來是訪問了1臺node上的pod,但實際上,還是將請求打到service的虛擬ip上,然後由service決定將請求轉發到哪個pod上。
好啦,今天的內容就到這裡啦,我們分別演示了兩種service的創建方式,有疑問的話,歡迎在下方留言哦!!