天天看點

不背鍋運維:粗講:K8S的Service及分享現撸案例

作者:不背鍋運維

Service存在的意義

Kubernetes中的Service是一種網絡抽象,用于将一組Pod暴露給其他元件,例如其他Pod或外部使用者。Service可以作為一個負載均衡器,為一組Pod提供單一的IP位址和DNS名稱,并通過選擇器來将流量路由到這些Pod。

Services的存在有以下幾個意義:

  1. 透明的服務發現: Kubernetes使用Service作為一種透明的服務發現機制。使用Service可以将Pod隐藏在後面,這樣其他元件可以使用Service的DNS名稱來通路它們,而不需要知道Pod的實際IP位址和端口号。
  2. 負載均衡: Service可以将流量路由到一組Pod上,并使用标簽選擇器将流量均勻地配置設定給這些Pod。這使得可以輕松地進行水準擴充,以滿足不斷增長的負載。
  3. 穩定的IP位址: Kubernetes為每個Service配置設定一個穩定的IP位址,這個IP位址與Pod的生命周期無關。這意味着可以在Pod啟動和停止時保持穩定的服務位址,并且無需手動更改任何配置。
  4. 外部通路: 通過将Service類型設定為NodePort或LoadBalancer,可以将Service暴露給外部使用者或外部負載均衡器。這使得可以輕松地将Kubernetes叢集與外部服務和使用者內建。

總之,Service是Kubernetes中非常重要的一部分,可以提供透明的服務發現、負載均衡、穩定的IP位址和外部通路。在實際生産環境中,使用Service是建構可靠和可擴充應用程式的關鍵。

Pod、Service、Label的關系

在Kubernetes中,Pod是最小的可部署單元,它是由一個或多個容器組成的。Pod提供了一個運作環境,其中包含應用程式所需的資源,如存儲、網絡和命名空間。

Service是Kubernetes中的一種抽象,用于定義一組Pod,這些Pod執行相同的任務,并且可以通過Service的IP位址和端口号進行通路。Service允許應用程式通過固定的IP和端口号進行通路,而不必考慮後端Pod的IP和端口号。

在Kubernetes中,Pod和Service之間有一種緊密的關系。Service使用标簽選擇器來确定哪些Pod應該成為它的後端。一旦Service選擇了一組Pod,它将為這些Pod配置設定一個固定的IP和端口号,這些IP和端口号将用于通路這些Pod。

當Pod被建立或删除時,Service會自動更新它的後端清單。這意味着當Pod被添加到Service的後端時,它們将自動成為Service的一部分,并且可以通過Service的IP和端口号進行通路。同樣地,當Pod被删除時,它們将自動從Service的後端清單中删除,這樣通路它們的請求就不會被發送到已經不存在的Pod上。

是以,Pod和Service之間的關系是非常緊密的,Service為一組Pod提供了一個穩定的網絡位址,并且自動更新它的後端清單以確定通路這些Pod時的高可用性和可靠性。

在Kubernetes中,Pod、Service和标簽之間有着密切的關系。标簽(Label)是Kubernetes中的一種機制,它允許你為對象添加任意的中繼資料,例如版本、環境、用途等等。

Pod可以使用标簽進行分類和分組,通過給Pod打上特定的标簽,可以友善地對它們進行選擇和管理。同樣地,Service也可以使用标簽選擇器來選擇具有特定标簽的Pod作為後端。标簽可以被應用于任何Kubernetes對象,包括Pod、Service、ReplicaSet等等。

當建立一個Service時,可以使用标簽選擇器來指定Service所選取的Pod的标簽。例如,可以通過以下方式建立一個Service,它将選擇所有标有app=goweb-demo的Pod作為它的後端:

goweb-demo-v1.yaml

apiVersion: v1
kind: Service
metadata:
  name: goweb-demo
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8090
  selector:
    app: goweb-demo
           

在這個例子中,Service使用selector字段來選擇具有app=goweb-demo标簽的Pod作為它的後端。這意味着隻有那些标記為app=goweb-demo的Pod才能被Service通路。

标簽是Kubernetes中非常重要的一個概念,它使得對Pod和Service的選擇和管理變得更加靈活和高效。通過使用标簽,可以輕松地對應用程式的不同版本、環境和用途進行分類和分組,并根據需要建立相應的Pod和Service來滿足應用程式的需求。

Service的通路類型

Kubernetes中的Service對象可以指定不同的通路類型,以便在叢集内和叢集外提供不同級别的通路。 下面是Kubernetes中Service的三種通路類型:

  1. ClusterIP:預設的通路類型,将建立一個虛拟IP位址,代表一組後端Pod。隻能從叢集内部通路該Service,外部無法通路。
  2. NodePort:将在每個Node上公開一個端口,并将該端口重定向到Service。可以通過Node的IP位址和該端口通路該Service。可以從叢集外部通路該Service,但需要在防火牆中打開該端口。
  3. LoadBalancer:将在外部建立一個負載均衡器,并将流量路由到Service。負載均衡器可以将流量路由到多個後端Pod,以提高可用性和性能。需要使用外部負載均衡器的雲平台支援,例如AWS ELB或GCP GCLB。

另外,還有一種名為ExternalName的通路類型,可以将Service映射到叢集外部的DNS名稱,而不是叢集内部的Pod。該通路類型通常用于将Service映射到外部服務,例如資料庫或API網關。

可以使用kubectl指令行或YAML檔案來指定Service的通路類型和其他配置。例如,在YAML檔案中,可以将Service的類型指定為type: ClusterIP、type: NodePort或type: LoadBalancer,具體取決于需要提供的通路級别。

實戰開撸:案例1

  1. 準備Deployment yaml配置檔案
kubectl create deployment goweb-demo --image=192.168.11.247/web-demo/goweb-demo:20221229v3 --replicas=3 --dry-run=client -o yaml > my-deployment.yaml
           

上述指令将使用名為“192.168.11.247/web-demo/goweb-demo:20221229v3”的鏡像建立一個名為“goweb-demo”的Deployment,并設定3個副本。--dry-run=client選項使kubectl隻檢查配置檔案的文法,而不會實際建立Deployment。-o yaml選項指定輸出格式為YAML,并将其重定向到my-deployment.yaml檔案中。下面是我們得到的my-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: goweb-demo
  name: goweb-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: goweb-demo
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: goweb-demo
    spec:
      containers:
      - image: 192.168.11.247/web-demo/goweb-demo:20221229v3
        name: goweb-demo
        resources: {}
status: {}
           

編輯my-deployment.yaml檔案以更改Deployment的任何其他配置選項。例如,您可以為Deployment指定标簽,設定容器端口,配置健康檢查等。下面是我調整後的my-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: goweb-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: goweb
  template:
    metadata:
      labels:
        app: goweb
    spec:
      containers:
      - name: goweb-container
        image: 192.168.11.247/web-demo/goweb-demo:20221229v3
           
  1. 建立Deployment
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl apply -f my-deployment.yaml
deployment.apps/goweb-demo created
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get deployments
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
goweb-demo   3/3     3            3           8m25s
tantianran@test-b-k8s-master:~/goweb-demo$ 
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pod
NAME                          READY   STATUS    RESTARTS   AGE
goweb-demo-654c45b968-9wcr8   1/1     Running   0          5s
goweb-demo-654c45b968-jsw8z   1/1     Running   0          5s
goweb-demo-654c45b968-mngq7   1/1     Running   0          5s
tantianran@test-b-k8s-master:~/goweb-demo$ 
           
  1. 準備Service yaml配置檔案 現在使用go語言開發的web demo已經跑起來了,而且跑了3個pod副本,接下來就要對外提供通路,我的goweb demo應用對外提供通路的端口是8090。

在指令行下建立一個将容器端口8090映射到Node的端口30080上的Service對象,可以使用以下指令:

kubectl create service nodeport goweb --tcp=80:8090 --node-port=30080
           

其中,goweb是Service對象的名稱,預設也是用此名稱與deployment中定義的label "app: goweb" 保持一緻,--tcp=80:8090表示将容器端口8090映射到Service的端口80上,--node-port=30080表示将Service的端口30080映射到Node的端口30080上。

tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
goweb        NodePort    10.111.227.27   <none>        80:30080/TCP   5s    app=goweb
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        96d   <none>
tantianran@test-b-k8s-master:~/goweb-demo$ 
           

使用--dry-run=client -o yaml得到my-service.yaml 檔案,然後使用kubectl apply指令将其應用到叢集中

kubectl create service nodeport goweb --tcp=80:8090 --node-port=30080 --dry-run=client -o yaml > my-service.yaml 
           

my-service.yaml

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: goweb
  name: goweb
spec:
  ports:
  - name: 80-8090
    nodePort: 30080
    port: 80
    protocol: TCP
    targetPort: 8090
  selector:
    app: goweb
  type: NodePort
status:
  loadBalancer: {}
           

在這個示例中,我們建立了一個名為“goweb”的服務,它将流量路由到标簽為“app=goweb”的Pod上。該服務類型被設定為NodePort,并指定了端口号為30080。服務監聽80端口,将流量轉發到Pod上的8090端口。

  1. 建立service
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl apply -f my-service.yaml 
service/goweb created
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
goweb        NodePort    10.104.241.81   <none>        80:30080/TCP   7s    app=goweb
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        96d   <none>

tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get ep
NAME         ENDPOINTS                                                  AGE
goweb        10.244.240.19:8090,10.244.240.38:8090,10.244.240.56:8090   16s
kubernetes   192.168.11.13:6443                                         96d
tantianran@test-b-k8s-master:~/goweb-demo$ 
           

要在叢集外通路該服務,可以使用任何節點的IP位址和NodePort端口号。例如,如果節點的IP位址為192.168.11.14,則可以使用http://192.168.1.14:30080通路該服務。

實戰開撸:案例2

在案例1中,都是使用yaml進行建立,并且分享了如何快速得到一個yaml。那麼本案例2,全程在kubectl指令行下進行建立。
  1. 建立deployment 要建立一個名為 nginx-deployment 的 Deployment 并使用最新版本的 nginx 鏡像
kubectl create deployment my-deployment001 --image=192.168.11.247/web-demo/goweb-demo:20221229v3 --replicas=3
           
  1. 暴露 Deployment 的端口
kubectl expose deployment my-deployment001 --port=80 --target-port=8090 --type=NodePort
           

其中,my-deployment001 是你要暴露端口的 Deployment 的名稱,80 是你要使用的 Service 的端口,8090 是你要将流量路由到的 Pod 的端口,--type 是 Service 的類型,通常是 ClusterIP、NodePort 或 LoadBalancer。上面的指令中,将建立一個類型為 NodePort 的 Service,并将其暴露在随機配置設定的端口上。

檢視Service

tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get svc my-deployment001
NAME               TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
my-deployment001   NodePort   10.109.238.29   <none>        80:32537/TCP   3m48s
           

這将列出 Service 的詳細資訊,包括 Service 的 IP 位址、端口和類型,上面随機配置設定的端口是32537。

這樣,就已經成功地建立了一個 Deployment 并将其暴露在一個端口上。現在,可以使用 Service 的 IP 位址和端口來通路應用程式。如果你使用的是 NodePort 類型的 Service,你可以在任何節點上使用 Service 的節點 IP 位址和端口來通路它。如果你使用的是 LoadBalancer 類型的 Service,Kubernetes 會在你的雲提供商中自動建立一個負載均衡器,并将流量路由到你的 Service。

打開浏覽器,通路看看:

最後的總結

Kubernetes (k8s) Service是一個抽象層,它為一組Pod提供了一個穩定的通路位址和DNS名稱。在k8s中,Service是通過控制器和負載均衡器來實作的,它可以将流量分發給後端Pod執行個體,并確定它們的可用性和可靠性。下面是對Kubernetes Service的總結:

  1. Service類型 k8s Service有四種類型,分别是ClusterIP、NodePort、LoadBalancer和ExternalName。不同類型的Service有不同的用途,選擇合适的類型非常重要。
  • ClusterIP:這是最常用的類型。它為Pod提供了一個穩定的虛拟IP位址,隻能從叢集内部通路。
  • NodePort:它為Pod提供了一個靜态的端口号,可以通過任何節點的IP位址和該端口通路Service。它将請求轉發到相應的Pod,支援外部通路。
  • LoadBalancer:這種類型需要雲服務商提供的負載均衡器支援。它為Service配置設定一個公共IP位址,并将流量負載均衡到Pod中。
  • ExternalName:它将Service映射到一個外部位址或DNS名稱,而不是選擇Pod。它通常用于将k8s内部的Service與外部服務連接配接起來。
  1. Service Selector Service Selector是用來選擇要将流量轉發到哪個Pod的标簽。每個Service都會指定一個或多個Selector,用于确定應該選擇哪些Pod。在建立Service時,可以指定标簽選擇器以選擇相關Pod。
  2. 端口 Service的端口指的是該Service的監聽端口。Service可以監聽多個端口,每個端口都可以關聯一個或多個後端Pod。端口也可以分為兩個類型:端口和目标端口。端口是Service監聽的端口,而目标端口是後端Pod的端口。
  3. 負載均衡 k8s Service可以通過三種負載均衡算法來将流量配置設定到後端Pod中:
  • Round Robin:這是最常見的負載均衡算法。它按順序配置設定流量到每個Pod,然後循環下去。
  • Session Affinity:這種算法會将同一用戶端的所有請求都發送到同一個後端Pod中。這有助于維護狀态,并確定在會話期間一緻性。
  • IPVS:這是一種進階的負載均衡算法,它使用Linux核心中的IPVS子產品來實作流量分發。
  1. DNS k8s Service通過DNS來提供一個穩定的通路位址。在建立Service時,k8s會将其關聯的Pod的IP位址注冊到k8s叢集的DNS中,并使用Service名稱和Namespace作為DNS條目。這樣,用戶端可以通過Service名稱和命名空間來通路該Service,k8s DNS将解析這個名稱并将其映射到Service關聯的Pod IP位址。

在k8s中,每個Pod都有一個唯一的IP位址,但是這個IP位址在Pod重新排程或者Pod數量發生變化時可能會發生變化。這種變化可能會導緻用戶端連接配接中斷,是以k8s Service提供了一個穩定的通路位址,使得用戶端可以通過Service名稱來通路Pod而不需要關心其IP位址的變化。這種方式也使得k8s Service非常适合于微服務架構,因為它可以将多個Pod組合成一個邏輯單元,并通過一個穩定的通路位址對外提供服務。

本文轉載于(喜歡的盆友關注我們):https://mp.weixin.qq.com/s/9HBcSLkcxLZ8dA-0kqtLcA

繼續閱讀