【九】Kubernetes 之 Service 概念圖文講解及功能演示

Service 概念

Kubernetes Service 定義了這樣一種抽象:邏輯上的一組 Pod,一種可以訪問它們的策略 —— 通常稱爲微服務

Service 通常是通過 Label Selector,也就是 Service 通過標籤選擇的方式匹配一組 Pod 對外提供訪問的機制。

image-20210610160403405

解釋上圖具體實現過程:

首先、定義一個 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地址,只能被集羣內部訪問。(常用)

image-20210610172350273

NodePort: 通過每個節點上的 IP 和靜態端口(NodePort)暴露服務,提供對外訪問。也就是說我們可以通過集羣中任意一個節點 IP 地址和端口來訪問後的 Pod 應用。(常用)

image-20210610173828868

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 壓力巨大。

image-20210615150001445

iptables 代理模式

通過如下圖可以看到,所有的訪問都是通過 iptables 來完成,而不需要通過 Kube-proxy 來調度,這樣的話,訪問速度加快,而 Kube-proxy 壓力減少,穩定性就會提升。

image-20210615151737681

IPVS 代理模式

IPVS 代理模式跟 iptables 代理模式中的區別只是把 iptables 變成 IPVS ,其他的沒有變。IPVS 是在內核空間中工作,意味着通信的延遲更短,性能更好。如果沒有安裝 IPVS 模塊,則 kube-proxy 將退回到以 iptables 代理模式運行。

image-20210615152354572

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 (服務發現)來保證可靠性。

image-20210616104350125

接下來創建 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。

image-20210616110257437

訪問 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

image-20210616111754546

外部訪問端口30001,集羣中任意一個節點的IP地址加上端口訪問即可。

image-20210616112043680

由於實驗環境原因LoadBalancer 類型ExternalName 類型沒有進行實驗演示,下一章更新 Ingress 基本概念及功能演示的學習筆記,歡迎關注我。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章