【云原生】Gateway API路由、重定向、修饰符等关键操作

Gateway API路由、重定向、修饰符等关键操作

文章目录

一、HTTP路由

  • HTTPRoute资源可匹配HTTP流量并将其路由至Kubernetes后端,本指南将说明HTTPRoute如何基于主机、请求头和路径字段匹配流量,并将其转发到不同的Kubernetes服务。
  • 以下流程描述了三个不同服务之间的指定流量走向:
    • 发送foo.example.com/login的流量,转发至foo-svc
    • 发往bar.example.com/*且带有env: canary请求头的流量,转发至bar-svc-canary
    • 发送bar.example.com/*且无该请求头的流量,转发至bar-svc
  • 虚线代表用于配置此路由行为而部署的Gateway资源。有两个HTTPRoute资源会在同一个prod-web网关之上创建按路由规则。这一示例体现了多个路由可以绑定到同一个网关的实现方式------只要这些路由之间不存在冲突,它们就能够在网关上完成规则合并。

1.1、环境配置Istio

  • 之前我们采用的GatewayClass用的是Envoy,不过Envoy无法满足我们学习Gateway的需求,比如在后续的学习中我们会学到重定向之类的技能,但是Envoy不支持307和308状态码,而只支持301之类的,所以我们要部署一个Istio服务网格。
bash 复制代码
[root@master ~]# wget https://github.com/istio/istio/releases/download/1.18.1/istio-1.18.1-linux-amd64.tar.gz
[root@master ~]# tar -zxvf istio-1.18.1-linux-amd64.tar.gz
[root@master ~]# cd istio-1.18.1/
[root@master istio-1.18.1]# cp bin/istioctl /usr/local/bin/
  • 因为我们是本地学习并不是生产,所以部署istiodemo版本就可以满足了。
bash 复制代码
[root@master istio-1.18.1]# istioctl install --set profile=demo -y
✔ Istio core installed                                                                                                  
✔ Istiod installed                                                                                                      
✔ Egress gateways installed                                                                                             
✔ Ingress gateways installed                                                                                            
✔ Installation complete                                                                                                 Making this installation the default for injection and validation.


[root@master istio-1.18.1]# kubectl get pod -n istio-system 
NAME                                    READY   STATUS    RESTARTS   AGE
istio-egressgateway-7f49c9d8b4-dcn48    1/1     Running   0          4m12s
istio-ingressgateway-54dc9548db-4pfhn   1/1     Running   0          4m12s
istiod-7694fbf654-8n8j7                 1/1     Running   0          4m32s
1.1.1、IstioClass
  • 部署好Istio之后,它会自动帮我们在default命名空间下创建一个IstioClass我们看一下。
bash 复制代码
[root@master ~]# kubectl get gc
NAME    CONTROLLER                                      ACCEPTED   AGE
eg      gateway.envoyproxy.io/gatewayclass-controller   True       27m
istio   istio.io/gateway-controller                     True       5m47s
  • 我们再看一下这个Istio这个class怎么写的。
bash 复制代码
[root@master ~]# kubectl get gc istio -o yaml
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  creationTimestamp: "2025-12-18T01:46:09Z"
  generation: 1
  name: istio
  resourceVersion: "9240"
  uid: df37e3a5-e6cf-4873-b8f2-e030a02b9df8
spec:
  controllerName: istio.io/gateway-controller
  description: The default Istio GatewayClass
status:
  conditions:
  - lastTransitionTime: "2025-12-18T01:46:09Z"
    message: Handled by Istio controller
    observedGeneration: 1
    reason: Accepted
    status: "True"
    type: Accepted
  • 我们只需要关心controllerName字段、status字段。

1.2、默认路由

  • 若要从网关接收流量,必须为HTTPRoute资源配置ParentRefs字段,该字段用于指定此HTTPRoute应关联的上级网关。

  • 先创建一下这个Gateway后端资源deployment、service

bash 复制代码
[root@master ~]# cat deployment_defaulthttp.yaml 
apiVersion: "apps/v1"
kind: Deployment
metadata:
  name: default-http
  labels:
    app: default-http
spec:
  replicas: 1
  selector:
    matchLabels:
      app: default-http
  template:
    metadata:
      labels:
        app: default-http
    spec:
      containers:
      - name: test-default-http
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

---

apiVersion: "v1"
kind: Service
metadata:
  name: example-svc
spec:
  selector:  
    app: default-http   
  type: ClusterIP
  ports:
  - port: 80  
    targetPort: 80  
  • 下面开始创建Gateway、HTTPRoute
  • 下面的资源将会接收example.com的流量,然后把流量转发到后端example-svc服务的80端口。
bash 复制代码
[root@master ~]# cat defaulthttp.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: example-gateway
spec:
  gatewayClassName: istio  # 关联的 GatewayClass
  listeners:
  - name: http  # 监听器的名字 
    protocol: HTTP   # 协议
    port: 80    # 端口
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: example-route
spec:
  parentRefs:
  - name: example-gateway  # 关联的 Gateway
  hostnames:
  - "example.com"   # 使用域名提供服务
  rules:
  - backendRefs:    # 后端 Service
    - name: example-svc
      port: 80
  • 部署一下
bash 复制代码
[root@master ~]# kubectl apply -f defaulthttp.yaml
gateway.gateway.networking.k8s.io/example-gateway created
httproute.gateway.networking.k8s.io/example-route created
  • 查看一下创建的资源
  • 通过查看的资源我们可以得知,gateway给我们分配了一个lb地址,因为我们没有使用dns,所以要做一下hosts的域名解析。
bash 复制代码
[root@master ~]# kubectl get gateway,httproute
NAME                                                CLASS   ADDRESS         PROGRAMMED   AGE
gateway.gateway.networking.k8s.io/example-gateway   istio   192.168.93.12   True         33s

NAME                                                HOSTNAMES         AGE
httproute.gateway.networking.k8s.io/example-route   ["example.com"]   33s
bash 复制代码
[root@master ~]# echo "192.168.93.12 example.com" >> /etc/hosts
  • 访问一下
bash 复制代码
[root@master ~]# curl example.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
  • 通过访问的回显可以看到拿到了我们预期的结果了。这就是一个很简单的使用案例了。
  • 一个HTTPRoute资源仅能匹配一组域名。在该HTTPRoute执行其他任何匹配规则之前,会优先对这些域名进行匹配校验。

1.3、路径匹配规则路由

  • 下面的foo-route路由会匹配发往foo.example.com的所有流量,并指定其路由规则,将其转发至对应的后端服务。

  • 由于该路由仅配置了一条匹配规则,因此只有发往foo.example.com/login/*的流量会被转发;所有发往非/login开头的路径的流量,都不会被此路由匹配。

  • 先创建一下这个Gateway后端资源deployment、service,如果嫌麻烦的话,直接用默认路由标题创建的deployment也是可以的。

bash 复制代码
[root@master ~]# cat deployment_pathprefixhttp.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-default-conf  # ConfigMap 名称,后续挂载到 Pod 中使用
  labels:
    app: pathprefix-http
data:
  default.conf: |
    server {
        listen       80;
        listen  [::]:80;
        server_name  localhost;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        # 新增 /login 路由规则:直接返回
        location /login {
            default_type text/plain;  # 指定返回内容类型为纯文本
            return 200 "foo-svc Service";       # 200 是HTTP状态码,"retue"是返回内容
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }
---
apiVersion: "apps/v1"
kind: Deployment
metadata:
  name: pathprefix-http
  labels:
    app: pathprefix-http
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pathprefix-http
  template:
    metadata:
      labels:
        app: pathprefix-http
    spec:
      containers:
      - name: test-pathprefix-http
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        # 挂载 ConfigMap 到 Nginx 配置目录
        volumeMounts:
        - name: nginx-conf
          mountPath: /etc/nginx/conf.d/default.conf  # 直接覆盖默认配置文件
          subPath: default.conf  # 指定 ConfigMap 中的配置文件
      # 定义挂载的 ConfigMap 卷
      volumes:
      - name: nginx-conf
        configMap:
          name: nginx-default-conf  # 关联上面创建的 ConfigMap 名称
          items:
          - key: default.conf      # ConfigMap 中存储配置的 key
            path: default.conf     

---

apiVersion: "v1"
kind: Service
metadata:
  name: foo-svc  # svc 的名字
spec:
  selector:  
    app: pathprefix-http   
  type: ClusterIP
  ports:
  - port: 80  
    targetPort: 80  
  • 部署一下资源
bash 复制代码
[root@master ~]# kubectl apply -f deployment_pathprefixhttp.yaml 
deployment.apps/pathprefix-http created
service/foo-svc created
  • 为了更好的区别我们的流量,我们在这次的控制器挂在了configmapnignx的配置文件,访问login直接返回foo-svc Service
bash 复制代码
[root@master ~]# kubectl exec -it pathprefix-http-57c785c894-89prh -- sh -c 'echo "foo-svc" > /usr/share/nginx/html/index.html'

[root@master ~]# kubectl get svc | grep foo-svc
foo-svc                 ClusterIP      10.97.52.143     <none>          80/TCP                         4m39s
[root@master ~]# curl 10.97.52.143/login
foo-svc Service
  • 下面开始创建HTTPRoute,直接使用刚开始创建的Gateway,因为Gateway可以被作为统一入口进行关联使用。
bash 复制代码
[root@master ~]# cat pathprefixhttp.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: foo-route
spec:
  parentRefs:
  - name: example-gateway   # Gateway 可以作为统一入口, 供 HTTPRoute 使用的
  hostnames:
  - "foo.example.com"   # 使用域名提供服务
  rules:
  - matches:   # 规则匹配
    - path:
        type: PathPrefix   # 根据路径前缀匹配
        value: /login    # 跟 nginx 一样匹配 /login 路由
    backendRefs:
    - name: foo-svc
      port: 80
  • 部署一下
bash 复制代码
[root@master ~]# kubectl apply -f pathprefixhttp.yaml
httproute.gateway.networking.k8s.io/foo-route created
  • 查看一下创建的资源
bash 复制代码
[root@master ~]# kubectl get httproute foo-route 
NAME        HOSTNAMES             AGE
foo-route   ["foo.example.com"]   4m1s
  • 做一下域名解析,然后访问
bash 复制代码
[root@master ~]# echo "192.168.93.12 foo.example.com" >> /etc/hosts 
[root@master ~]# curl foo.example.com/login
foo-svc Service
  • 通过刚刚的访问可以看到,跟我们预期的期望是一样的,如果访问的是HTTPRoute不存在的规则,那么将不会有任何回显。
bash 复制代码
# 这个 404 是 istio 跑出来的, 并不是 nginx 的404
[root@master ~]# curl foo.example.com -I
HTTP/1.1 404 Not Found
date: Thu, 18 Dec 2025 02:46:03 GMT
server: istio-envoy
transfer-encoding: chunked
  • istio也会根据Gateway创建响应的pod,我们去看一下日志。
bash 复制代码
[root@master ~]# kubectl logs --tail=1 example-gateway-istio-5bf75776f-j2xvx 
[2025-12-18T02:46:03.971Z] "HEAD / HTTP/1.1" 404 NR route_not_found - "-" 0 0 0 - "10.244.219.64" "curl/7.79.1" "d474de01-acb3-9588-821e-9ada49dd8763" "foo.example.com" "-" - - 10.244.166.136:80 10.244.219.64:31409 - -

1.4、带有请求头的规则路由

  • 下面的这个HTTPRoute会匹配发往bar.example.com的流量。该域名下的所有流量都会依据路由规则进行匹配------最具体的匹配规则会优先生效 :即带有env: canary请求头的流量会被转发至bar-svc-canary;若请求头缺失,或者值不是canary,则流量会被转发至bar-svc

  • 这次为了简单一些,直接使用默认路由 充当无头部信息访问的Service (example-svc),当有头部信息的被匹配到的时候访问Service (foo-svc)

  • 创建HTTPRoute资源

bash 复制代码
[root@master ~]# cat headerhttp.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: bar-route
spec:
  parentRefs:
  - name: example-gateway
  hostnames:
  - "bar.example.com"  # 使用域名提供服务
  rules:
  - matches:
    - headers:  # 匹配规则
      - type: Exact  # 精确匹配
        name: env    # 请求头
        value: canary   # 请求头的值
    backendRefs: # 带有头部信息的 svc
    - name: foo-svc
      port: 80
  - backendRefs:  # 没有头部信息的 svc
    - name: example-svc
      port: 80
  • 部署一下
bash 复制代码
[root@master ~]# kubectl apply -f  headerhttp.yaml 
httproute.gateway.networking.k8s.io/bar-route created
  • 查看一下创建的资源
bash 复制代码
[root@master ~]# kubectl get httproute bar-route 
NAME        HOSTNAMES             AGE
bar-route   ["bar.example.com"]   82s
  • 做一下域名解析,然后访问
bash 复制代码
[root@master ~]# echo "192.168.93.12 bar.example.com" > /etc/hosts 
1.4.1、改动Deployment资源
  • 只需要稍微改动一下我们就可以看到带有头部访问和不带头部范文的效果。
bash 复制代码
# foo-svc Service
[root@master ~]# kubectl exec -it pathprefix-http-8c9dcb686-57qst -- sh -c "echo "head" > /usr/share/nginx/html/index.html"

# example-svc Service
[root@master ~]# kubectl exec -it default-http-78d4bd4ff8-nqfnc -- sh -c "echo ""no head"" > /usr/share/nginx/html/index.html"
1.4.2、带有头部访问
bash 复制代码
[root@master ~]# curl -H "env: canary" bar.example.com
head
  • 跟我们预期的一样,带有规则的头部信息将会访问到foo-svc
1.4.3、没有头部的访问
bash 复制代码
[root@master ~]# curl bar.example.com
no head
  • 或者头部信息不匹配也都将访问example-svc的业务
bash 复制代码
[root@master ~]# curl -H "env: test" bar.example.com
no head

二、HTTP头部修饰符

  • HTTPRoute资源可修改客户端发起的HTTP请求头,以及服务器返回HTTP响应头。有两种过滤器可以满足此类需求:RequestHeaderModifier(请求头修饰器)ResponseHeaderModifier(响应头修饰器)

2.1、创建命名空间区分

  • 以防止做的操作乱掉、所以创建一个新的命名空间。
bash 复制代码
[root@master ~]# kubectl create ns modifiers
namespace/modifiers created

2.2、HTTP请求头修改器

  • HTTP头修改指的是再入站请求中添加、移除或者修改`HTTP头的过程。

  • 如需要配置HTTP头修改功能,需定义一个包含一个或多个HTTP过滤器的网关(Gateway)对象。每个过滤器都会指定对入站请求执行的具体修改操作,例如添加自定义请求头或者修改现有请求头。

  • 若要为HTTP请求添加请求头,可使用类型为RequestHeaderModifier的过滤器,配置工作类型为add,并同时指定待添加请求头的名称

  • 先部署一个进行这次演示Deployment和Service

bash 复制代码
[root@master ~]# cat modifier-deployment.yaml 
# 1. ConfigMap:存储自定义NGINX配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: modifier-nginx-config
  namespace: modifiers
data:
  default.conf: |
    server {
        listen       80;
        listen  [::]:80;
        server_name  localhost;

        # 新增/add-a-request-header路由,直接return返回(状态码200+自定义响应)
        location /add-a-request-header {
            # return指令:直接返回响应,无需转发
            # 格式:return 状态码 [响应内容/重定向地址];
            #return 200 '{"code":200,"msg":"Success","path":"/add-a-request-header"}';
          return 200 '{"code":200,"msg":"Gateway添加的请求头已生效","request_header": {"my-header-name":"$http_my_header_name"}}';
            # 设置响应Content-Type,避免浏览器解析异常
            add_header Content-Type application/json;
        }

        # 原有根路径配置
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }

---

# 2. Deployment:部署NGINX容器,挂载ConfigMap覆盖默认配置
apiVersion: apps/v1
kind: Deployment
metadata:
  name: modifier-http
  namespace: modifiers
  labels:
    app: modifier-http
spec:
  replicas: 1
  selector:
    matchLabels:
      app: modifier-http
  template:
    metadata:
      labels:
        app: modifier-http
    spec:
      containers:
      - name: test-modifier-http
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        # 挂载ConfigMap到NGINX配置目录,覆盖默认的default.conf
        volumeMounts:
        - name: nginx-config-volume
          mountPath: /etc/nginx/conf.d/default.conf  # 直接覆盖默认配置文件
          subPath: default.conf  # 指定ConfigMap中的key
      # 定义卷:关联上面的ConfigMap
      volumes:
      - name: nginx-config-volume
        configMap:
          name: modifier-nginx-config  # 关联创建的ConfigMap名称
          items:
          - key: default.conf
            path: default.conf  # 卷内的路径,对应subPath

---

# 3. Service:暴露Deployment的80端口
apiVersion: v1
kind: Service
metadata:
  name: modifier-http
  namespace: modifiers
spec:
  selector:  
    app: modifier-http   
  type: ClusterIP
  ports:
  - port: 80  
    targetPort: 80
  • 部署一下,并且查看一下状态
bash 复制代码
[root@master ~]# kubectl apply -f modifier-deployment.yaml 
configmap/modifier-nginx-config created
deployment.apps/modifier-http created
service/modifier-http created
[root@master ~]# kubectl get pod,svc,cm -n modifiers 
NAME                                 READY   STATUS    RESTARTS   AGE
pod/modifier-http-64fb45d67f-b6lrl   1/1     Running   0          12s

NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/example-svc     ClusterIP   10.106.248.48   <none>        80/TCP    12m
service/modifier-http   ClusterIP   10.102.26.62    <none>        80/TCP    12s

NAME                              DATA   AGE
configmap/istio-ca-root-cert      1      34m
configmap/kube-root-ca.crt        1      34m
configmap/modifier-nginx-config   1      12s
  • 创建GatewayHTTPRoute
bash 复制代码
[root@master ~]# cat add-modifier.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: acme-gw
  namespace: modifiers
spec:
  gatewayClassName: istio
  listeners:
  - name: http
    protocol: HTTP
    port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: header-http-echo
  namespace: modifiers
spec:
  parentRefs:
    - name: acme-gw
  hostnames:
  - "modifier.example.com"
  rules:  # 规则
    - matches:   # 匹配条件: 满足条件的流量才会走该规则
        - path:
            type: PathPrefix  # 路径匹配类型: 前缀匹配(支持Exact/PathPrefix/RegularExpression)
            value: /add-a-request-header   # 匹配的前缀
      filters:  # 过滤链, 匹配后转发到后端的处理逻辑
        - type: RequestHeaderModifier  # 过滤器类型, 修改请求头
          requestHeaderModifier:
            add:   # 动作: 添加请求头
              - name: my-header-name     # 要添加的头名称
                value: my-header-value   # 头值
      backendRefs:
        - name: modifier-http  # 目标 Service
          port: 80
  • 部署一下
bash 复制代码
[root@master ~]# kubectl apply -f add-modifier.yaml
gateway.gateway.networking.k8s.io/acme-gw created
httproute.gateway.networking.k8s.io/header-http-echo created
  • 访问验证一下
bash 复制代码
# 要做一下 hosts 解析
[root@master ~]# echo "192.168.93.12 modifier.example.com" >> /etc/hosts
bash 复制代码
# 访问匹配的路径(/add-a-request-header)看看是否可以给我们添加一个头部信息
[root@master ~]# curl modifier.example.com/add-a-request-header
{"code":200,"msg":"Gateway添加的请求头已生效","request_header": {"my-header-name":"my-header-value"}}
  • 部署的configmap里面添加了/add-a-request-header路由并且直接访问打印出来请求头的value

  • 接下来,我们使用set动作修改请求头部中的key-value

bash 复制代码
# 首先更改一下 configmap 的配置, 只需要更改 return  即可
[root@master ~]# kubectl edit configmaps -n modifiers modifier-nginx-config
            return 200 '{"client_send_accept":"$http_accept_original","backend_receive_accept":"$http_accept"}';


# 重启一下 pod
[root@master ~]# kubectl rollout restart deployment -n modifiers modifier-http 
deployment.apps/modifier-http restarted
  • 我们去更改一下,只需要把add工作更改为set动态即可,然后保存退出
bash 复制代码
[root@master ~]# kubectl edit -n modifiers httproute header-http-echo
        set:
        - name: accept
          value: application/xml  # 默认值: "*/*"
  • 我们访问一下
bash 复制代码
[root@master ~]# curl http://modifier.example.com/add-a-request-header
{"client_send_accept":"","backend_receive_accept":"application/xml"}
  • 也可以使用remove关键字并指定待删和请求头名称列表,来移除请求头。
bash 复制代码
[root@master ~]# kubectl edit -n modifiers httproute header-http-echo
    filters:
    - requestHeaderModifier:
        remove:
        - User-Agent

2.3、HTTP响应头修改器

  • HTTP响应头修改器与编辑请求头的实用价值同理,编译相应头也有着诸多用途。例如,它能让技术团队仅针对特定后端服务添加或者删除Cookie,这有助于识别哪些此前被重定向至该后端服务的特定用户。
  • 另一个潜在的应用场景是:当前端需要判断其对接的后端服务器的稳定版本还是测试版本时,就可以通过修改响应头来实现,进而渲染不同的用户界面,或者响应地调整自身的响应数据解析逻辑。
  • 修改HTTP响应头所使用的语法,与修改原始请求头的语法极为相似,二者的区别仅在于使用的过滤器不同而已,
  • 响应头支持添加、编辑和删除,也可以一次性添加多个响应头,示例如下:
bash 复制代码
[root@master ~]# cat response-modifier.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: response-http-echo
  namespace: modifiers
  # 可选:添加标签便于管理
  labels:
    app: response-modifier
    gateway: acme-gw
spec:
  # 关联的网关
  parentRefs:
    - name: acme-gw
  # 匹配的域名
  hostnames:
    - "response.example.com"
  # 路由规则
  rules:
    # 取消路径匹配,默认匹配所有路径(包括 /)
    - filters:
        # 响应头修改过滤器
        - type: ResponseHeaderModifier
          responseHeaderModifier:
            add:
              - name: X-Header-Add-1
                value: header-add-1
              - name: X-Header-Add-2
                value: header-add-2
              - name: X-Header-Add-3
                value: header-add-3
      # 后端服务关联
      backendRefs:
        - name: modifier-http
          port: 80
  • 部署一下
bash 复制代码
[root@master ~]# kubectl apply -f response-modifier.yaml 
httproute.gateway.networking.k8s.io/response-http-echo created
  • 访问测试一下,访问前需要做hosts解析
bash 复制代码
[root@master ~]# echo "192.168.93.12 response.example.com" >> /etc/hosts
bash 复制代码
[root@master ~]# curl response.example.com -v
*   Trying 192.168.93.12:80...
* Connected to response.example.com (192.168.93.12) port 80 (#0)
> GET / HTTP/1.1
> Host: response.example.com
> User-Agent: curl/7.79.1
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< server: istio-envoy
< date: Thu, 18 Dec 2025 08:17:43 GMT
< content-type: text/html
< content-length: 615
< last-modified: Tue, 28 Dec 2021 15:28:38 GMT
< etag: "61cb2d26-267"
< accept-ranges: bytes
##############################################################
< x-envoy-upstream-service-time: 1
< x-header-add-1: header-add-1
< x-header-add-2: header-add-2
< x-header-add-3: header-add-3
##############################################################
< 
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>

三、HTTP请求镜像

  • HTTPRoute资源可用于将请求镜像复制至多个后端服务。这一功能在利用生成流量测试新服务时十分实用。
  • 请求镜像功能在蓝绿部署场景下尤为适用。它可以在完全不影响客户端响应结果的前端下,评估新服务对应用性能的影响。
  • 其实就是把请求复制多份,分别发送到别的svc流量上,但不会影响到真正的svc去处理客户的请求。

3.1、创建命名空间区分

bash 复制代码
[root@master ~]# kubectl create ns cp-image
namespace/cp-image created

3.2、创建Deployment、Svc资源

bash 复制代码
[root@master ~]# cat cp-image-deployment.yaml 
apiVersion: "apps/v1"
kind: Deployment
metadata:
  name: image-1-http
  namespace: cp-image
  labels:
    app: image-1-http
spec:
  replicas: 1
  selector:
    matchLabels:
      app: image-1-http
  template:
    metadata:
      labels:
        app: image-1-http
    spec:
      containers:
      - name: test-image-1-http
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

---

apiVersion: "v1"
kind: Service
metadata:
  name: foo-v1
  namespace: cp-image
spec:
  selector:  
    app: image-1-http   
  type: ClusterIP
  ports:
  - port: 80  
    targetPort: 80  


---


apiVersion: "apps/v1"
kind: Deployment
metadata:
  name: image-2-http
  namespace: cp-image
  labels:
    app: image-2-http
spec:
  replicas: 1
  selector:
    matchLabels:
      app: image-2-http
  template:
    metadata:
      labels:
        app: image-2-http
    spec:
      containers:
      - name: test-image-2-http
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

---

apiVersion: "v1"
kind: Service
metadata:
  name: foo-v2
  namespace: cp-image
spec:
  selector:  
    app: image-2-http   
  type: ClusterIP
  ports:
  - port: 80  
    targetPort: 80
  • 部署一下
bash 复制代码
[root@master ~]# kubectl apply -f cp-image-deployment.yaml 
deployment.apps/image-1-http created
service/foo-v1 created
deployment.apps/image-2-http created
service/foo-2 created
  • 修改一下index内容
bash 复制代码
# foo-v1
[root@master ~]# kubectl exec -it -n cp-image image-1-http-76bb4959b6-zd6s9 -- sh -c "echo "foo-v1" > /usr/share/nginx/html/index.html"


# foo-v2
[root@master ~]# kubectl exec -it -n cp-image image-2-http-6dcc98f4b-hsrts -- sh -c "echo "foo-v2" > /usr/share/nginx/html/index.html"

3.2、创建Gateway、HTTPRote

  • 接下来我们将创建的HTTPRoute,所有请求将会被转发到foo-v1服务上,同时也会被转发至foo-v2服务上,但仅由foo-v1服务生成响应并返回给客户端。
bash 复制代码
[root@master ~]# cat request-image-httproute.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: mirror-gateway
  namespace: cp-image
spec:
  gatewayClassName: istio
  listeners:
  - name: http
    protocol: HTTP
    port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-filter-mirror
  namespace: cp-image
  labels:
    gateway: mirror-gateway
spec:
  parentRefs:
  - name: mirror-gateway
  hostnames:
  - mirror.example
  rules:
  - backendRefs:
    - name: foo-v1
      port: 80
    filters:
    - type: RequestMirror # 规则类型: 请求复制
      requestMirror:
        backendRef:
          name: foo-v2
          port: 80
  • 部署一下
bash 复制代码
[root@master ~]# kubectl apply -f  request-image-httproute.yaml
gateway.gateway.networking.k8s.io/mirror-gateway created
httproute.gateway.networking.k8s.io/http-filter-mirror created
  • 查看一下资源
bash 复制代码
[root@master ~]# kubectl get gateway,httproute -n cp-image 
NAME                                               CLASS   ADDRESS         PROGRAMMED   AGE
gateway.gateway.networking.k8s.io/mirror-gateway   istio   192.168.93.13   True         60s

NAME                                                     HOSTNAMES            AGE
httproute.gateway.networking.k8s.io/http-filter-mirror   ["mirror.example"]   60s
  • 做一下hosts解析
bash 复制代码
[root@master ~]# echo "192.168.93.13 mirror.example" >> /etc/hosts
  • 访问之前使用命令持续查看image-1-httpimage-2-http的pod日志(多开几个终端)
bash 复制代码
# image-1-http 
[root@master ~]# kubectl logs -n cp-image image-1-http-76bb4959b6-zd6s9 -f
bash 复制代码
# image-2-http 
[root@master ~]# kubectl logs -n cp-image image-2-http-6dcc98f4b-hsrts -f
  • 进行访问测试
bash 复制代码
[root@master ~]# curl mirror.example
foo-v1
  • 回头查看日志
bash 复制代码
# image-1-http 
[root@master ~]# kubectl logs -n cp-image image-1-http-76bb4959b6-zd6s9 -f
10.244.166.150 - - [18/Dec/2025:08:49:23 +0000] "GET / HTTP/1.1" 200 7 "-" "curl/7.79.1" "10.244.219.64"
bash 复制代码
# image-2-http 
[root@master ~]# kubectl logs -n cp-image image-2-http-6dcc98f4b-hsrts -f
10.244.166.150 - - [18/Dec/2025:08:49:23 +0000] "GET / HTTP/1.1" 200 7 "-" "curl/7.79.1" "10.244.219.64,10.244.166.150"
  • Gateway只给我们返回了foo-v1的响应,并且我们的请求也发送到了foo-v2
相关推荐
小二·2 小时前
Go 语言系统编程与云原生开发实战(第8篇)消息队列实战:Kafka 事件驱动 × CQRS 架构 × 最终一致性(生产级落地)
云原生·golang·kafka
研究司马懿3 小时前
【云原生】初识Gateway API
云原生·gateway
java干货11 小时前
<span class=“js_title_inner“>微服务:把一个简单的问题,拆成 100 个网络问题</span>
微服务·云原生·架构
Spring_java_gg16 小时前
<span class=“js_title_inner“>面向云原生时代的 LLM 推理|Kthena入局了!!!</span>
云原生
eso198320 小时前
如何确保程序化广告系统中微服务架构的高可用性和可扩展性?
微服务·云原生·架构
江畔何人初21 小时前
/etc/profile,.profile,.bashrc三者区分
linux·运维·云原生
努力搬砖的咸鱼1 天前
部署你的第一个应用到 K8s
微服务·云原生·容器·kubernetes
舰长1151 天前
使用 kubeadm搭建生产环境的单 master 节点 K8S 集群(一)
云原生·容器·kubernetes