天天看點

Kubernetes系列之Service

作者:程式設計識堂
小夥伴兒們,如果覺得文章幹貨滿滿,歡迎加入公衆号【程式設計識堂】,更多幹貨等你們來哦!

簡介

通過上期的學習,我們已經能夠通過Deployment來建立一組Pod來提供高可用性服務。雖然每 個Pod都會配置設定一個單獨的Pod IP,然而卻存在如下兩問題:

  • Pod IP僅僅是叢集内可見的虛拟IP,外部無法通路。
  • Pod IP會随着Pod的銷毀而消失,當Deployment對Pod進行動态伸縮時,Pod IP可能随時随地都會變化,這樣對于我們通路這個服務帶來了難度。

是以,Kubernetes中的Service對象就是解決以上問題的實作服務發現核心關鍵。

Service類型

ClusterIp:預設類型,自動配置設定一個僅 Cluster 内部可以通路的虛拟 IP

NodePort:在ClusterIP基礎上為 Service在每台機器上綁定一個端口,這樣就可以通過 NodePort 來通路該服務

LoadBalancer:在 NodePort 的基礎上,借助 cloud provider 建立一個外部負載均衡器,并将請求轉發到NodePort。是付費服務,而且價格不菲。

ExternalName:把叢集外部的服務引入到叢集内部來,在叢集内部直接使用。沒有任何類型代理被建立, 這隻有 kubernetes 1.7 或更高版本的 kube-dns 才支援

Service和Pods

Kubernetes的Pods是有生命周期的。他們可以被建立,而且銷毀不會再啟動。如果您使用Deployment來運作您的應用程式,則它可以動态建立和銷毀Pod。

一個Kubernetes的Service是一種抽象,它定義了一組Pods的邏輯集合和一個用于通路它們的政策 - 有的時候被稱之為微服務。一個Service的目标Pod集合通常是由Label Selector 來決定的 。

Pod 的 IP 位址,它實際路由到一個固定的目的地,Service 的 IP實際上不能通過單個主機來進行應答。相反,我們使用 iptables(Linux 中的資料包處理邏輯)來定義一個虛拟IP位址(VIP),它可以根據需要透明地進行重定向。當用戶端連接配接到 VIP 時,它們的流量會自動地傳輸到一個合适的 Endpoint、環境變量和 DNS,實際上會根據 Service 的 VIP 和端口來進行填充。

kube-proxy代理模式

kube-proxy支援三種代理模式: 使用者空間,iptables和IPVS;它們各自的操作略有不同。

Userspace代理模式

Client Pod要通路Server Pod時,它先将請求發給本機核心空間中的service規則,由它再将請求轉給監聽在指定套接字上的kube-proxy,kube-proxy處理完請求,并分發請求到指定Server Pod後,再将請求遞交給核心空間中的service,由service将請求轉給指定的Server Pod。由于其需要來回在使用者空間和核心空間互動通信,是以效率很差 。

iptables代理模式

當一個用戶端連接配接到一個 VIP,iptables 規則開始起作用。一個 backend 會被選擇(或者根據會話親和性,或者随機),資料包被重定向到這個backend。不像 userspace 代理,資料包從來不拷貝到使用者空間,kube-proxy 不是必須為該 VIP 工作而運作,并且用戶端 IP 是不可更改的。當流量打到 Node 的 端口上,或通過負載均衡器,會執行相同的基本流程,但是在那些案例中用戶端 IP 是可以更改的。

IPVS代理模式

在大規模叢集(例如10,000個服務)中,iptables 操作會顯着降低速度。IPVS 專為負載平衡而設計, 并基于核心内哈希表。是以,您可以通過基于 IPVS 的 kube-proxy 在大量服務中實作性能一緻性。同 時,基于 IPVS 的 kube-proxy 具有更複雜的負載平衡算法(最小連接配接,局部性,權重,持久性)。

使用 ipvs 代理。在 Kubernetes v1.0 版本, Service 是 “4層”(TCP/UDP over IP)概念。 在 Kubernetes v1.1 版本,新增了Ingress API(beta 版),用來表示 “7層”(HTTP)服務 。

這種模式,kube-proxy 會監視 Kubernetes Service 對象和 Endpoints ,調用 netlink 接口以相應地建立 ipvs 規則并定期與 Kubernetes Service 對象和 Endpoints 對象同步 ipvs 規則,以確定 ipvs 狀态與期望一 緻。通路服務時,流量将被重定向到其中一個後端 Pod與 iptables 類似,ipvs 于 netfilter 的 hook 功 能,但使用哈希表作為底層資料結構并在核心空間中工作。這意味着 ipvs 可以更快地重定向流量,并且在同步代理規則時具有更好的性能。此外,ipvs 為負載均衡算法提供了更多選項。

注: 在 Kubernetes 1.14 版本開始預設使用 ipvs 代理。

ClusterIP

類型為ClusterIP的service,這個service有一個Cluster-IP,其實就一個VIP。具體實作原理依靠 kubeproxy元件,通過iptables或是ipvs實作。 clusterIP 主要在每個 node 節點使用 iptables,将發向 clusterIP 對應端口的資料,轉發到 kube-proxy 中。然 後 kube-proxy 自己内部實作有負載均衡的方法,并可以查詢到這個 service 下對應 pod 的位址和端 口,進而把 資料轉發給對應的 pod 的位址和端口

這種類型的service 隻能在叢集内通路。

使用鏡像

docker pull tomcat:9.0.20-jre8-alpine           

部署Service

service/clusteripdemo.yml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: clusteripdemo
  labels:
    app: clusteripdemo
spec:
  replicas: 1
  template:
    metadata:
      name: clusteripdemo
      labels:
        app: clusteripdemo
    spec:
      containers:
        - name: clusteripdemo
          image: tomcat:9.0.20-jre8-alpine
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080
      restartPolicy: Always
  selector:
    matchLabels:
      app: clusteripdemo

---
apiVersion: v1
kind: Service
metadata:
  name: clusterip-svc
spec:
  selector:
    app: clusteripdemo
  ports:
    - port: 8080
  type: ClusterIP           

注:一個Service的目标Pod集合通常是由Label Selector 來決定的,即Service模闆spec.selector.app 與spec.template.metadata.labels.app 對應的值必須一樣

資源與資源之間用三個中劃線隔開 ---

運作Service

#運作服務
kubectl apply -f clusteripdemo.yml
# 查詢pod
kubectl get pod -o wide
#查詢 deployment
kubectl get deploy
#查詢service
kubectl get svc
#通路服務
curl 10.1.178.19:8080
#删除服務
kubectl delete -f clusteripdemo.yml           
Kubernetes系列之Service

NodePort

我們的場景不全是叢集内通路,也需要叢集外業務通路。那麼ClusterIP就滿足不了了。NodePort當然是其中的一種實作方案。nodePort 的原理在于在 node 上開了一個端口,将向該端口的流量導入到 kube-proxy,然後由 kube-proxy 進一步到給對應的 pod 。

使用鏡像

docker pull tomcat:9.0.20-jre8-alpine           

部署service

service/nodeportdemo.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodeportdemo
  labels:
    app: nodeportdemo
spec:
  replicas: 1
  template:
    metadata:
      name: nodeportdemo
      labels:
        app: nodeportdemo-test
    spec:
      containers:
        - name: nodeportdemo
          image: tomcat:9.0.20-jre8-alpine
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080
      restartPolicy: Always
  selector:
    matchLabels:
      app: nodeportdemo-test
---
apiVersion: v1
kind: Service
metadata:
  name: nodeport-src
spec:
  selector:
    app: nodeportdemo-test
  ports:
    - port: 8081 #叢集内其他服務通路的端口号
      targetPort: 8080 # pod容器的端口号
      nodePort: 30008 #叢集外部通路的端口号
  type: NodePort           

運作service

#運作服務
kubectl apply -f nodeportdemo.yml
#檢視服務
kubectl get svc
#通路服務
curl 10.1.58.136:8081
#浏覽器通路tomcat均可以通路
http://192.168.150.128:30008/
http://192.168.150.129:30008/
http://192.168.150.130:30008/
http://192.168.150.131:30008/           
Kubernetes系列之Service
Kubernetes系列之Service

LoadBalancer

LoadBalancer類型的service 是可以實作叢集外部通路服務的另外一種解決方案。不過并不是所有的 k8s叢集都會支援,大多是在公有雲托管叢集中會支援該類型。負載均衡器是異步建立的,關于被提供的負載均衡器的資訊将會通過Service的status.loadBalancer字段被釋出出去,并且需要付費,作為開發人員,我們隻做簡單了解。

apiVersion: v1
kind: Service
metadata:
  name: loadBalancerdemo
spec:
  selector:
    app: pod-bcst
  ports:
    - port: 8081 #叢集内其他服務通路的端口号
      targetPort: 8080 # pod容器的端口号
      nodePort: 30008 #叢集外部通路的端口号
  type: LoadBalancer           

ExternalName

類型為ExternalName 的service将服務映射到 DNS 名稱,而不是典型的選擇器,例如my-service或者 mysql資料庫。您可以使用spec.externalName參數指定這些服務。 這種類型的 Service 通過傳回域名和它的值,可以将服務映射到externalName 字段的内容( 例 如: hub.bcst.com )。ExternalName Service 是 Service 的特例,它沒有 selector,也沒有定義任何 的端口和 Endpoint。相反的,對于運作在叢集外部的服務,它通過傳回該外部服務的域名這種方式來提供服務。作為開發人員,不經常使用,隻做了解

建立 ExternalName 類型的服務的 yaml 如下:

apiVersion: v1
kind: Service
metadata:
  name: externalNamedemo
spec:
  selector:
    app: pod-bcst
  ports:
    - port: 3000
      protocol: TCP
      targetPort: 443
  type: ExternalName
  externalName: www.bcst.com           

繼續閱讀