前言
这里基于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定义、服务引用场景以及测试流程等,整理清楚了,也方便在具体业务场景中进行抉择选择具体服务类型。