**摘要:**本文基于真实虚拟机环境,演示 Kubernetes 微服务网络通信的完整实验流程。内容涵盖 Service 的标签选择器与 Endpoint 关联机制、ClusterIP、Headless、NodePort 三种 Service 类型,以及 IPVS 负载均衡模式的切换与验证;随后深入讲解 Ingress 的路径转发、域名访问、动静分离、TLS 加密、Basic Auth 认证和网页重写等高级路由策略,最后通过 Nginx Ingress 注解实现基于请求头和基于权重的金丝雀灰度发布。全文以具体命令和验证输出为主线,步骤清晰、可直接复现。
1. 引言
在 Kubernetes 集群中部署微服务时,网络通信是核心环节。Pod 的 IP 地址是动态变化的,直接访问 Pod 并不可靠。Kubernetes 通过 Service 提供稳定的访问入口,通过 Ingress 实现集群外部流量的精细化路由。本文基于真实虚拟机环境,从标签与 Endpoint 的关系讲起,逐步演示 Service 的 ClusterIP、Headless、NodePort 模式,以及 Ingress 的路径转发、域名访问、TLS 加密、认证和灰度发布,所有操作均给出具体命令和验证步骤。
2. 环境准备
本文实验环境为一套多节点 Kubernetes 集群,包含一台 master 节点和多台 node 节点。所有节点均使用 Linux 操作系统,并已提前完成 Kubernetes 集群的初始化部署。实验中使用 myapp:v1 和 myapp:v2 两个镜像作为测试业务,镜像内置了返回版本信息的 Web 服务。
在开始实验前,请确认集群状态正常:
bash
[root@k8s-master ~]# kubectl get nodes
[root@k8s-master ~]# kubectl get pods -n kube-system
如果所有节点状态为 Ready,且核心组件 Pod 均处于 Running 状态,即可继续后续实验。
3. 理解标签与 Service 中的 Endpoint
Service 通过标签选择器(Selector)匹配后端 Pod,并将匹配到的 Pod IP 和端口记录在 Endpoints 中。只有当 Pod 的标签与 Service 的 Selector 完全一致时,Pod 才会被纳入负载均衡池。
3.1 创建一个 Service
首先使用命令行生成 Service 的 YAML 模板,然后编辑并应用:
bash
[root@k8s-master services]# kubectl create service clusterip --tcp 80:80 testservice --dry-run=client -o yaml >> testservice.yaml
[root@k8s-master services]# vim testservice.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: testservice
name: testservice
spec:
ports:
name: webport
port: 80
protocol: TCP
targetPort: 80
selector:
app: webserver
type: ClusterIP
[root@k8s-master services]# kubectl apply -f testservice.yaml
service/testservice created
使用 watch 命令持续监控 Service 和 Pod 的状态变化:
bash
[root@k8s-master ~]# watch -n 1 "kubectl describe svc testservice ; kubectl get pods --show-labels"
此时 Service 已创建,但由于还没有任何 Pod 带有 app=webserver 标签,Endpoints 为空:
Name: testservice
Namespace: default
Labels: app=testservice
Selector: app=webserver
Type: ClusterIP
IP: 10.100.62.227
Port: webport 80/TCP
TargetPort: 80/TCP
Endpoints: (空)
Session Affinity: None
Events: <none>
3.2 创建 Pod 并测试标签匹配
创建一个不带 app=webserver 标签的 Pod:
bash
[root@k8s-master services]# kubectl run webserver --image myapp:v1 --dry-run=client -o yaml > webserver.yml
[root@k8s-master services]# vim webserver.yml
kind: Pod
metadata:
labels:
run: webserver
name: webserver
spec:
containers:
- image: myapp:v1
name: webserver
[root@k8s-master services]# kubectl apply -f webserver.yml
pod/webserver created
观察监控输出可以发现,Pod 虽然正常运行,但 Service 的 Endpoints 仍然为空,因为 Pod 的标签是 run=webserver,与 Service 的 Selector(app=webserver)不匹配。
现在为 Pod 添加正确的标签:
bash
[root@k8s-master services]# kubectl label pods webserver app=webserver
pod/webserver labeled
再次查看监控,Endpoints 已出现 Pod 的 IP 地址,通过 Service IP 可以访问后端业务:
bash
[root@k8s-master services]# curl 10.100.62.227
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
这个实验清晰地说明了标签选择器是 Service 关联 Pod 的唯一依据。
4. 利用 Service 暴露控制器管理的 Pod
生产环境中通常使用 Deployment 管理 Pod 副本,Service 需要与 Deployment 配合,将流量负载均衡到多个副本上。
4.1 生成控制器和 Service 的组合 YAML
bash
[root@k8s-master services]# kubectl create service clusterip --tcp 80:80 webservice --dry-run=client -o yaml >> webservice.yaml
[root@k8s-master services]# kubectl create deployment webcluster --image myapp:v1 --dry-run=client -o yaml >> webservice.yaml
[root@k8s-master services]# vim webservice.yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
app: webservice
name: webservice
spec:
ports:
- name: webport
port: 80
protocol: TCP
targetPort: 80
selector:
app: webcluster
type: ClusterIP
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: webcluster
name: webcluster
spec:
replicas: 2
selector:
matchLabels:
app: webcluster
template:
metadata:
labels:
app: webcluster
spec:
containers:
- image: myapp:v1
name: myapp
4.2 应用并验证负载均衡
bash
[root@k8s-master services]# kubectl apply -f webservice.yaml
查看 Service 的 Endpoints,可以看到两个 Pod 的 IP 都已加入:
Endpoints: 10.244.2.8:80,10.244.5.95:80
多次访问 Service IP 的 hostname.html 路径,可以看到请求被轮询分发到不同的 Pod:
bash
[root@k8s-master services]# curl 10.98.31.55/hostname.html
webcluster-77c87d9946-tlzxj
[root@k8s-master services]# curl 10.98.31.55/hostname.html
webcluster-77c87d9946-pz5nq
[root@k8s-master services]# curl 10.98.31.55/hostname.html
webcluster-77c87d9946-pz5nq
这说明 Service 已经将流量均匀分发到 Deployment 管理的多个 Pod 副本上。
5. Service 的 IPVS 模式
Kubernetes 默认使用 iptables 实现 Service 的负载均衡,也可以切换为 IPVS 模式。IPVS 基于内核态哈希表,支持更多负载均衡算法,性能更优。
5.1 在所有节点安装 ipvsadm 工具
bash
[root@k8s-master ~]# for name in 100 10 20 200
> do
> ssh -l root 172.25.254.$name "dnf install ipvsadm -y"
> done
5.2 修改 kube-proxy 配置
bash
[root@k8s-master ~]# kubectl -n kube-system edit cm kube-proxy
# 将 mode 修改为 ipvs
mode: "ipvs"
configmap/kube-proxy edited
修改配置后需要重启所有 kube-proxy Pod 使配置生效:
bash
[root@k8s-master ~]# kubectl -n kube-system get pods | grep kube-proxy
[root@k8s-master ~]# kubectl -n kube-system delete pods kube-proxy-6kp78 kube-proxy-hvk7k kube-proxy-p7fdf kube-proxy-tb29j
5.3 验证 IPVS 规则
在 master 节点查看 IPVS 规则:
bash
[root@k8s-master ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.96.0.1:443 rr
-> 172.25.254.100:6443 Masq 1 0 0
TCP 10.96.0.10:53 rr
-> 10.244.1.2:53 Masq 1 0 0
TCP 10.98.31.55:80 rr
-> 10.244.2.8:80 Masq 1 0 0
-> 10.244.5.95:80 Masq 1 0 0
可以看到 Service 的 ClusterIP 和端口被映射为 IPVS 虚拟服务器,后端 Pod 以轮询(rr)算法被调度。
6. Service 的 ClusterIP 类型
ClusterIP 是 Service 的默认类型,为 Service 分配一个集群内部虚拟 IP,仅集群内部可以访问。
6.1 集群内部 DNS 解析
Kubernetes 内置 DNS 服务(kube-dns / CoreDNS),为 Service 提供域名解析。解析格式为:
dig <servicename>.<namespace>.svc.cluster.local @<dns-ip>
查看 DNS 服务的 ClusterIP:
bash
[root@k8s-master services]# kubectl -n kube-system get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 4d3h
使用 dig 命令解析 webservice 服务:
bash
[root@k8s-master services]# dig webservice.default.svc.cluster.local @10.96.0.10
;; ANSWER SECTION:
webservice.default.svc.cluster.local. 30 IN A 10.109.112.7
集群内部的应用之间通信时,应使用 Service 的域名而不是 IP,因为 Pod 和 Service 的 IP 都可能变化,而域名保持不变。
6.2 ClusterIP 的 Headless 模式
将 Service 的 clusterIP 设置为 None,即进入 Headless 模式。此时 Service 不分配虚拟 IP,DNS 直接返回后端 Pod 的 IP 列表。
bash
[root@k8s-master services]# vim webservice.yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
app: webservice
name: webservice
spec:
ports:
- name: webport
port: 80
protocol: TCP
targetPort: 80
selector:
app: webcluster
type: ClusterIP
clusterIP: None
[root@k8s-master services]# kubectl delete -f webservice.yaml
[root@k8s-master services]# kubectl apply -f webservice.yaml
查看 Service 详情,IP 字段为 None:
IP: None
IPs: None
Endpoints: 10.244.2.15:80,10.244.5.99:80
再次解析域名,DNS 直接返回两个 Pod 的 IP:
bash
[root@k8s-master services]# dig webservice.default.svc.cluster.local @10.96.0.10
;; ANSWER SECTION:
webservice.default.svc.cluster.local. 30 IN A 10.244.5.99
webservice.default.svc.cluster.local. 30 IN A 10.244.2.15
Headless Service 适用于需要直接连接 Pod 的场景,例如 StatefulSet 管理的数据库集群。
7. Service 的 NodePort 模式
NodePort 模式在 ClusterIP 的基础上,将 Service 的端口映射到每个节点的固定端口(30000-32767),集群外部可以通过任意节点的该端口访问服务。
7.1 创建 NodePort 类型的 Service
bash
[root@k8s-master services]# vim nodeport.yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
app: webservice
name: webservice
spec:
ports:
- name: webport
port: 80
protocol: TCP
targetPort: 80
nodePort: 30951
selector:
app: webcluster
type: NodePort
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: webcluster
name: webcluster
spec:
replicas: 2
selector:
matchLabels:
app: webcluster
template:
metadata:
labels:
app: webcluster
spec:
containers:
- image: myapp:v1
name: myapp
应用配置后,查看 IPVS 规则可以看到节点 IP 上的 30951 端口被映射到后端 Pod:
bash
[root@k8s-master services]# ipvsadm -Ln
TCP 172.25.254.100:30951 rr
-> 10.244.2.16:80 Masq 1 0 0
-> 10.244.5.100:80 Masq 1 0 0
7.2 从集群外部访问
在集群外部的机器上,通过任意节点的 IP 加 NodePort 端口即可访问服务:
bash
[Administrator.DESKTOP-VJ307M3] ➤ curl 172.25.254.100:30951/hostname.html
webcluster-77c87d9946-ks6cd
NodePort 模式适合小规模集群或临时对外提供服务,但生产环境更推荐使用 Ingress 统一管理入口流量。
8. Ingress 基础与多版本路由
Ingress 是 Kubernetes 的 API 对象,负责管理集群外部访问集群内服务的 HTTP 和 HTTPS 路由。Ingress Controller(如 Nginx Ingress Controller)负责实际执行转发规则。
8.1 准备两个版本的服务
首先创建两个不同版本的 Deployment 和对应的 Service:
bash
[root@k8s-master services]# kubectl create deployment myappv1 --image myapp:v1 --dry-run=client -o yaml > myappv1.yaml
[root@k8s-master services]# kubectl create deployment myappv2 --image myapp:v2 --dry-run=client -o yaml > myappv2.yaml
[root@k8s-master services]# kubectl create service clusterip --tcp 80:80 servicev1 --dry-run=client -o yaml >> myappv1.yaml
[root@k8s-master services]# kubectl create service clusterip --tcp 80:80 servicev2 --dry-run=client -o yaml >> myappv2.yaml
编辑 YAML 文件,确保 Service 的 Selector 与 Deployment 的 Pod 标签一致,然后应用:
bash
[root@k8s-master services]# kubectl apply -f myappv1.yaml
[root@k8s-master services]# kubectl apply -f myappv2.yaml
[root@k8s-master services]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
servicev1 ClusterIP 10.97.35.20 <none> 80/TCP 4m4s
servicev2 ClusterIP 10.100.116.247 <none> 80/TCP 40s
验证两个 Service 分别返回不同版本的内容:
bash
[root@k8s-master services]# curl 10.97.35.20
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@k8s-master services]# curl 10.100.116.247
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
8.2 基于路径的 Ingress 路由
创建 Ingress 规则,将 /v1 路径转发到 servicev1,将 /v2 路径转发到 servicev2:
bash
[root@k8s-master services]# kubectl create ingress ingress1 --class nginx --rule "*/=servicev1:80" --dry-run=client -o yaml > 1-ingress.yml
[root@k8s-master services]# vim 1-ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress1
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: 'www.timinglee.org'
http:
paths:
- backend:
service:
name: servicev1
port:
number: 80
path: /v1
pathType: Prefix
- backend:
service:
name: servicev2
port:
number: 80
path: /v2
pathType: Prefix
[root@k8s-master services]# kubectl apply -f 1-ingress.yml
查看 Ingress 规则详情:
bash
[root@k8s-master services]# kubectl describe ingress ingress1
Rules:
Host Path Backends
---- ---- --------
www.timinglee.org
/v1 servicev1:80 (10.244.2.26:80,10.244.5.109:80)
/v2 servicev2:80 (10.244.1.66:80,10.244.2.27:80)
在客户端机器上配置 hosts 解析,然后验证路径转发:
bash
[Administrator.DESKTOP-VJ307M3] ➤ vim /etc/hosts
172.25.254.50 www.timinglee.org
[Administrator.DESKTOP-VJ307M3] ➤ curl www.timinglee.org/v1
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[Administrator.DESKTOP-VJ307M3] ➤ curl www.timinglee.org/v2
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
9. Ingress 高级路由策略
9.1 基于域名的访问
同一个 Ingress 可以配置多个域名,每个域名对应不同的后端服务:
bash
[root@k8s-master services]# vim 2-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress1
spec:
ingressClassName: nginx
rules:
- host: myapp1.timinglee.org
http:
paths:
- backend:
service:
name: servicev1
port:
number: 80
path: /
pathType: Prefix
- host: myapp2.timinglee.org
http:
paths:
- backend:
service:
name: servicev2
port:
number: 80
path: /
pathType: Prefix
[root@k8s-master services]# kubectl apply -f 2-ingress.yaml
在客户端配置 hosts 后验证:
bash
[Administrator.DESKTOP-VJ307M3] ➤ vim /etc/hosts
172.25.254.50 www.timinglee.org myapp1.timinglee.org myapp2.timinglee.org
[Administrator.DESKTOP-VJ307M3] ➤ curl myapp1.timinglee.org
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[Administrator.DESKTOP-VJ307M3] ➤ curl myapp2.timinglee.org
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
9.2 基于动静分离的路由
通过正则表达式匹配路径,将动态请求(/php)和静态请求(/static)分发到不同的后端服务:
bash
[root@k8s-master services]# vim 3-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress1
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /index.html
spec:
ingressClassName: nginx
rules:
- host: www.timinglee.org
http:
paths:
- backend:
service:
name: servicev1
port:
number: 80
path: /php
pathType: ImplementationSpecific
- backend:
service:
name: servicev2
port:
number: 80
path: /static
pathType: ImplementationSpecific
[root@k8s-master services]# kubectl apply -f 3-ingress.yaml
验证动静分离效果:
bash
[Administrator.DESKTOP-VJ307M3] ➤ curl www.timinglee.org/php/
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[Administrator.DESKTOP-VJ307M3] ➤ curl www.timinglee.org/static/
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
9.3 TLS 加密访问
使用 openssl 生成自签名证书,创建 Secret,然后在 Ingress 中启用 HTTPS:
bash
[root@k8s-master ~]# openssl req -newkey rsa:2048 -nodes -keyout tls.key -x509 -days 365 -subj "/CN=nginxsvc/O=nginxsvc" -out tls.crt
[root@k8s-master ~]# kubectl create secret tls web-tls-secret --key tls.key --cert tls.crt
secret/web-tls-secret created
创建启用 TLS 的 Ingress:
bash
[root@k8s-master services]# vim 4-ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress1
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- myapp-tls.timinglee.org
secretName: web-tls-secret
ingressClassName: nginx
rules:
- host: myapp-tls.timinglee.org
http:
paths:
- backend:
service:
name: servicev1
port:
number: 80
path: /
pathType: Prefix
[root@k8s-master services]# kubectl apply -f 4-ingress.yml
在客户端配置 hosts 后,使用 HTTPS 协议访问:
bash
[Administrator.DESKTOP-VJ307M3] ➤ vim /etc/hosts
172.25.254.50 www.timinglee.org myapp1.timinglee.org myapp2.timinglee.org myapp-tls.timinglee.org
[Administrator.DESKTOP-VJ307M3] ➤ curl -k https://myapp-tls.timinglee.org
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
9.4 Basic Auth 认证
Ingress 支持为访问路径配置 Basic Auth 认证。首先安装工具并生成认证文件:
bash
[root@k8s-master ~]# dnf install httpd-tools -y
[root@k8s-master ~]# htpasswd -cm auth admin
[root@k8s-master ~]# cat auth
admin:$apr1$k8PiN9hR$TWLIGse6Y9oGgGFZr96P00
将认证文件创建为 Secret:
bash
[root@k8s-master ~]# kubectl create secret generic web-auth --from-file auth
在 Ingress 中配置认证注解:
bash
[root@k8s-master services]# vim 5-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress1
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: web-auth
nginx.ingress.kubernetes.io/auth-realm: "Please input username and password"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: www.timinglee.org
http:
paths:
- backend:
service:
name: servicev1
port:
number: 80
path: /v1
pathType: Prefix
[root@k8s-master services]# kubectl apply -f 5-ingress.yaml
验证认证效果,未带凭据访问返回 401,携带正确凭据可以正常访问:
bash
[Administrator.DESKTOP-VJ307M3] ➤ curl www.timinglee.org/v1
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
</body>
</html>
[Administrator.DESKTOP-VJ307M3] ➤ curl www.timinglee.org/v1 -u admin:lee
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
9.5 网页重写
通过 app-root 注解可以将根路径请求重定向到指定页面:
bash
[root@k8s-master services]# vim 6-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress1
annotations:
nginx.ingress.kubernetes.io/app-root: /hostname.html
spec:
ingressClassName: nginx
rules:
- host: www.timinglee.org
http:
paths:
- backend:
service:
name: servicev1
port:
number: 80
path: /
pathType: Prefix
[root@k8s-master services]# kubectl apply -f 6-ingress.yaml
验证重定向效果:
bash
[root@k8s-master services]# curl -I www.timinglee.org
HTTP/1.1 302 Moved Temporarily
Location: http://www.timinglee.org/hostname.html
[root@k8s-master services]# curl -L www.timinglee.org
myappv2-688fc4d776-5t7kt
也可以使用正则表达式实现更灵活的重写规则:
bash
[root@k8s-master services]# vim 6-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress1
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
rules:
- host: www.timinglee.org
http:
paths:
- backend:
service:
name: servicev1
port:
number: 80
path: /
pathType: Prefix
- backend:
service:
name: servicev2
port:
number: 80
path: /lee(/*.*/*|$)(.*)
pathType: ImplementationSpecific
[root@k8s-master services]# kubectl apply -f 6-ingress.yaml
验证正则重写效果:
bash
[root@k8s-master services]# curl -L www.timinglee.org
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@k8s-master services]# curl -L www.timinglee.org/lee
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
[root@k8s-master services]# curl -L www.timinglee.org/lee/a
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
10. 金丝雀发布(Canary)
金丝雀发布是一种渐进式发布策略,先将新版本流量引入一小部分,验证稳定后再逐步扩大。Nginx Ingress Controller 通过注解支持基于请求头和基于权重的灰度发布。
10.1 基于 Header 的灰度发布
创建两个 Ingress,主 Ingress 指向 v1 服务,金丝雀 Ingress 指向 v2 服务,并通过请求头 version: 2 触发灰度流量:
bash
[root@k8s-master services]# vim cannary.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress1
spec:
ingressClassName: nginx
rules:
- host: www.timinglee.org
http:
paths:
- backend:
service:
name: servicev1
port:
number: 80
path: /
pathType: Prefix
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress2
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "version"
nginx.ingress.kubernetes.io/canary-by-header-value: "2"
spec:
ingressClassName: nginx
rules:
- host: www.timinglee.org
http:
paths:
- backend:
service:
name: servicev2
port:
number: 80
path: /
pathType: Prefix
[root@k8s-master services]# kubectl apply -f cannary.yaml
验证效果:不带请求头访问返回 v1,携带 version: 2 请求头访问返回 v2:
bash
[Administrator.DESKTOP-VJ307M3] ➤ curl www.timinglee.org
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[Administrator.DESKTOP-VJ307M3] ➤ curl -H "version:2" www.timinglee.org
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
10.2 基于权重的灰度发布
修改金丝雀 Ingress 注解,将触发方式改为权重,10% 流量进入 v2:
bash
[root@k8s-master services]# vim cannary.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress2
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
ingressClassName: nginx
rules:
- host: www.timinglee.org
http:
paths:
- backend:
service:
name: servicev2
port:
number: 80
path: /
pathType: Prefix
[root@k8s-master services]# kubectl apply -f cannary.yaml
验证效果,多次访问约 10% 请求返回 v2:
bash
[Administrator.DESKTOP-VJ307M3] ➤ for i in {1..10}; do curl -s www.timinglee.org | grep Version; done
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>