1. 程式人生 > 實用技巧 >025.Kubernetes掌握Service-SVC基礎使用

025.Kubernetes掌握Service-SVC基礎使用

一 Service簡介

1.1 Service概念

Service是Kubernetes的核心概念,通過建立Service,可以為一組具有相同功能的容器應用提供一個統一的入口地址,並且將請求負載分發到後端的各個容器應用上。

1.2 Service定義詳解

  1 apiVersion: v1		#必須,api版本
  2 kind: Service		#必須,型別為Service
  3 metadata:			#必須,元資料
  4   name: string		#必須,Service名稱
  5   namespace: string		#必須,名稱空間,預設為default
  6   labels:			#自定義標籤屬性列表
7 - name: string 8 annotations: #自定義註解屬性列表 9 - name: string 10 spec: #必須,詳細描述 11 selector: [] #必須,Label Selector配置 12 type: ClusterIP #必須,Serice型別,詳見如下 13 sessionAffinity: string #虛擬服務IP地址,當選擇type=ClusterIP時,若不指定,則系統進行自動分配;當type=LoadBalancer時,需要指定 14 ports: #Service需要暴露的埠列表
15 - name: string #埠名稱 16 protocol: #埠協議,支援TCP和UDP,預設為TCP 17 port: int #服務監聽的埠號 18 targetPort: 8080 #需要轉發到後端Pod的埠號 19 nodePort: int #當spec.type=NodePort時,指定對映到物理機的埠號 20 status: #當spec.type=LoadBalancer時,設定外部負載均衡的地址,用於公有云 21 loadBalancer: #外部負載均衡器 22 ingress: #外部負載均衡器
23 ip: string #外部負載均衡器的IP地址 24 hostname: string #外部負載均衡器的主機名
spec.type:Service的型別,指定Service的訪問方式,預設為ClusterIP。
  • ClusterIP:虛擬的服務IP地址,該地址用於Kubernetes叢集內部的Pod訪問,在Node上kube-proxy通過設定的iptables規則進行轉發;
  • NodePort:使用宿主機的埠,使能夠訪問各Node的外部客戶端通過Node的IP地址和埠號就能訪問服務;
  • LoadBalancer:使用外接負載均衡器完成到服務的負載分發,需要在spec.status.loadBalancer欄位指定外部負載均衡器的IP地址,並同時定義nodePort和clusterIP,用於公有云。

二 Service基本使用

2.1 Service的基本用法

一般來說,對外提供服務的應用程式需要通過某種機制來實現,對於容器應用最簡便的方式就是通過TCP/IP機制及監聽IP和埠號來實現。 示例:定義一個提供Web服務的RC,由兩個Tomcat容器副本組成,每個容器都通過containerPort設定提供服務的埠號為8080。
[root@k8smaster01 study]# cat webapp-rc.yaml
  1 apiVersion: v1
  2 kind: ReplicationController
  3 metadata:
  4   name: webapp
  5 spec:
  6   replicas: 2
  7   template:
  8     metadata:
  9       name: webapp
 10       labels:
 11         app: webapp
 12     spec:
 13       containers:
 14       - name: webapp
 15         image: tomcat
 16         ports:
 17         - containerPort: 8080
[root@k8smaster01 study]# kubectl create -f webapp-rc.yaml [root@k8smaster01 study]# kubectl get pods -l app=webapp -o yaml | grep podIP podIP: 172.24.9.88 podIP: 172.24.9.199 [root@k8smaster01 study]# curl 172.24.9.88:8080

直接通過Pod的IP地址和埠號可以訪問到容器應用內的服務,但是Pod的IP地址是不可靠的,例如當Pod所在的Node發生故障時,Pod將被Kubernetes重新排程到另一個Node,Pod的IP地址將發生變化。 如果容器應用本身是分散式的部署方式,通過多個例項共同提供服務,就需要在這些例項的前端設定一個負載均衡器來實現請求的分發。Kubernetes中的Service就是用於解決這些問題的核心元件。 Service示例:以如上webapp應用為例,為了讓客戶端應用訪問到兩個Tomcat Pod例項,可以建立一個Service來提供服務。Kubernetes提供了一種快速的方法,即通過kubectl expose命令來建立Service。[root@k8smaster01 study]# kubectl expose rc webapp [root@k8smaster01 study]# kubectl get svc | grep -E 'NAME|webapp' NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE webapp ClusterIP 10.10.10.51 <none> 8080/TCP 45s [root@k8smaster01 study]# curl 10.10.10.51:8080 #測試訪問 提示:如上Service地址10.10.10.51:8080的訪問被自動負載分發到後端兩個Pod。 Service示例2:通過Service配置檔案暴露服務。 [root@k8smaster01 study]# vi webappsvc.yaml
  1 apiVersion: v1
  2 kind: Service
  3 metadata:
  4   name: webappservice
  5 spec:
  6   ports:
  7   - port: 8081
  8     targetPort: 8080
  9   selector:
 10     app: webapp
[root@k8smaster01 study]# kubectl create -f webappsvc.yaml [root@k8smaster01 study]# kubectl get svc | grep -E 'NAME|webappser' NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE webappservice ClusterIP 10.10.10.83 <none> 8081/TCP 22s 提示:如上Service定義中的關鍵欄位是ports和selector。本例中ports定義部分指定了Service所需的虛擬埠號為8081,由於與Pod容器埠號8080不一樣,所以需要再通過targetPort來指定後端Pod的埠號。selector定義部分設定的是後端Pod所擁有的label:app=webapp。 [root@k8smaster01 study]# curl 10.10.10.83:8081 #訪問測試
  • Service負載分發策略:RoundRobin和SessionAffinity
    • RoundRobin:輪詢模式,即輪詢將請求轉發到後端的各個Pod上。
    • SessionAffinity:基於客戶端IP地址進行會話保持的模式,即第1次將某個客戶端發起的請求轉發到後端的某個Pod上,之後從相同的客戶端發起的請求都將被轉發到後端相同的Pod上。
在預設情況下,Kubernetes採用RoundRobin模式對客戶端請求進行負載分發,同時可以通過設定service.spec.sessionAffinity=ClientIP來啟用SessionAffinity策略。這樣,同一個客戶端IP發來的請求就會被轉發到後端固定的某個Pod上了。 通過Service的定義,Kubernetes實現了一種分散式應用統一入口的定義和負載均衡機制。Service還可以進行其他型別的設定,例如設定多個埠號、直接設定為叢集外部服務,或實現為Headless Service(無頭服務)模式。

2.2 多埠Service

有時一個容器應用也可能提供多個埠的服務,那麼在Service的定義中也可以相應地設定為將多個埠對應到多個應用服務。 示例1:如下,Service設定了兩個埠號,並且為每個埠號都進行了命名。 [root@k8smaster01 study]# vi twoportservice.yaml
  1 apiVersion: v1
  2 kind: Service
  3 metadata:
  4   name: webapp
  5 spec:
  6   ports:
  7   - port: 8080
  8     targetPort: 8080
  9     name: web
 10   - port: 8005
 11     targetPort: 8005
 12     name: management
 13   selector:
 14     app: webapp
[root@k8smaster01 study]# vi kubednsservice.yaml
  1 apiVersion: v1
  2 kind: Service
  3 metadata:
  4   name: kube-dns
  5   namespace: kube-system
  6   labels:
  7     k8s-app: kube-dns
  8     kubernetes.io/cluster-service: "true"
  9     kubernetes.io/name: "KubeDNS"
 10 spec:
 11   selector:
 12     k8s-app: kube-dns
 13   clusterIP: 169.169.0.100
 14   ports:
 15   - name: dns
 16     port: 53
 17     protocol: UDP
 18 
 19   - name: dns-tcp
 20     port: 53
 21     protocol: TCP

2.3 外部服務Service

在某些環境中,應用系統需要將一個外部資料庫、另一個叢集或Namespace中的服務作為服務的後端,則可通過建立一個無Label Selector的Service來實現。 [root@k8smaster01 study]# vi noselectorservice.yaml
  1 apiVersion: v1
  2 kind: Service
  3 metadata:
  4   name: my-service
  5 spec:
  6   ports:
  7   - protocol: TCP
  8     port: 80
  9     targetPort: 80
[root@k8smaster01 study]# kubectl create -f noselectorservice.yaml 如上定義建立的是一個不帶標籤選擇器的Service,即無法選擇後端的Pod,系統不會自動建立Endpoint,因此需要手動建立一個和該Service對應的Endpoint,用於指向實際的後端訪問地址。 如下所示的Endpoint的定義檔案: [root@k8smaster01 study]# vi noselectorendpoint.yaml
  1 apiVersion: v1
  2 kind: Endpoints
  3 metadata:
  4   name: my-service
  5 subsets:
  6 - addresses:
  7   - IP: 47.96.145.131
  8   ports:
  9   - port: 80
[root@k8smaster01 study]# kubectl create -f noselectorendpoint.yaml [root@k8smaster01 study]# kubectl get svc | grep -E 'NAME|my-service' NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-service ClusterIP 10.10.10.211 <none> 80/TCP 3s [root@k8smaster01 study]# curl 10.10.10.211 提示:如上所示,訪問沒有標籤選擇器的Service和帶有標籤選擇器的Service一樣,請求將會被路由到由使用者手動定義的後端Endpoint上。

三 Headless Service

3.1 無頭服務簡介

在某些應用場景中,若需要人為指定負載均衡器,不使用Service提供的預設負載均衡的功能,或者應用程式希望知道屬於同組服務的其他例項。Kubernetes提供了Headless Service來實現這種功能,即不為Service設定ClusterIP(入口IP地址),僅通過Label Selector將後端的Pod列表返回給呼叫的客戶端。 此場景中,Service就不再具有一個特定的ClusterIP地址,對其進行訪問將獲得包含Label“app=nginx”的全部Pod列表,然後客戶端程式自行決定如何處理這個Pod列表。 例如,StatefulSet就是使用Headless Service為客戶端返回多個服務地址的。 對於“去中心化”類的應用叢集,Headless Service非常適合。

3.2 Nginx場景實驗

通過對Headless Service搭建Nginx叢集,從而自動實現應用叢集的建立。 [root@k8smaster01 study]# vi nginx-service.yaml #建立Service
  1 apiVersion: v1
  2 kind: Service
  3 metadata:
  4   labels:
  5     name: nginx-svc
  6   name: nginx-svc
  7 spec:
  8   ports:
  9   - protocol: TCP
 10     port: 80
 11     targetPort: 80
 12   selector:
 13     name: nginx-demo			#定義selector
 14   clusterIP: None
[root@k8smaster01 study]# kubectl create -f nginx-service.yaml [root@k8smaster01 study]# vi nginx-deployment.yaml
  1 apiVersion: apps/v1
  2 kind: Deployment
  3 metadata:
  4   labels:
  5     name: nginx-demo
  6   name: nginx-demo
  7 spec:
  8   replicas: 2
  9   selector:
 10     matchLabels:
 11       name: nginx-demo
 12   template:
 13     metadata:
 14       labels:
 15         name: nginx-demo
 16     spec:
 17       containers:
 18       - name: nginx
 19         image: nginx:1.7.9
 20         ports:
 21         - containerPort: 80
 22           name: web
[root@k8smaster01 study]# kubectl create -f nginx-deployment.yaml [root@k8smaster01 study]# kubectl create -f nginx-service.yaml [root@k8smaster01 study]# kubectl get svc -o wide [root@k8smaster01 study]# kubectl get pods -o wide [root@k8smaster01 study]# nslookup nginx-svc.default.svc.cluster.local 10.10.190.170 提示:由上可知,通過解析SVC的地址,直接解析出來的為Pod的IP。