Service 概念
Kubernetes Service 定義了這樣一種抽象:邏輯上的一組 Pod,一種可以訪問它們的策略 —— 通常稱為微服務。
Service 通常是通過 Label Selector
,也就是 Service 通過標籤選擇的方式匹配一組 Pod 對外提供訪問的機制。
解釋上圖具體實現過程:
首先、定義一個 Nginx Deployment
由它建立三個Pod
,每個 Pod 中都有對應的標籤mynginx
。
第二、定義一個Nginx Service
,標籤為mynginx
,Service 會根據自己的標籤去匹配後端的 Pod 標籤,從而把它們加入佇列中提供對外服務,當然標籤可以定義多個。
第三、當我們Client
訪問Nginx Service
的時候,Service 會以輪詢的訪問策略來對外提供服務。
第四、當我們後端的Pod
掛掉的時候,Nginx Deployment
會重新建立一個新的Pod
來滿足期望值,Service 會自動的將新 Pod 加入到負載均衡佇列中。
Service提供負載均衡的能力限制:
Service 只提供 4 層負載均衡能力,並沒有 7 層功能,也就是說只能基於IP地址和埠進行轉發實現負載均衡。
需要提供 7 層負載均衡能力可以通過 Ingress 負載均衡方案來實現,後面的文章中會介紹,歡迎關注我哦。
Service 型別講解
Service 具有四種類型:
ClusterIP: 預設型別,自動分配一個叢集內部虛擬IP地址,只能被叢集內部訪問。(常用)
NodePort: 通過每個節點上的 IP 和靜態埠(NodePort
)暴露服務,提供對外訪問。也就是說我們可以通過叢集中任意一個節點 IP 地址和埠來訪問後的 Pod 應用。(常用)
LoadBalancer: 使用雲提供商的負載均衡器向外部暴露服務。 外部負載均衡器可以將流量路由到自動建立的 NodePort
服務和 ClusterIP
服務上。(摘自於官方)
ExternalName: 把叢集外部的服務引入到叢集內部來,在叢集內部直接使用。
也就是說假設外部有一個數據庫叢集,叢集內部的Service
只需要寫叢集外部IP地址資訊,叢集內部的Pod
就可以實現訪問。
如果某一天外部叢集 IP 地址發生變化,只需要更新叢集內部的Service
資訊,內部的Pod
還是可以正常訪問外部資料庫叢集。
VIP 和 Service 代理
在 Kubernetes 叢集中,每個 Node 執行一個 kube-proxy
程序。 kube-proxy
負責為 Service 實現了一種 VIP(虛擬 IP)的形式,而不是 ExternalName
的形式。
在 Kubernetes v1.0 版本,代理完全在 userspace 。在 Kubernetes V1.1 版本,新增了 iptables 代理,但並不是預設的執行代理模式。
從 Kubernetes V1.2 開始,預設代理模式為 iptables;在 Kubernetes V1.8.0-beta.0 中,添加了 IPVS 代理。
然後從 Kubernetes V1.14 版本開始預設使用 IPVS 代理模式。
userspace 代理模式
當 Client 需要訪問 Pod 時,首先需要訪問 iptables,再從防火牆訪問到 Kube-proxy,再從 Kube-proxy 訪問到對應的 Pod。
無論 Client 訪問本地的 Pod 還是其他節點的 Pod 都需要通過 Kube-proxy 來代理,包括 apiserver 也會監控 Kube-proxy 進行服務更新等操作,這樣會導致 Kube-proxy 壓力巨大。
iptables 代理模式
通過如下圖可以看到,所有的訪問都是通過 iptables 來完成,而不需要通過 Kube-proxy 來排程,這樣的話,訪問速度加快,而 Kube-proxy 壓力減少,穩定性就會提升。
IPVS 代理模式
IPVS 代理模式跟 iptables 代理模式中的區別只是把 iptables 變成 IPVS ,其他的沒有變。IPVS 是在核心空間中工作,意味著通訊的延遲更短,效能更好。如果沒有安裝 IPVS 模組,則 kube-proxy 將退回到以 iptables 代理模式執行。
Service 實驗演示
ClusterIP 型別
首先建立 Deployment ,my-nginx.yaml
檔案如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx # 標籤匹配
replicas: 3
template:
metadata:
labels:
run: my-nginx # 定義標籤
spec:
containers:
- name: my-nginx
image: hub.test.com/library/mynginx:v1
ports:
- containerPort: 80
建立 Deployment 以及檢視狀態資訊
[root@k8s-master01 ~]# kubectl apply -f my-nginx.yaml
deployment.apps/my-nginx created
[root@k8s-master01 ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
my-nginx 3/3 3 3 8s
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
my-nginx-94fb9fc7c-2xjqc 1/1 Running 0 11s
my-nginx-94fb9fc7c-rmwtr 1/1 Running 0 11s
my-nginx-94fb9fc7c-x969q 1/1 Running 0 11s
此時已經可以訪問每一個 Pod ,為了防止後端的 Pod 掛掉之後重新建立新的 Pod ,IP地址也會隨著改變,所以要通過 Service (服務發現)來保證可靠性。
接下來建立 Service,my-nginx-svc.yaml
配置檔案如下
apiVersion: v1
kind: Service
metadata:
name: my-nginx-service # Service 名稱
spec:
type: ClusterIP # Service 型別
selector:
run: my-nginx # 標籤匹配後端 Pod
ports:
# 預設情況下,為了方便起見,`targetPort` 被設定為與 `port` 欄位相同的值。
- port: 80
targetPort: 80
建立 Service 和檢視狀態
[root@k8s-master01 ~]# kubectl apply -f my-nginx-svc.yaml
service/my-nginx-service created
[root@k8s-master01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 22d
my-nginx-service ClusterIP 10.100.13.4 <none> 80/TCP 7s
檢視 Service 詳細事件時,可以看到後端的 IP 地址都對應著每一個 Pod。
訪問 Service IP 地址實際是訪問後端的 Pod,Service 做了一個輪詢的訪問策略。
[root@k8s-master01 ~]# curl 10.100.13.4
version: v1
hostname: my-nginx-94fb9fc7c-2xjqc
[root@k8s-master01 ~]# curl 10.100.13.4
version: v1
hostname: my-nginx-94fb9fc7c-x969q
[root@k8s-master01 ~]# curl 10.100.13.4
version: v1
hostname: my-nginx-94fb9fc7c-rmwtr
NodePort 型別
利用剛剛建立好的 Deployment,這裡只需要修改 Service 檔案重新建立即可。my-nginx-svc.yaml
檔案如下
apiVersion: v1
kind: Service
metadata:
name: my-nginx-service # Service 名稱
spec:
type: NodePort # Service 型別
selector:
run: my-nginx # 標籤匹配後端 Pod
ports:
# 預設情況下,為了方便起見,`targetPort` 被設定為與 `port` 欄位相同的值。
- port: 80
targetPort: 80
# 預設情況下,為了方便起見,Kubernetes 控制平面會從某個範圍內分配一個埠號(預設:30000-32767)
nodePort: 30001
建立 Service 和檢視狀態
[root@k8s-master01 ~]# kubectl apply -f my-nginx-svc.yaml
service/my-nginx-service created
[root@k8s-master01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 22d
my-nginx-service NodePort 10.104.50.48 <none> 80:30001/TCP 6s
外部訪問埠30001
,叢集中任意一個節點的IP地址加上埠訪問即可。
由於實驗環境原因LoadBalancer 型別
和ExternalName 型別
沒有進行實驗演示,下一章更新 Ingress 基本概念及功能演示的學習筆記,歡迎關注我。