在 Kubernetes 叢集中,Pod 是短暫且動態的,它們的 IP 位址可能隨時改變。為了提供穩定的網路存取方式,Kubernetes 引入了 Service 的概念。本文將介紹 Service 的類型、建立方式、DNS 解析機制以及 Endpoint 的運作原理。
Service 類型
Kubernetes 提供了四種主要的 Service 類型,每種類型都有其特定的使用場景。
ClusterIP
ClusterIP 是 Kubernetes 中最基本也是預設的 Service 類型。它會為 Service 分配一個叢集內部的虛擬 IP 位址,只有叢集內部的 Pod 可以存取這個 Service。
1
2
3
4
5
6
7
8
9
10
11
12
| apiVersion: v1
kind: Service
metadata:
name: my-clusterip-service
spec:
type: ClusterIP
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
|
使用場景:
- 內部微服務之間的通訊
- 資料庫服務(如 MySQL、PostgreSQL)
- 快取服務(如 Redis、Memcached)
NodePort
NodePort 類型的 Service 會在每個節點上開放一個固定的連接埠(範圍為 30000-32767),外部流量可以透過 <NodeIP>:<NodePort> 存取服務。
1
2
3
4
5
6
7
8
9
10
11
12
13
| apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
type: NodePort
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 30080
|
使用場景:
- 開發和測試環境
- 不需要負載平衡器的小型部署
- 直接存取特定節點的服務
LoadBalancer
LoadBalancer 類型的 Service 會向雲端供應商請求一個外部負載平衡器,自動將流量分發到後端的 Pod。這種類型通常用於生產環境中需要對外暴露的服務。
1
2
3
4
5
6
7
8
9
10
11
12
| apiVersion: v1
kind: Service
metadata:
name: my-loadbalancer-service
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
|
使用場景:
- 生產環境的對外服務
- 需要高可用性的應用程式
- 雲端環境(AWS、GCP、Azure)中的服務暴露
ExternalName
ExternalName 是一種特殊的 Service 類型,它不會建立任何代理或轉發規則,而是透過 DNS CNAME 記錄將服務名稱對應到外部的 DNS 名稱。
1
2
3
4
5
6
7
| apiVersion: v1
kind: Service
metadata:
name: my-external-service
spec:
type: ExternalName
externalName: external.example.com
|
建立 Service
使用 kubectl 命令建立
最簡單的方式是使用 kubectl expose 命令:
1
2
3
4
5
| # 為 Deployment 建立 Service
kubectl expose deployment my-deployment --port=80 --target-port=8080
# 指定 Service 類型
kubectl expose deployment my-deployment --port=80 --target-port=8080 --type=NodePort
|
使用 YAML 檔案建立
建立一個完整的 Service YAML 檔案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| apiVersion: v1
kind: Service
metadata:
name: web-service
namespace: default
labels:
app: web
spec:
type: ClusterIP
selector:
app: web
tier: frontend
ports:
- name: http
protocol: TCP
port: 80
targetPort: 8080
- name: https
protocol: TCP
port: 443
targetPort: 8443
sessionAffinity: None
|
然後套用設定:
1
| kubectl apply -f service.yaml
|
驗證 Service 狀態
1
2
3
4
5
6
7
8
| # 列出所有 Service
kubectl get services
# 查看 Service 詳細資訊
kubectl describe service web-service
# 查看 Service 的 YAML 定義
kubectl get service web-service -o yaml
|
DNS 解析
Kubernetes 叢集內建 DNS 服務(通常是 CoreDNS),為每個 Service 自動建立 DNS 記錄。
DNS 命名規則
Service 的完整 DNS 名稱格式為:
1
| <service-name>.<namespace>.svc.cluster.local
|
例如,在 default 命名空間中名為 web-service 的 Service,其完整 DNS 名稱為:
1
| web-service.default.svc.cluster.local
|
DNS 解析範例
在同一個命名空間內,可以直接使用 Service 名稱:
1
2
3
4
5
6
7
8
| # 同一命名空間內
curl http://web-service
# 跨命名空間存取
curl http://web-service.other-namespace
# 完整 DNS 名稱
curl http://web-service.other-namespace.svc.cluster.local
|
測試 DNS 解析
可以使用 nslookup 或 dig 命令測試 DNS 解析:
1
2
3
4
5
| # 建立一個測試 Pod
kubectl run dns-test --image=busybox:1.28 --rm -it --restart=Never -- nslookup web-service
# 使用 dig 命令
kubectl run dns-test --image=tutum/dnsutils --rm -it --restart=Never -- dig web-service.default.svc.cluster.local
|
Headless Service
當不需要負載平衡和單一 Service IP 時,可以建立 Headless Service(將 clusterIP 設為 None)。DNS 查詢會直接返回所有後端 Pod 的 IP 位址。
1
2
3
4
5
6
7
8
9
10
11
| apiVersion: v1
kind: Service
metadata:
name: headless-service
spec:
clusterIP: None
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
|
Endpoint
Endpoint 是 Kubernetes 中用來追蹤 Service 後端 Pod IP 位址的資源。當 Pod 被建立或刪除時,Endpoint 會自動更新。
查看 Endpoint
1
2
3
4
5
6
7
8
| # 列出所有 Endpoint
kubectl get endpoints
# 查看特定 Service 的 Endpoint
kubectl get endpoints web-service
# 詳細資訊
kubectl describe endpoints web-service
|
輸出範例:
1
2
| NAME ENDPOINTS AGE
web-service 10.244.1.5:8080,10.244.2.3:8080 5m
|
Endpoint 的運作原理
- 選擇器匹配:Service 透過
selector 選擇符合標籤的 Pod - 自動更新:Endpoint Controller 會監控 Pod 的狀態變化
- 健康檢查:只有通過 readiness probe 的 Pod 才會被加入 Endpoint
手動管理 Endpoint
在某些情況下,您可能需要手動建立 Endpoint,例如指向叢集外部的服務:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # 建立無選擇器的 Service
apiVersion: v1
kind: Service
metadata:
name: external-db
spec:
ports:
- port: 3306
targetPort: 3306
---
# 手動建立 Endpoint
apiVersion: v1
kind: Endpoints
metadata:
name: external-db
subsets:
- addresses:
- ip: 192.168.1.100
- ip: 192.168.1.101
ports:
- port: 3306
|
EndpointSlice
在 Kubernetes 1.21 之後,EndpointSlice 成為預設的 Endpoint 管理方式。它提供更好的擴展性,特別是在大型叢集中。
1
2
3
4
5
| # 查看 EndpointSlice
kubectl get endpointslices
# 查看特定 Service 的 EndpointSlice
kubectl get endpointslices -l kubernetes.io/service-name=web-service
|
總結
Kubernetes Service 是建立穩定網路存取的核心元件:
| 類型 | 存取範圍 | 使用場景 |
|---|
| ClusterIP | 叢集內部 | 內部微服務通訊 |
| NodePort | 節點 IP + 連接埠 | 開發測試環境 |
| LoadBalancer | 外部負載平衡器 | 生產環境對外服務 |
| ExternalName | DNS CNAME | 存取外部服務 |
透過 Service、DNS 解析和 Endpoint 的協作,Kubernetes 提供了強大且靈活的服務發現與網路通訊機制,讓應用程式能夠在動態的容器環境中保持穩定運作。