K8S Service 多種類型 Types 測試手記
前言
這里基于whoami
示范服務,部署3個實例,分別一一驗證各種類型的K8S Service服務范疇。
大致逐一從下面列表逐一驗證每種類型的Service訪問方式:
Service Name
- 域名解析結果等
CLUSTER-IP
EXTERNAL-IP
一些設定如下:
- 測試環境K8S版本號為
v1.27.3
- K8S集群Node節點IP地址段范圍:
10.0.1.0/24
- K8S集群自動生成Pod網段為
10.43.0.0/24
- 本書所列代碼皆可拷貝直接粘貼到終端界面直接運行
首先,部署whoami服務
先部署包含3個實例的whoami
:
# cat << 'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami
labels:
app: whoami
spec:
replicas: 3
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: containous/whoami
ports:
- containerPort: 80
name: web
EOF
查看一下:
# kubectl get all
NAME READY STATUS RESTARTS AGE
pod/whoami-767d459f67-qffqw 1/1 Running 0 23m
pod/whoami-767d459f67-xdv9p 1/1 Running 0 23m
pod/whoami-767d459f67-gwpgx 1/1 Running 0 23m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/whoami 3/3 3 3 23m
NAME DESIRED CURRENT READY AGE
replicaset.apps/whoami-767d459f67 3 3 3 23m
其次,安裝busybox進行調試
安裝一個包含有curl
的busybox方便后續調試:
kubectl run busybox-curl --image=yauritux/busybox-curl --command -- sleep 3600
另起一個終端,輸入下面命令進入:
kubectl exec -ti busybox-curl -n default -- sh
環境準備好之后,下面逐一測試各種類型:
默認Cluster IP模式
K8S默認Service為Cluster IP
模式,面向內部Pod以及通過Ingress對外提供服務。
下面一張圖很清晰解釋清楚了Port
和TargetPort
適用情景,Port
為Service對外輸出的端口,TargetPort
為服務后端Pod的端口,兩者之間有一個轉換:port -> targetPort -> containerPort
。
創建一個Service:
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
labels:
name: whoami-clusterip
name: whoami-clusterip
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: whoami
EOF
部署后可以查看一下:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/whoami-clusterip ClusterIP 10.43.247.74 <none> 80/TCP 57s
下面就需要逐一測試了。
域名形式:
# curl whoami-clusterip
Hostname: whoami-767d459f67-gwpgx
IP: 127.0.0.1
IP: 10.42.8.35
RemoteAddr: 10.42.9.32:35968
GET / HTTP/1.1
Host: whoami-clusterip
User-Agent: curl/7.81.0
Accept: */*
Cluster IP形式:
# curl 10.43.247.74
Hostname: whoami-767d459f67-qffqw
IP: 127.0.0.1
IP: 10.42.3.73
RemoteAddr: 10.42.9.32:42398
GET / HTTP/1.1
Host: 10.43.247.74
User-Agent: curl/7.81.0
Accept: */*
域名解析,只解析到Cluster IP上:
# nslookup whoami-clusterip
Server: 10.43.0.10
Address: 10.43.0.10:53
Name: whoami-clusterip.default.svc.cluster.local
Address: 10.43.247.74
External IP模式
原理同Cluster IP模式,為指定服務綁定一個額外的一個IP地址。當終端訪問該IP地址,將流量一樣轉發到Service。
當訪問external IP
,其端口轉換過程:port -> targetPort -> containerPort
。
與默認Service相比,端口轉換流程沒有增加,但好處對外暴露了一個可訪問的IP地址,不過可能需要在交換機/路由器層面提供動靜態路由支持。
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
labels:
name: whoami-externalip
name: whoami-externalip
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: whoami
externalIPs:
- 10.10.10.10
EOF
服務顯示如下,綁定了指定的擴展IP地址10.10.10.10
。
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/whoami-externalip ClusterIP 10.43.192.118 10.10.10.10 80/TCP 57s
kube-proxy
將在每一個Node節點為10.10.10.10
上建立一個轉發規則,該IP地址的80
端口將直接轉發到對應的后端三個whoami
Pod 上。
-A KUBE-SERVICES -d 10.10.10.10/32 -p tcp -m comment --comment "default/whoami-externalip external IP" -m tcp --dport 80 -j KUBE-EXT-QN5HIEVYUPDP6UNK
......
-A KUBE-EXT-QN5HIEVYUPDP6UNK -j KUBE-SVC-QN5HIEVYUPDP6UNK
......
-A KUBE-SVC-QN5HIEVYUPDP6UNK ! -s 10.42.0.0/16 -d 10.43.192.118/32 -p tcp -m comment --comment "default/whoami-externalip cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SVC-QN5HIEVYUPDP6UNK -m comment --comment "default/whoami-externalip -> 10.42.2.79:80" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-JSAT6D2KFCSF4YLF
-A KUBE-SVC-QN5HIEVYUPDP6UNK -m comment --comment "default/whoami-externalip -> 10.42.3.77:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-2R66UI3G2AY2IMNM
-A KUBE-SVC-QN5HIEVYUPDP6UNK -m comment --comment "default/whoami-externalip -> 10.42.8.42:80" -j KUBE-SEP-ZHHIL2SAN2G37GCM
訪問域名:
# curl whoami-externalip
Hostname: whoami-767d459f67-gwpgx
IP: 127.0.0.1
IP: 10.42.8.35
RemoteAddr: 10.42.9.32:46746
GET / HTTP/1.1
Host: whoami-externalip
User-Agent: curl/7.81.0
Accept: */*
訪問ClusterIP形式:
# curl 10.43.192.118
Hostname: whoami-767d459f67-qffqw
IP: 127.0.0.1
IP: 10.42.3.73
RemoteAddr: 10.42.9.32:47516
GET / HTTP/1.1
Host: 10.43.192.118
User-Agent: curl/7.81.0
Accept: */*
訪問暴露的External IP:
# curl 10.10.10.10
Hostname: whoami-767d459f67-gwpgx
IP: 127.0.0.1
IP: 10.42.8.35
RemoteAddr: 10.42.9.0:38477
GET / HTTP/1.1
Host: 10.10.10.10
User-Agent: curl/7.81.0
Accept: */*
域名解析結果只解析到其對應的Cluster IP:
# nslookup whoami-externalip
Server: 10.43.0.10
Address: 10.43.0.10:53
Name: whoami-externalip.default.svc.cluster.local
Address: 10.43.192.118
NodePort 模式
與Cluster IP
相比,多了一個nodePort
,這個NodePort會在K8S所有Node節點上都會開放。
這里有一個端口轉換過程:nodePort -> port -> targetPort -> containerPort
,多了一層數據轉換過程。
服務定義如下:
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
labels:
name: whoami-nodeport
name: whoami-nodeport
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080
protocol: TCP
selector:
app: whoami
EOF
查看一下服務分配地址:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/whoami-nodeport NodePort 10.43.215.233 <none> 80:30080/TCP 57s
訪問域名:
# curl whoami-nodeport
Hostname: whoami-767d459f67-xdv9p
IP: 127.0.0.1
IP: 10.42.2.75
RemoteAddr: 10.42.9.32:36878
GET / HTTP/1.1
Host: whoami-nodeport
User-Agent: curl/7.81.0
Accept: */*
測試 CLUSTER IP :
# curl 10.43.215.233
Hostname: whoami-767d459f67-qffqw
IP: 127.0.0.1
IP: 10.42.3.73
RemoteAddr: 10.42.9.32:40552
GET / HTTP/1.1
Host: 10.43.215.233
User-Agent: curl/7.81.0
Accept: */*
因為是在每一個K8S Node節點上都會開放一個30080
端口,因此可以這樣訪問 {Node IP}:{nodePort}
,如下Node IP地址為10.0.1.11
# curl 10.0.1.11:30080
Hostname: whoami-767d459f67-qffqw
IP: 127.0.0.1
IP: 10.42.3.73
RemoteAddr: 10.42.1.0:1880
GET / HTTP/1.1
Host: 10.0.1.11:30080
User-Agent: curl/7.81.0
Accept: */*
域名還是只解析到對應Cluster IP:
# nslookup whoami-nodeport
Server: 10.43.0.10
Address: 10.43.0.10:53
Name: whoami-nodeport.default.svc.cluster.local
Address: 10.43.215.233
LoadBalancer 模式
LoadBalancer
模式,會強制K8S Service自動開啟nodePort
。
這里有一張圖,詳細解析數據流向。
服務數據端口轉換過程:port -> nodePort -> port -> targetPort -> containerPort
:
- 與默認
Cluster IP
相比,多了兩層數據轉換過程 - 與
nodePort
相比,對了一層數據轉換過程 - 與
externalIP
相比,在小流量場景下就沒有什么優勢了
具體服務定義:
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
labels:
name: whoami-clusterip-none
name: whoami-clusterip-none
spec:
clusterIP: None
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: whoami
EOF
查看一下部署結果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/whoami-loadbalancer LoadBalancer 10.43.63.92 <pending> 80:30906/TCP 57s
服務域名形式:
# curl whoami-loadbalancer
Hostname: whoami-767d459f67-qffqw
IP: 127.0.0.1
IP: 10.42.3.73
RemoteAddr: 10.42.9.32:57844
GET / HTTP/1.1
Host: whoami-loadbalancer
User-Agent: curl/7.81.0
Accept: */*
測試 CLUSTER-IP
# curl 10.43.63.92
Hostname: whoami-767d459f67-xdv9p
IP: 127.0.0.1
IP: 10.42.2.75
RemoteAddr: 10.42.9.32:42400
GET / HTTP/1.1
Host: 10.43.63.92
User-Agent: curl/7.81.0
Accept: */*
域名解析到Cluster IP:
# nslookup whoami-loadbalancer
Server: 10.43.0.10
Address: 10.43.0.10:53
Name: whoami-loadbalancer.default.svc.cluster.local
Address: 10.43.63.92
安裝LoadBalancer
此時whoami-loadbalancer
服務對應的EXTERNAL-IP
為 <pending>
,我們需要安裝一個負載均衡器,可以選擇MetalLB
作為負載均衡器。
# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.11/config/manifests/metallb-native.yaml
稍后分配可用的LoadBalaner可分配的地址池:
cat << 'EOF' | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default-pool
namespace: metallb-system
spec:
addresses:
- 10.0.1.100-10.0.1.200
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default-pool
EOF
等安裝完成之后,可以看到服務whoami-loadbalancer
分配的IP地址為 10.0.1.101
:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
......
service/whoami-loadbalancer LoadBalancer 10.43.63.92 10.0.1.101 80:30906/TCP 27h
......
測試負載均衡IP地址
測試一下:
# curl 10.0.1.101
Hostname: whoami-767d459f67-xdv9p
IP: 127.0.0.1
IP: 10.42.2.78
RemoteAddr: 10.42.8.0:33658
GET / HTTP/1.1
Host: 10.0.1.101
User-Agent: curl/7.79.1
Accept: */*
我們看到該服務分配的端口為80:30906/TCP
,30906
為K8S為該服務自動生成的NodePort類型端口。
可以找任一K8S Node節點IP地址測試一下:
# curl 10.0.1.12:30906
Hostname: whoami-767d459f67-qffqw
IP: 127.0.0.1
IP: 10.42.3.77
RemoteAddr: 10.42.2.0:9717
GET / HTTP/1.1
Host: 10.0.1.12:30906
User-Agent: curl/7.81.0
Accept: */*
分析一下路由表,可以分析到該負載均衡的External_IP:80
的打流量到NodePort:30906
上,然后走Service對應{Pod:80}
流量分發邏輯。
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/whoami-loadbalancer" -m tcp --dport 30906 -j KUBE-EXT-NBTYBEEXACZI7DPC
......
-A KUBE-SERVICES -d 10.0.1.101/32 -p tcp -m comment --comment "default/whoami-loadbalancer loadbalancer IP" -m tcp --dport 80 -j KUBE-EXT-NBTYBEEXACZI7DPC
......
-A KUBE-EXT-NBTYBEEXACZI7DPC -m comment --comment "masquerade traffic for default/whoami-loadbalancer external destinations" -j KUBE-MARK-MASQ
-A KUBE-EXT-NBTYBEEXACZI7DPC -j KUBE-SVC-NBTYBEEXACZI7DPC
......
-A KUBE-SVC-NBTYBEEXACZI7DPC ! -s 10.42.0.0/16 -d 10.43.63.92/32 -p tcp -m comment --comment "default/whoami-loadbalancer cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SVC-NBTYBEEXACZI7DPC -m comment --comment "default/whoami-loadbalancer -> 10.42.2.79:80" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-E3K3SUYNFWT2VICE
-A KUBE-SVC-NBTYBEEXACZI7DPC -m comment --comment "default/whoami-loadbalancer -> 10.42.3.77:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-HG5MYVVID7GJOZA7
-A KUBE-SVC-NBTYBEEXACZI7DPC -m comment --comment "default/whoami-loadbalancer -> 10.42.8.42:80" -j KUBE-SEP-GFJH72YCBKBFB6OG
Headless 無頭模式
一般應用在有狀態的服務,或需要終端調用者自己實現負載均衡,等一些特定場景。
通過調用者從端口角度分析,數據轉換流程:targetPort -> containerPort
。
在意服務性能的場景,不妨試試無頭模式。
服務定義:
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
labels:
name: whoami-clusterip-none
name: whoami-clusterip-none
spec:
clusterIP: None
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: whoami
EOF
查看服務部署情況:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/whoami-clusterip-none ClusterIP None <none> 80/TCP 9h
通過service域名訪問,K8S會自動根據服務域名whoami-clusterip-none
進行pick后端對應Pod IP地址。
# curl whoami-clusterip-none
Hostname: whoami-767d459f67-xdv9p
IP: 127.0.0.1
IP: 10.42.2.75
RemoteAddr: 10.42.9.32:34998
GET / HTTP/1.1
Host: whoami-clusterip-none
User-Agent: curl/7.81.0
Accept: */*
查詢DNS會把所有節點都列出來。
# nslookup whoami-clusterip-none
Server: 10.43.0.10
Address: 10.43.0.10:53
Name: whoami-clusterip-none.default.svc.cluster.local
Address: 10.42.3.73
Name: whoami-clusterip-none.default.svc.cluster.local
Address: 10.42.2.75
Name: whoami-clusterip-none.default.svc.cluster.local
Address: 10.42.8.35
External Name模式
用于引進帶域名的外部服務,這里引入內部服務作為測試。
多了一層域名解析過程,端口轉換流程依賴于所引入服務的服務設定。
服務定義:
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
labels:
name: whoami-externalname
name: whoami-externalname
spec:
type: ExternalName
externalName: whoami-clusterip.default.svc.cluster.local
EOF
這里外聯的是whoami-clusterip
服務的完整訪問域名。
查看服務部署情況:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/whoami-externalname ExternalName <none> whoami-clusterip.default <none> 9h
根據域名訪問測試:
# curl whoami-externalname
Hostname: whoami-767d459f67-qffqw
IP: 127.0.0.1
IP: 10.42.3.77
RemoteAddr: 10.42.9.35:36756
GET / HTTP/1.1
Host: whoami-externalname
User-Agent: curl/7.81.0
Accept: */*
DNS解析結果:
# nslookup whoami-externalname
Server: 10.43.0.10
Address: 10.43.0.10:53
whoami-externalname.default.svc.cluster.local canonical name = whoami-clusterip.default.svc.cluster.local
Name: whoami-clusterip.default.svc.cluster.local
Address: 10.43.247.74
小結
簡要分析了各種類型Service定義、服務引用場景以及測試流程等,整理清楚了,也方便在具體業務場景中進行抉擇選擇具體服務類型。
posted on 2023-09-13 10:13 nieyong 閱讀(206) 評論(0) 編輯 收藏 所屬分類: 容器