Kubernetes Service


基本概念

當應用由單體架構轉向微服務架構時,應用被拆成很多小的互相協作的微服務,每個服務會以多個副本運行,副本數量會隨着系統所需的處理能力進行變化,這就是微服務的伸縮性。 微服務的負載均衡器對實現伸縮性起了十分重要的作用。

Service是Kubernetes最重要的資源對象。Kubernetes中的Service對象可以對應微服務架構中的微服務。Service定義了服務的訪問入口,服務的調用者Pod通過這個地址訪問Service后端的Pod副本實例。 Service通過Label Selector同后端的Pod副本建立關系,Replication Controller保證后端Pod副本的數量,也就是保證服務的伸縮性。

service代理模式

我們知道,kubernetes的node節點運行的時候,需要啟動兩個進程,分別是kubelet和kube-proxy。其中kubeproxy實際上就是一個智能的負載均衡器。發送到service的請求由kube-proxy轉發到后端在的某個pod實例上。

kubernetes為每個service分配一個全局唯一的虛擬IP,叫做ClusterIP,這樣在整個集群中,服務的調用者都通過ClusterIP和服務進行通信。

在Service的整個生命周期內Service的名稱和ClusterIP保持不變,因此通過引入域名服務將Service的名稱和ClusterIP建立DNS域名映射,服務的調用者可以通過使用服務的名稱來訪問服務。

kube-proxy作為一個集群內部的負載均衡器,支持多種代理模式:

  • userspace代理模式
  • iptables代理模式
  • ipvs代理模式

userspace代理模式

這是kubernetes 1.1版本之前支持的模式,當前基本已棄用。

這種模式下,kube-proxy會watch kube-apiserver對Service對象和Endpoints對象的添加和移除。 並在所有node上為每一個service打開一個本地的隨機端口。然后在每個node上配置iptables規則來捕獲到達service的請求,並將其重定向至本地為該service打開的隨機端口,完成代理訪問。

iptables代理模式

這是當前kubernetes默認使用的service的代理模式。

和userspace模式一樣,其也使用iptables規則來捕獲對cluster ip的訪問,但是它會通過iptables的dnat規划直接請請求轉發至具體的backend pod,而不需要在node為每個service打開一個本地隨機端口。相對於userspace,其擁有更好的轉發性能,同時如果初始轉發的pod失敗沒有響應,Iptables代理能夠自動的重試另一個pod。

ipvs代理模式

ipvs模式在kubernetes 1.8版本開始引入,1.11版本正式GA。不過要啟用該模式,仍然需要修改kube-proxy配置。

這種模式通過ipvs實現轉輸層的負載均衡。相對於iptables代理模式,其優勢如下:

  • 為大型集群提供了更好的可擴展性和性能
  • 支持比iptables更復雜的復制均衡算法(最小負載、最少連接、加權等等)
  • 支持服務器健康檢查和連接重試等功能

ipvs也依賴iptables,ipvs會使用iptables進行包過濾、SNAT、masquared(偽裝)。

配置Service

kubrenetes支持四種類型的service,可以通過ServicesTypes指定:

  • ClusterIP:僅僅使用一個集群內部的地址,這也是默認值,使用該類型,意味着,service只能在集群內部被訪問
  • NodePort:在集群內部的每個節點上,都開放這個服務。可以在任意的 :NodePort地址上訪問到這個服務
  • LoadBalancer:這是當kubernetes部署到公有雲上時才會使用到的選項,是向雲提供商申請一個負載均衡器,將流量轉發到已經以NodePort形式開放的service上。
  • ExternalName:ExternalName實際上是將service導向一個外部的服務,這個外部的服務有自己的域名,只是在kubernetes內部為其創建一個內部域名,並cname至這個外部的域名。

下面示例創建一個nginx的deployment,包含三個pod,后面所有創建的service都會與之關聯:

創建一個nginx的Deployment:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
  spec:
    containers:
      - name: nginx
        image: nginx
        ports:
          - containerPort:80

可以通過如下指令查看創建的pod:

kubectl get pod -l app=nginx -o wide

創建ClusterIP類型的Service

普通ClusterIP類型的Service

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
    - port: 80 
      targetPort: 80
  selector:
    app: nginx

需要說明下三個端口的意義,其中port表示service監聽的端口,targetPort表示后端Pod監聽的端口,nodePort表示如果要將service暴露出來,外部訪問的端口。不指定ClusterIP,則默認使用ClusterIP方式創建Service,並自動生成一個ClusterIP。可以通過查看service來看到ClusterIP。

查看service:

kubectl get svc nginx

指定ClusterIP的Service

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  clusterIP: 10.254.0.100
  ports:
    - port: 80 
      targetPort: 80
  selector:
    app: nginx

默認情況下,ClusterIP的值是由k8s自動創建的,我們可以通過ClusterIP指定,在創建k8s中的dns的時候會用到。

headless service

創建一個headless service,即指定ClusterIP為None,這個時候,創建的Service沒有IP地址。

我們知道,在默認情況下創建的service,k8s會自動為其生成一個ip地址,並在dns中生成一條域名記錄指向該ip,當外部有請求到達時,由kubeproxy組件接受請求並轉發到后端的pods。而當ClusterIP為None時,k8s並不會為service生成一個IP,但是仍然會往dns里生成一條域名記錄,而這個域名的值會直接指向service所關聯的pods的IP地址,有多個pods,就會生成多條A記錄。這樣的好處是,當有請求到達時,會直接請求到指定的pods,而無需再通過kubeproxy轉發,從而提高了響應效率。缺點是負載均衡依賴於dns輪循,沒有更靈活的均衡方案。

示例:

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  clusterIP: None
  ports:
    - port: 80 
      targetPort: 80
  selector:
    app: nginx

創建NodePort類型的service

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: NodePort
  ports:
    - port: 80 
      targetPort: 80
      nodePort: 80
  selector:
    app: nginx

創建ExternalName類型的service

下面直接給個示例:

kind: Service
apiVersion: v1
metadata:
  name: database
spec:
  type: ExternalName
  externalName: database.example.com

創建一個service名為database,指向一個外部的服務,這個服務的域名為database.example.com。我們在集群內部訪問database.default.svc可直接跳轉至database.example.com。實際就是個dns別名。

擴展service

sessionAffinity

主要是用於基於userspace(當前基本已廢棄)和iptables轉發模式下的pod調度算法,默認為none,此時的調度算法為輪詢, 可通過將設置為ClientIP以實現基於客戶端ip的親和性調度,但也會導致負載不均。

apiVersion: v1
kind: Service
metadata:
  name: nginx-app
  labels:
    app: nginx-app
    tier: nginx-app
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nginx-app
    tier: nginx-app
  type: LoadBalancer
  sessionAffinity: ClientIP

externalTrafficPolicy

默認情況下,目標容器看到的源Ip不是客戶端的源ip,如果要保留客戶端的源ip,可以配置externalTrafficPolicy選項如下:

  • service.spec.externalTrafficPolicy - 如果這個服務需要將外部流量路由到 本地節點或者集群級別的端點,那么需要指明該參數。存在兩種選項:Cluster(默認)和 Local。 Cluster隱藏源 IP 地址,可能會導致第二跳(second hop)到其他節點,但是全局負載效果較好。Local保留客戶端源 IP 地址,避免 LoadBalancer 和 NodePort 類型服務的第二跳,但是可能會導致負載不平衡。
  • service.spec.healthCheckNodePort - 定義服務的 healthCheckNodePort (數字端口號)。 如果沒有聲明,服務 API 后端會用分配的 nodePort 創建 healthCheckNodePort。如果客戶端 指定了 nodePort,則會使用用戶自定義值。這只有當類型被設置成 LoadBalancer並且 externalTrafficPolicy被設置成 Local時,才會生效。

ExternalIP

kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 9376
  externalIPs:
  - 80.11.12.10

當從集群外部請求80.11.12.10這個Ip時,如果集群收到該請求,就會將流量轉發至my-service這個service。但這里有個前提, 即80.11.12.10這個Ip的流量能正確的路由到這個service上來,而這部分路由的功能kubernetes並不保證,需要集群管理人員自行做路由處理。

一般來講,externalIPs通常會與loadbalancer類型的service配合使用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM