一、Service 概述
(一)Service 的定義
Service 是 Kubernetes 中的一種抽象概念,用于定義一組 Pod 以及訪問這組 Pod 的策略。其核心作用是將一組 Pod 封裝為一個虛擬服務,并為客戶端提供統一的入口,從而實現服務的負載均衡、服務發現與暴露等功能。
具體而言,Service 為提供服務的 Pod 抽象出一個穩定的網絡訪問地址(通常是 DNS 域名格式的服務名稱),客戶端應用可通過該地址訪問服務,且網絡訪問方式與傳統方式一致。同時,Service 具備負載均衡器的功能,能將客戶端請求分發到后端各個 Pod 上。
(二)Service 的重要性
在 Kubernetes 實現微服務架構的過程中,Service 是核心資源。它不僅為客戶端提供了穩定的訪問地址(域名或 IP 地址)和負載均衡功能,還能屏蔽后端 Endpoint 的變化,使得構建高可用和可擴展的應用程序成為可能。
二、Service 工作原理
(一)基本原理
由于 Pod 的 IP 地址是動態變化的,無法直接通過 Pod 的 IP 地址進行訪問,Service 應運而生。它為一組 Pod 創建一個虛擬的 IP 地址,客戶端通過該 IP 地址訪問時,請求會被負載均衡到其中一個 Pod 上。
Service 的實現依賴于 kube-proxy 和 CoreDNS 組件:
kube-proxy:在每個節點上監聽 Service 的變化,一旦 Service 發生變化,便更新本地的 iptables 規則,實現流量的轉發和負載均衡。
CoreDNS:作為 Kubernetes 集群中的 DNS 解析服務,將 Service 的虛擬 IP 地址注冊其中,使客戶端可通過 Service 名稱訪問虛擬 IP 地址。
通過在 Service 定義中使用 spec.selector 字段指定屬于該 Service 的 Pod 標簽,可將請求負載均衡到這些 Pod 上。
(二)負載均衡機制
當 Service 對象在 Kubernetes 集群中定義后,集群內的客戶端應用可通過服務 IP 訪問 Pod 提供的服務,而從服務 IP 到后端 Pod 的負載均衡由每個節點上的 kube-proxy 代理實現。kube-proxy 的代理模式主要有以下幾種:
- userspace 模式
- 初期的 kube-proxy 是一個真實的 TCP/UDP 代理。當 Pod 以 ClusterIP 方式訪問 Service 時,流量會被本機的 iptables 轉發到 kube-proxy 進程,再由其轉發到后端 Pod。
- 具體過程為:kube-proxy 為每個 Service 在節點上打開一個隨機代理端口,建立 iptables 規則將 ClusterIP 的請求重定向到該端口,然后由 kube-proxy 轉發到后端 Pod。
- 由于存在內核態到用戶態的切換,開銷較大,該模式已被廢棄。
- iptables 模式
- 從 Kubernetes 1.2 版本開始,iptables 模式成為默認模式。此時 kube-proxy 不再負責轉發數據包,而是通過 API Server 的 Watch 接口實時跟蹤 Service 和 Endpoint 的變更信息,并更新對應的 iptables 規則。客戶端的請求流量通過 iptables 的 NAT 機制直接路由到目標 Pod。
- 該模式下不存在內核態到用戶態的切換,效率顯著提高。但隨著 Service 數量的增加,iptables 規則不斷增多,會導致內核負擔加重。
- ipvs 模式
- 從 Kubernetes 1.8 版本開始引入 ipvs 模式,它基于 netfilter 實現,專門用于高性能負載均衡,使用高效的 Hash 表數據結構,允許幾乎無限的規模擴張。
- ipvs 提供了多種負載均衡算法,如 rr(輪訓)、lc(最小連接數)、df(目標哈希)、sh(源哈希)、sed(預計延遲最短)、nq(從不排隊)等。
- ipvs 使用 ipset 存儲 iptables 規則,查找時類似 Hash 表查找,時間復雜度為 O (1),而 iptables 的時間復雜度為 O (n),因此 ipvs 模式性能更優。若操作系統未啟用 IPVS 內核模塊,kube-proxy 會自動切換為 iptables 模式;若啟用了,則運行在 ipvs 模式。可通過命令
lsmod | grep ip_vs
查看系統是否開啟了 ipvs 模塊。
- kernelspace 模式
- 這是 Windows Server 上的代理模式,文檔中未作詳細介紹。
三、Service 的四種類型
Kubernetes 支持四種 Service 類型,分別適用于不同的應用場景:
(一)ClusterIP
- 特點:這是最常用的 Service 類型,為 Pod 提供一個虛擬的 IP 地址,其他 Pod 可通過該虛擬 IP 地址訪問該 Service,Kubernetes 會自動將請求路由到相應的 Pod。
- 使用場景:適用于集群內部的服務通信,例如連接前端服務和后端服務,供內部其他服務使用。
- 示例:通過
kubectl expose deployment webapp
命令或 YAML 文件可創建 ClusterIP 類型的 Service。創建后,系統會分配一個虛擬 IP 地址,客戶端可通過該 IP 地址和端口號訪問 Service,請求會被自動負載分發到后端的 Pod。
(二)NodePort
- 特點:將 Pod 公開為集群中所有節點上的某個端口,當外部請求到達任何一個節點上的該端口時,Kubernetes 會將請求路由到相應的 Pod。它會創建一個 ClusterIP,并將指定的端口映射到每個節點上的相同端口。
- 使用場景:當需要從外部訪問集群中的服務時,可通過節點的 IP 地址和映射的端口進行訪問,適用于開發和測試環境。
- 示例:在 YAML 文件中設置
type: NodePort
和nodePort: 30008
等參數可創建 NodePort 類型的 Service。創建后,可在 Windows 宿主機上通過瀏覽器訪問http://節點IP:30008
來測試服務。
(三)LoadBalancer
- 特點:使用云提供商的負載均衡器將請求路由到后端 Pod,Kubernetes 會自動創建和配置負載均衡器,并將其綁定到 Service 上。
- 使用場景:適用于需要將流量從外部負載均衡器分發到集群內部的服務,例如在生產環境中暴露 Web 應用程序。
- 示例:在 YAML 文件中設置
type: LoadBalancer
等參數可創建 LoadBalancer 類型的 Service。創建后,云服務商會在 Service 定義中補充 LoadBalancer 的 IP 地址,客戶端可通過該 IP 地址和端口號訪問服務。
(四)ExternalName
- 特點:允許 Service 通過返回 CNAME 記錄來引用集群外部的服務,它沒有 ClusterIP、NodePort 或 LoadBalancer。
- 使用場景:適用于需要將 Kubernetes 內部的服務與集群外的現有服務進行關聯,例如連接到外部的數據庫或其他資源。此外,還可用于實現兩個不同命名空間中的 Pod 通過 Service 名稱進行通信。
- 示例:通過在 YAML 文件中設置
type: ExternalName
和externalName
字段指定外部服務的地址(如域名或 IP)可創建 ExternalName 類型的 Service。創建后,集群內客戶端應用可通過訪問該 Service 來訪問外部服務。
四、生成用于測試 Service 的 Deployment
在應用 Service 概念之前,需先創建一個提供 Web 服務的 Pod 集合,以方便對各種 Service 進行驗證。以下是創建過程:
(一)編輯 Deployment YAML 文件
apiVersion: apps/v1
kind: Deployment
metadata:name: webapp
spec:replicas: 2 # Pod的副本數selector: # 目標Pod的標簽選擇器matchLabels: # 需要匹配的標簽app: webapp # 對應目標Pod的標簽名稱template: # 自動創建新Pod副本的模板metadata:labels: # 定義Pod的標簽app: webapp # 標簽值為app:webappspec:containers:- name: webappimage: kubeguide/tomcat-app:v1ports:- name: httpcontainerPort: 8080protocol: TCP
(二)創建 Deployment
使用命令kubectl create -f webapp-deployment.yaml
創建 Deployment。
(三)查看 Pod 創建情況
通過kubectl get pod
命令可查看 Pod 的創建狀態,確保 Pod 處于 Running 狀態。
(四)查看 Pod 的 IP 地址
使用kubectl get pods -l app=webapp -o wide
命令可查看各個 Pod 的 IP 地址。
(五)訪問 Pod 地址
通過curl Pod IP:8080
命令可訪問 Pod 提供的服務,驗證 Pod 是否正常工作。
五、Service 的創建
(一)創建 ClusterIP 類型 Service
- 通過 expose 命令創建
- 執行
kubectl expose deployment webapp
命令暴露端口。 - 查看創建的 Service:
kubectl get svc
,系統會分配一個虛擬 IP 地址。 - 訪問測試:
curl 虛擬IP:8080
,請求會被負載分發到后端 Pod。 - 刪除 Service:
kubectl delete service webapp
。
- 執行
- 使用 YAML 文件創建編輯 YAML 文件:
apiVersion: v1
kind: Service
metadata:name: webapp
spec:ports:- protocol: TCPport: 8080targetPort: 8080selector:app: webapp
創建服務:kubectl create -f webapp-service.yaml
。
查看并訪問測試:kubectl get svc
獲取虛擬 IP,然后curl 虛擬IP:8080
。
查看 EndPoint 列表:kubectl describe svc webapp
可查看后端的 EndPoint(Pod 的 IP 和端口)。
查看 EndPoint 資源對象:kubectl get endpoints
。
刪除 Service:kubectl delete -f webapp-service.yaml
或kubectl delete service webapp
。
(二)創建 NodePort 類型的 Service
- 創建 Service 文件
apiVersion: v1
kind: Service
metadata:name: webapp
spec:type: NodePortports:- port: 8080targetPort: 8080nodePort: 30008selector:app: webapp
創建 Service:kubectl create -f webapp-svc-nodeport.yaml
。
查看創建的 Service:kubectl get svc
,可見 NodePort 類型及端口映射信息。
測試訪問:在 Windows 宿主機上通過瀏覽器訪問http://節點IP:30008
。
刪除 Service:kubectl delete -f webapp-svc-nodeport.yaml
。
(三)創建 LoadBalancer 類型的 Service
- 編寫 YAML 文件
apiVersion: v1
kind: Service
metadata:name: webappnamespace: defaultlabels:app: webapp
spec:type: LoadBalancerports:- port: 8080targetPort: httpprotocol: TCPname: httpnodePort: 31771 # 可選,系統會自動指定selector:app: webapp
創建 Service:kubectl create -f webapp-svc-loadbalancer.yaml
。
查看創建結果:kubectl get svc
,External-IP 初始為<pending>,待云提供商分配后會顯示具體 IP。
訪問測試:通過負載均衡器的 IP 和端口訪問服務。
刪除 Service:kubectl delete -f webapp-svc-loadbalancer.yaml
。
(四)創建 ExternalName 類型的 Service
以兩個不同命名空間中的 Pod 通信為例:
創建兩個命名空間:kubectl create namespace test01
和kubectl create namespace test02
。
- 在 test01 命名空間創建 Pod 和相關 Service
- 創建 Pod 的 Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:name: myapp01namespace: test01
spec:replicas: 1selector:matchLabels:app: myapp01release: canarytemplate:metadata:labels:app: myapp01release: canaryspec:containers:- name: myappimage: ikubernetes/myapp:v1ports:- name: http01containerPort: 80
創建無頭 Service
apiVersion: v1
kind: Service
metadata:name: myapp-svc01namespace: test01
spec:selector:app: myapp01release: canaryclusterIP: None # 無頭Serviceports:- port: 39320targetPort: 80
創建 ExternalName Service:
kind: Service
apiVersion: v1
metadata:name: myapp-svcname02namespace: test01
spec:type: ExternalNameexternalName: myapp-svc02.test02.svc.cluster.local
- 在 test02 命名空間創建 Pod 和相關 Service
- 類似地,創建 myapp02 的 Deployment、無頭 Service 和 ExternalName Service,注意命名空間和引用的服務名稱。
- 驗證 Pod 間的通信
- 通過
kubectl exec
進入 Pod,使用nslookup
和ping
命令驗證是否可通過 Service 名稱解析到對方 Pod 的 IP 地址,實現跨命名空間通信。
- 通過
六、Service 的其他應用
(一)Service 的多端口設置
當容器應用提供多個端口服務時,可在 Service 定義中設置多個端口號:
創建 Service 文件
apiVersion: v1
kind: Service
metadata:name: webapp
spec:ports:- port: 8080targetPort: 8080name: webprotocol: TCP- port: 8005targetPort: 8005name: managementprotocol: TCPselector:app: webapp
- 創建 Service:
kubectl create -f service-multiple-ports.yaml
。 - 查看 EndPoint 列表和 Service 信息:
kubectl describe svc webapp
和kubectl get svc webapp
。 - 刪除 Service:
kubectl delete -f webapp-service.yaml
或kubectl delete service webapp
。
(二)Kubernetes 服務發現
服務發現機制用于客戶端獲知后端服務的訪問地址,主要有以下兩種方式:
- 基于環境變量的服務發現
- 當 Pod 部署到節點后,節點上的 kubelet 會在 Pod 內部設置一組基于活躍 Service 生成的環境變量。
- 使用該方式時,需先創建 Service,再創建 Pod。Pod 運行時,系統會自動為其容器注入所有有效 Service 的信息,包括服務 IP、端口號、協議等。
- 客戶端應用可根據 Service 相關環境變量的命名規則,從環境變量中獲取目標服務的地址。例如,通過
kubectl exec -it Pod名稱 -- env
命令可查看 Pod 中的環境變量。
- 基于 DNS 的服務發現
- Kubernetes 新版默認使用 CoreDNS 作為集群內部 DNS,一般 CoreDNS 的 Service 地址為 Service 網段的低 10 個地址(如 10.96.0.10),端口為 53。
- DNS 服務器監聽 Kubernetes 創建的 Service,并為每個 Service 添加一組 DNS 記錄,集群中的 Pod 可通過內部 DNS 解析到 Service 的 ClusterIP。
- 例如,創建一個含 nslookup 命令的容器,通過
kubectl exec -it 容器名稱 -- nslookup Service名稱
可測試 DNS 解析。
七、案例練習
(一)案例一:創建 LoadBalancer 類型的 Nginx 服務
- YAML 文件
apiVersion: v1
kind: Service
metadata:name: mynginxnamespace: defaultlabels:app: mynginx
spec:type: LoadBalancerports:- port: 80targetPort: httpprotocol: TCPname: httpselector:app: mynginxapiVersion: apps/v1
kind: Deployment
metadata:name: mynginx-deploymentnamespace: defaultlabels:app: mynginx
spec:replicas: 2selector:matchLabels:app: mynginxtemplate:metadata:labels:app: mynginxspec:containers:- name: mynginximage: nginx:1.7.9ports:- name: httpcontainerPort: 80protocol: TCP
- 創建服務和 Deployment:
kubectl create -f nginx-service.yaml
。
(二)案例二:創建 NodePort 類型的 Tomcat 服務
- YAML 文件
apiVersion: v1
kind: Service
metadata:name: webapp
spec:type: NodePortports:- port: 8080targetPort: 8080nodePort: 30008selector:app: webappapiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:replicas: 2selector:matchLabels:app: webapptemplate:metadata:labels:app: webappspec:containers:- name: webappimage: kubeguide/tomcat-app:v1ports:- name: httpcontainerPort: 8080protocol: TCP
- 創建服務和 Deployment:
kubectl create -f tomcat-service.yaml
。
八、本章總結
本章全面介紹了 Kubernetes 中 Service 的核心知識,包括概念、工作原理、類型、創建方法及相關應用:
- Service 的核心作用:作為 Pod 的抽象,為其提供穩定的訪問入口,實現負載均衡、服務發現與暴露,是 Kubernetes 微服務架構的核心。
- 工作原理關鍵組件:kube-proxy 負責流量轉發和負載均衡規則更新,CoreDNS 實現 Service 的 DNS 解析。
- 四種 Service 類型特點與場景:
- ClusterIP:集群內部通信。
- NodePort:外部通過節點端口訪問。
- LoadBalancer:結合云服務商負載均衡器。
- ExternalName:關聯集群外部服務。
- 服務發現機制:基于環境變量和 DNS,使客戶端能便捷獲取服務地址。
- 實踐應用:通過 Deployment 配合不同類型 Service 的創建與配置案例,掌握了 Service 在實際場景中的運用