詳解k8s 4種類型Service


 

Services 和 Pods

KubernetesPods是有生命周期的。他們可以被創建,而且銷毀不會再啟動。 如果您使用Deployment來運行您的應用程序,則它可以動態創建和銷毀 Pod。

一個Kubernetes的Service是一種抽象,它定義了一組Pods的邏輯集合和一個用於訪問它們的策略 - 有的時候被稱之為微服務。一個Service的目標Pod集合通常是由Label Selector 來決定的(下面有講一個沒有選擇器的Service 有什么用處)。

舉個例子,想象一個處理圖片的后端運行了三個副本。這些副本都是可以替代的 - 前端不關心它們使用的是哪一個后端。盡管實際組成后端集合的Pod可能會變化,前端的客戶端卻不需要知道這個變化,也不需要自己有一個列表來記錄這些后端服務。Service抽象能讓你達到這種解耦。

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

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

Userspace

作為一個例子,考慮前面提到的圖片處理應用程序。 當創建 backend Service 時,Kubernetes master 會給它指派一個虛擬 IP 地址,比如 10.0.0.1。 假設 Service 的端口是 1234,該 Service 會被集群中所有的 kube-proxy 實例觀察到。 當代理看到一個新的 Service, 它會打開一個新的端口,建立一個從該 VIP 重定向到新端口的 iptables,並開始接收請求連接。

當一個客戶端連接到一個 VIP,iptables 規則開始起作用,它會重定向該數據包到 Service代理 的端口。 Service代理 選擇一個 backend,並將客戶端的流量代理到 backend 上。

這意味着 Service 的所有者能夠選擇任何他們想使用的端口,而不存在沖突的風險。 客戶端可以簡單地連接到一個 IP 和端口,而不需要知道實際訪問了哪些 Pod

iptables

再次考慮前面提到的圖片處理應用程序。 當創建 backend Service 時,Kubernetes 控制面板會給它指派一個虛擬 IP 地址,比如 10.0.0.1。 假設 Service 的端口是 1234,該 Service 會被集群中所有的 kube-proxy 實例觀察到。 當代理看到一個新的 Service, 它會配置一系列的 iptables 規則,從 VIP 重定向到 per-Service 規則。 該 per-Service 規則連接到 per-Endpoint 規則,該 per-Endpoint 規則會重定向(目標 NAT)到 backend。

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

IPVS

在大規模集群(例如10,000個服務)中,iptables 操作會顯着降低速度。 IPVS 專為負載平衡而設計,並基於內核內哈希表。 因此,您可以通過基於 IPVS 的 kube-proxy 在大量服務中實現性能一致性。 同時,基於 IPVS 的 kube-proxy 具有更復雜的負載平衡算法(最小連接,局部性,加權,持久性)。

下面我們詳細說下k8s支持的4種類型的Service。

ClusterIP

創建ClusterIP的Service yaml如下:

apiVersion: v1
kind: Service
metadata:
  name: service-python
spec:
  ports:
  - port: 3000
    protocol: TCP
    targetPort: 443
  selector:
    run: pod-python
  type: ClusterIP

使用 kuebctl get svc :

類型為ClusterIP的service,這個service有一個Cluster-IP,其實就一個VIP。具體實現原理依靠kubeproxy組件,通過iptables或是ipvs實現。

這種類型的service 只能在集群內訪問。

NodePort

我們的場景不全是集群內訪問,也需要集群外業務訪問。那么ClusterIP就滿足不了了。NodePort當然是其中的一種實現方案。

創建NodePort 類型service 如下:

apiVersion: v1
kind: Service
metadata:
  name: service-python
spec:
  ports:
  - port: 3000
    protocol: TCP
    targetPort: 443
    nodePort: 30080
  selector:
    run: pod-python
  type: NodePort

使用 kuebctl get svc :

此時我們可以通過http://4.4.4.1:30080http://4.4.4.2:30080 對pod-python訪問。該端口有一定的范圍,比如默認Kubernetes 控制平面將在--service-node-port-range標志指定的范圍內分配端口(默認值:30000-32767)。

LoadBalancer

LoadBalancer類型的service 是可以實現集群外部訪問服務的另外一種解決方案。不過並不是所有的k8s集群都會支持,大多是在公有雲托管集群中會支持該類型。負載均衡器是異步創建的,關於被提供的負載均衡器的信息將會通過Servicestatus.loadBalancer字段被發布出去。

創建 LoadBalancer service 的yaml 如下:

apiVersion: v1
kind: Service
metadata:
  name: service-python
spec:
  ports:
  - port: 3000
    protocol: TCP
    targetPort: 443
    nodePort: 30080
  selector:
    run: pod-python
  type: LoadBalancer

使用 kuebctl get svc :

可以看到external-ip。我們就可以通過該ip來訪問了。

當然各家公有雲支持諸多的其他設置。大多是公有雲負載均衡器的設置參數,都可以通過svc的注解來設置,例如下面的aws:

    metadata:
      name: my-service
      annotations:
        service.beta.kubernetes.io/aws-load-balancer-access-log-enabled: "true"
        # Specifies whether access logs are enabled for the load balancer
        service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval: "60"
        # The interval for publishing the access logs. You can specify an interval of either 5 or 60 (minutes).
        service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name: "my-bucket"
        # The name of the Amazon S3 bucket where the access logs are stored
        service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix: "my-bucket-prefix/prod"
        # The logical hierarchy you created for your Amazon S3 bucket, for example `my-bucket-prefix/prod`

ExternalName

類型為 ExternalName 的service將服務映射到 DNS 名稱,而不是典型的選擇器,例如my-service或者cassandra。 您可以使用spec.externalName參數指定這些服務。

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

kind: Service
apiVersion: v1
metadata:
  name: service-python
spec:
  ports:
  - port: 3000
    protocol: TCP
    targetPort: 443
  type: ExternalName
  externalName: remote.server.url.com

說明:您需要 CoreDNS 1.7 或更高版本才能使用 ExternalName類型。

當查找主機 service-python.default.svc.cluster.local時,集群DNS服務返回CNAME記錄,其值為my.database.example.com。 訪問service-python的方式與其他服務的方式相同,但主要區別在於重定向發生在 DNS 級別,而不是通過代理或轉發。

將生產工作負載遷移到Kubernetes集群並不容易。大多數我們不可以停止所有服務並在Kubernetes集群上啟動它們。有時,嘗試遷移輕量且不會破壞你服務的服務是很好的。在此過程中,一個可能不錯的解決方案是使用現有的有狀態服務(例如DB),並首先從無狀態容器開始。

從Pod中訪問外部服務的最簡單正確的方法是創建ExternalName service。例如,如果您決定保留AWS RDS,但您還希望能夠將MySQL容器用於測試環境。讓我們看一下這個例子:

kind: Service
apiVersion: v1
metadata:
  name: test-service
  namespace: default
spec:
  type: ExternalName
  externalName: test.database.example.com

你已將Web應用程序配置為使用URL測試服務訪問數據庫,但是在生產集群上,數據庫位於AWS RDS上,並且具有以下URL test.database.example.com。創建ExternalName service 並且你的Web Pod嘗試訪問test-service上的數據庫之后,Kubernetes DNS服務器將返回值為test.database.example.com的CNAME記錄。問題解決了。

ExternalName service 也可以用於從其他名稱空間訪問服務。例如:

kind: Service
apiVersion: v1
metadata:
  name: test-service-1
  namespace: namespace-a
spec:
  type: ExternalName
  externalName: test-service-2.namespace-b.svc.cluster.local
  ports:
  - port: 80 

在這里,我可以使用名稱空間a中定義的test-service-1訪問命名空間b中的服務
test-service-2

這個意義在哪里?

ExternalName service 也是一種service,那么ingress controller 會支持,那么就可以實現跨namespace的ingress。

 

 1、客戶端訪問節點時通過 iptables實現的

 2、iptables規則是通過 kube-proxy寫入的

 3、apiserver通過監控 kube-proxy去進行對服務和端點的監控

 4、kube-proxy通過 pod的標簽( lables)去判斷這個斷點信息是否寫入到 Endpoints里


免責聲明!

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



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