Kubernetes基礎:Service

本文的試驗環境爲CentOS 7.3,Kubernetes集羣爲1.11.2,安裝步驟參見kubeadm安裝kubernetes V1.11.1 集羣

Service 介紹

我們通過Pod、Deployment等可以將應用發佈到Kubernetes平臺中,但是如果我們如何才能訪問我們部署的應用呢?有一個辦法就是通過節點的IP加上節點的端口來訪問這個節點上的容器應用,但是如果我們有多個跨節點的相通應用時該怎麼辦呢?特別是應用發生擴容、縮容時應該如何處理,這時我們就需要利用Service來實現。

在Kubernetes中,Service是一種資源,提供了我們訪問單個或多個容器應用的能力。每個服務在其生命週期內,都擁有一個固定的IP地址和端口。每個服務對應了後臺的一個或多個Pod,通過這種方式,客戶端就不需要關心Pod所在的位置,方便後端進行方便的Pod擴容、縮容等操作。

可以通過下面的示意圖來理解Service的作用。

由此可知,服務可以被外部的客戶訪問,也可以被內部的客戶訪問。Service通過創建時指定的標籤選擇器來決定用戶的請求轉發到後臺的哪些Pods中。看一下Service創建的具體例子。

apiVersion: v1
kind: Service
metadata:
  name: tomcat-svc
spec:
  sessionAffinity: ClientIP # 該參數可以設置相同IP的請求總是定位到同一個Pod
  ports:
  - port: 8080
    targetPort: 8080
  selector:
    app: tomcat

這個例子定義了一個Service名爲tomcat-svc,端口爲8080,該服務會將用戶的請求轉發到後臺帶有app=tomcat標籤的Pods上。

kubectl get svc 

我們在測試服務是否正常的時候,不能使用ping命令。因爲Kubernetes中實現服務時,並不支持ping。因此不能使用ping的方式檢查服務是否正常,應當使用telnet或者nc等命令進行測試。

Pod中的應用訪問Service有兩種方式,一種是通過向Pod中注入環境變量的方式,這種方式缺點很明顯,必須首先創建Service,Pod內的應用才能通過環境變量訪問;另一種方式是通過DNS的方式,這種方式非常靈活。

Service 與 endpints

Endpoints 是組成Service的一組IP地址和端口資源。

kubectl get endpoints kubia

默認情況下創建Service的時候,會創建一個同名的Endpoints資源,通過kubectl descirbe svc svc-name可以看到這個服務對應的Endpoints。 如果創建Service的時候,不指定Pod的選擇器,則不會創建Endpoints資源。也可以手工創建Endpoints類型。創建時需要注意名稱要與Service的名稱一致。

apiVersion: v1
kind: Endpoints
metadata: 
  name: external-service
subsets:
  - addresses:
    - ip: 11.11.11.11
    - ip: 22.22.22.22
    ports:
    - port: 80

Service 的類型

  • NodePort
  • Loadbalance
  • Ingress

實例解析

1. 創建內部服務

創建用於內部訪問的服務很簡單,創建後服務將在生命週期內擁有固定的IP和端口。

apiVersion: v1
kind: Service
metadata:
  name: tomcat-svc
spec:
  sessionAffinity: ClientIP # 該參數可以設置相同IP的請求總是定位到同一個Pod
  ports:
  - port: 8080
    targetPort: 8080
  selector:
    app: tomcat

客戶每次鏈接Service時,都會對應到後端的一個Pod上,如果客戶需要鏈接所有的後端Pod呢,可以使用headless service。通過這種方式,Kubernetes內部的DNS服務會將Service對應的所有IP返回。

apiVersion: v1
kind: Service
metadata:
  name: tomcat-headless
spec:
  clusterIP: None
  ports:
  - port: 8080
    targetPort: 8080
  selector:
    app: tomcat

或者可以在客戶端通過程序調用Kubernetes API的方式獲取地址列表。

2. 爲外部服務創建一個內部別名

容器內部的應用要訪問外部應用時,可以直接在容器內訪問外部服務地址,也可以通過創建一個外部服務的別名進行轉發,這樣相當於將內外部調用關係解耦了,每次外部發生變化的時候,可以不用修改應用的代碼。

apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  type: ExternalName
  externalName: api.baidu.com
  ports:
  - port: 80

3. 向外部暴露內部服務

向外部暴露內部服務有三種方式:

  • NodePort
  • LoadBalancer
  • Ingress,7層負載均衡
3.1 NodePort 方式

創建這種方式的Service,內部可以通過ClusterIP進行訪問,外部用戶可以通過NodeIP:NodePort的方式單獨訪問每個Node上的實例。這種方式有很多問題,直接訪問節點的地址和端口需要在客戶端記錄很多信息,Pod發生遷移後這些信息沒辦法動態更新,節點的防火牆及節點所在網絡區域的防火牆策略配置會比較麻煩。

apiVersion: v1
kind: Service
metadata:
  name: nodeport
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30123
  selector:
    app: httpd

端口如果忽略,Kubernetes會自動生成。

$ kubectl get svc nodeport

獲取一些信息

kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type="InternalIP")].address}'

3.2 load balancer 方式

這種方式一般需要雲供應商的支持,或者一些本地資源如F5的支持。這裏不做過多介紹了。

3.3 Ingress 方式

LoadBalancer要求的IP資源較多,每個負載均衡服務都需要一個IP,Ingress可以只用一個IP,通過URL來判斷需要訪問的服務。Ingress工作在HTTP層,配置與使用更加靈活。目前爲止還是一個beta特性。

目前有很多Ingress的支持:

使用過程中的最佳實踐:

  • 總是添加 Readiness 探測
  • 不要在探測中使用關閉的邏輯

參考資料

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