Kubernetes 微服务网络实践:Service 与 Ingress 从入门到灰度发布

**摘要:**本文基于真实虚拟机环境,演示 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>
相关推荐
众人皆醒我独醉1 小时前
Kubernetes GPU 调度与管理的完整机制——从节点上架到 Pod 拿到 GPU
面试·kubernetes·gpu
晊晌_h1 小时前
嵌入式从0到精通——Linux 网络通信|TCP、HTTP 网络编程
linux·c语言·网络
池以遇1 小时前
云原生——k8s中的微服务
微服务·云原生·kubernetes
姚不倒1 小时前
Tengine 实战:主动健康检查 + 动态 Upstream 配置
运维·网络·nginx
茶栀(*´I`*)1 小时前
Python网络机器人入门:从Robots协议、网页结构到Requests库的基础实践
网络·python·机器人
Ai思想家2 小时前
一次模型调用会留下什么:聚合平台的日志留存与数据边界
大数据·服务器·网络·人工智能
筝筝ba2 小时前
linux查询某个网卡是否插了对应网线的命令
linux·运维·网络
姚不倒2 小时前
HAProxy 系列(二):健康检查与 SSL 卸载 — 保障可用性与性能
运维·网络·网络协议·ssl·haproxy
ue星空2 小时前
登录失败:failed to start login server: 以一种访问权限不允许的方式做了一个访问套接字的尝试。 (os error 10013)
网络·codex