kong网关基于header分流灰度发布

kong网关基于header分流灰度发布

在现代微服务架构中,灰度发布(Canary Release)已经成为一种常用且安全的上线策略。它允许我们将新版本的功能仅暴露给一小部分用户,从而在保证系统稳定性的同时收集反馈、验证效果、规避风险。而作为一款轻量高性能的 API 网关,Kong 提供了灵活的路由规则,使得我们可以通过配置请求头、Cookie、路径等条件,实现基于规则的流量分流。

本文将聚焦于一种实用的灰度发布方案:基于请求头(Header)进行流量分发。我们将以 X-App-Version 等请求头为判断依据,将部分请求引导至灰度环境(如 backend-v2),其余流量仍然指向正式环境(backend-v1)。通过 Kong 的声明式配置方式,可以轻松实现无数据库、无插件依赖的灰度发布策略,特别适合前后端联调、测试环境验证以及轻量化场景。

在这里插入图片描述

本篇文章将从实际业务需求出发,介绍如何使用 Kong 网关进行权重分流的灰度发布,包括:

  • Kong 中实现header分流的配置;

  • 如何基于 Docker Compose 部署一个 DB-less 模式的灰度发布环境;

  • 配置示例讲解:如何将v2流量导向新版本服务 backend-v2,v1保持在旧版本 backend-v1;

前置条件

节点规划如下:

主机名节点IP监听端口操作系统
frontend192.168.73.118080Ubuntu 24.04
backend-v1192.168.73.113001Ubuntu 24.04
backend-v2192.168.73.113002Ubuntu 24.04
kong-gateway192.168.73.118000Ubuntu 24.04

已安装 Docker 和 docker-compose工具。

无DB模式部署kong网关

创建kong.yml声明式配置文件:

root@ubuntu:/data/apps/kong# cat kong.yml 
_format_version: "3.0"services:- name: backend-serviceurl: http://backend-v1:3000- name: backend-service-grayurl: http://backend-v2:3000routes:- name: backend-route-grayservice: backend-service-graypaths:- /adminheaders:X-App-Version:- v2strip_path: false- name: backend-routeservice: backend-servicepaths:- /adminstrip_path: falseplugins:- name: corsconfig:origins:- "*"methods:- GET- POST- PUT- DELETE- OPTIONSheaders:- Accept- Authorization- Content-Type- X-Requested-With- X-App-Versionexposed_headers:- X-Custom-Headercredentials: truemax_age: 3600

配置参数说明:

好的,以下是你提供的这份 Kong 声明式配置(kong.yml)的逐项参数详解,特别聚焦于灰度发布与 CORS 支持相关部分:


_format_version: "3.0"

  • 说明:声明配置文件的格式版本,Kong 3.x 需要为 "3.0"
  • 作用:Kong 用来解析声明式配置,必须写。

services

定义了两个后端服务(一个正式,一个灰度):

  1. backend-service
- name: backend-serviceurl: http://backend-v1:3000
  • name:服务名称,用于 route 映射。
  • url:实际后端地址,这里是正式环境 backend-v1 的 3000 端口。
  • 备注:省略了 host/port/protocol 的写法,直接用 url 更简洁。
  1. backend-service-gray
- name: backend-service-grayurl: http://backend-v2:3000
  • 同上,只不过这是灰度环境的服务地址(backend-v2)。

routes

定义了两条路由规则,基于路径和请求头进行分流:

  1. backend-route-gray
- name: backend-route-grayservice: backend-service-graypaths:- /adminheaders:X-App-Version:- v2strip_path: false
  • name:路由名称。
  • service:绑定到灰度服务 backend-service-gray
  • paths:匹配 /admin 路径的请求。
  • headers:匹配请求头 X-App-Version: v2 的请求。
  • strip_path:为 false 表示保留 /admin 前缀,不会从请求 URL 中剥离。
  1. backend-route
- name: backend-routeservice: backend-servicepaths:- /adminstrip_path: false
  • 匹配 /admin 的默认路由,绑定到正式服务 backend-service
  • 没有 header 限制,所有不匹配前面 route 的请求都会走这个。

⚠️ 匹配顺序重要backend-route-gray 必须在前面,Kong 按顺序匹配 route,先匹配成功的就执行,后面的不再判断。


plugins

配置了全局的 CORS(跨域资源共享)插件:

- name: corsconfig:origins:- "*"methods:- GET- POST- PUT- DELETE- OPTIONSheaders:- Accept- Authorization- Content-Type- X-Requested-With- X-App-Versionexposed_headers:- X-Custom-Headercredentials: truemax_age: 3600

参数说明:

参数说明
origins允许哪些源(Origin)跨域访问。* 表示全部允许
methods允许的 HTTP 方法
headers允许客户端请求时携带的请求头(包括自定义的如 X-App-Version
exposed_headers响应中暴露给前端的响应头
credentials是否允许携带 Cookie、认证信息等
max_age预检请求(OPTIONS)结果缓存时间(秒)

最终请求 http://kong网关/admin

  • 如果带 X-App-Version: v2 请求头 → 进入 灰度服务
  • 如果不带或值不为 v2 → 进入 正式服务
  • 启用了全局的 CORS 支持,适合 Web 前端跨域请求调用 API

创建docker外部网络,打通kong网关与前后端服务网络

docker network create app_network

创建部署kong网关的docker-compose.yaml

root@ubuntu:/data/apps/kong# cat docker-compose.yaml
name: 'kong-gateway'services:kong:image: kong:3.9.1container_name: kong-gatewayrestart: alwaysenvironment:KONG_DATABASE: "off"KONG_DECLARATIVE_CONFIG: /usr/local/kong/declarative/kong.yml# kong proxyKONG_PROXY_LISTEN: 0.0.0.0:8000KONG_PROXY_LISTEN_SSL: 0.0.0.0:8443# kong adminKONG_ADMIN_LISTEN: 0.0.0.0:8001, 0.0.0.0:8444 ssl# kong managerKONG_ADMIN_GUI_LISTEN: 0.0.0.0:8002, 0.0.0.0:8445 ssl# kong logsKONG_PROXY_ACCESS_LOG: /dev/stdoutKONG_PROXY_ERROR_LOG: /dev/stderrKONG_ADMIN_ACCESS_LOG: /dev/stdoutKONG_ADMIN_ERROR_LOG: /dev/stderrports:- "8000:8000" # Proxy- "8443:8443" # Proxy SSL- "8001:8001" # Admin API- "8444:8444" # Admin API SSL- "8002:8002" # Kong Manager- "8445:8445" # Kong Manager SSLvolumes:- .kong.yml:/usr/local/kong/declarative/kong.ymlnetworks:- app-nethealthcheck:test: ["CMD-SHELL", "kong health"]interval: 15stimeout: 10sretries: 3networks:app-net:external: truename: app_network

启动kong网关

docker compose up -d

查看服务运行状态

root@ubuntu:/data/apps/kong# docker compose ps
NAME           IMAGE        COMMAND                  SERVICE   CREATED          STATUS                    PORTS
kong-gateway   kong:3.9.1   "/docker-entrypoint.…"   kong      31 seconds ago   Up 31 seconds (healthy)   0.0.0.0:8000-8002->8000-8002/tcp, [::]:8000-8002->8000-8002/tcp, 0.0.0.0:8443-8445->8443-8445/tcp, [::]:8443-8445->8443-8445/tcp
root@ubuntu:/data/apps/kong# 

访问kong manager查看创建的转发规则
Gateway Services
在这里插入图片描述

Routes
在这里插入图片描述

Plugins
在这里插入图片描述

部署前后端服务

示例 Canaryheader 是一个基于Kong网关和docker-compose的Web端灰度发布演示项目,支持基于百分比的流量灰度策略。

架构如下:
在这里插入图片描述

主要特性

  • 前端:html/js,展示后端返回的版本信息
  • 后端:Node.js (Express),分别为v1和v2版本
  • Kong网关:流量分流、服务注册、路由配置,支持基于header灰度
  • 容器化:所有服务均为Docker容器
  • 一键部署:docker-compose编排

目录结构

canaryheader/
├── docker-compose.yml
├── backend-v1/
│   ├── Dockerfile
│   └── index.js           # v1后端代码
├── backend-v2/
│   ├── Dockerfile
│   └── index.js           # v2后端代码
├── frontend/
│   ├── Dockerfile
│   └── index.html

backend-v1/index.js

root@ubuntu:/data/git/canary-header-app# cat backend-v1/index.js 
const express = require('express');
const app = express();
app.get('/admin', (req, res) => {res.json({ version: 'v1', message: 'Hello from backend v1!' });
});
app.listen(3000, () => console.log('Backend v1 running on 3000'));

backend-v1/Dockerfile

root@ubuntu:/data/git/canary-header-app# cat backend-v1/Dockerfile 
FROM node:24-alpine
WORKDIR /app
COPY index.js ./
RUN npm config set registry https://registry.npmmirror.com && \npm init -y && \npm install express
EXPOSE 3000
CMD ["node", "index.js"] 

backend-v2/index.js

root@ubuntu:/data/git/canary-header-app# cat backend-v2/index.js 
const express = require('express');
const app = express();
app.get('/admin', (req, res) => {res.json({ version: 'v2', message: 'Hello from backend v2!' });
});
app.listen(3000, () => console.log('Backend v2 running on 3000'));

backend-v2/Dockerfile

root@ubuntu:/data/git/canary-header-app# cat backend-v2/Dockerfile 
FROM node:24-alpine
WORKDIR /app
COPY index.js ./
RUN npm config set registry https://registry.npmmirror.com && \npm init -y && \npm install express
EXPOSE 3000
CMD ["node", "index.js"] 

frontend/index.html

root@ubuntu:/data/git/canary-header-app# cat frontend/index.html 
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8" /><title>Canary Flow</title><style>body {font-family: Arial, sans-serif;max-width: 600px;margin: 0 auto;padding: 20px;}.test-section {margin: 20px 0;padding: 15px;border: 1px solid #ddd;border-radius: 5px;}button {margin: 5px;padding: 10px 15px;background-color: #007bff;color: white;border: none;border-radius: 3px;cursor: pointer;}button:hover {background-color: #0056b3;}pre {background-color: #f8f9fa;padding: 10px;border-radius: 3px;white-space: pre-wrap;}.version-v1 { color: #28a745; font-weight: bold; }.version-v2 { color: #dc3545; font-weight: bold; }</style>
</head>
<body><h1>Canary Flow 灰度发布演示</h1><div class="test-section"><h3>灰度规则测试</h3><p>基于请求头 <code>X-App-Version</code> 的简单灰度规则:</p><ul><li><strong>X-App-Version: v2</strong> → 路由到 Backend v2</li><li><strong>无请求头或其他值</strong> → 路由到 Backend v1</li></ul></div><div class="test-section"><h3>测试按钮</h3><button onclick="fetchData()">默认请求 (v1)</button><button onclick="fetchDataWithVersion('v2')">使用 v2 版本</button><button onclick="fetchDataWithVersion('v1')">强制使用 v1</button></div><pre id="output">点击按钮开始测试...</pre><script>async function fetchData() {try {const res = await fetch("http://192.168.73.11:8000/admin");const data = await res.json();displayResult(data, "默认请求(无请求头)");} catch (error) {document.getElementById("output").innerText = "错误: " + error.message;}}async function fetchDataWithVersion(version) {try {const res = await fetch("http://192.168.73.11:8000/admin", {headers: {'X-App-Version': version}});const data = await res.json();displayResult(data, `X-App-Version: ${version}`);} catch (error) {document.getElementById("output").innerText = "错误: " + error.message;}}function displayResult(data, requestInfo = "") {const output = document.getElementById("output");const versionClass = data.version === 'v1' ? 'version-v1' : 'version-v2';const timestamp = new Date().toLocaleTimeString();output.innerHTML = `
请求信息: ${requestInfo}
时间: ${timestamp}
版本: <span class="${versionClass}">${data.version}</span>
消息: ${data.message}`;}</script>
</body>
</html>

说明:前端直接通过kong网关接口http://192.168.73.11:8000/admin调用后端服务。

frontend/Dockerfile

root@ubuntu:/data/git/canary-header-app# cat frontend/Dockerfile 
FROM nginx:alpine
RUN rm -rf /usr/share/nginx/html/*
COPY index.html /usr/share/nginx/html/

docker-compose.yaml

root@ubuntu:/data/git/canary-header-app# cat docker-compose.yml 
name: 'canary-flow-app'services:frontend:build: ./frontendimage: registry.cn-shenzhen.aliyuncs.com/cnmirror/canary-header-frontend:v1.0container_name: canary-frontendports:- "8080:80"networks:- app-netbackend-v1:build: ./backend-v1image: registry.cn-shenzhen.aliyuncs.com/cnmirror/canary-header-backend-v1:v1.0container_name: canary-backend-v1ports:- "3001:3000"networks:- app-netbackend-v2:build: ./backend-v2image: registry.cn-shenzhen.aliyuncs.com/cnmirror/canary-header-backend-v2:v1.0container_name: canary-backend-v2ports:- "3002:3000"networks:- app-netnetworks:app-net:external: truename: app_network

启动前后端服务

构建镜像

docker compose build

启动服务

docker compose up -d

查看服务运行状态

root@ubuntu:/data/git/canary-header-app# docker compose ps
NAME                IMAGE                                                                    COMMAND                  SERVICE      CREATED          STATUS          PORTS
canary-backend-v1   registry.cn-shenzhen.aliyuncs.com/cnmirror/canary-flow-backend-v1:v1.0   "docker-entrypoint.s…"   backend-v1   10 minutes ago   Up 10 minutes   0.0.0.0:3001->3000/tcp, [::]:3001->3000/tcp
canary-backend-v2   registry.cn-shenzhen.aliyuncs.com/cnmirror/canary-header-backend-v2:v1.0   "docker-entrypoint.s…"   backend-v2   10 minutes ago   Up 10 minutes   0.0.0.0:3002->3000/tcp, [::]:3002->3000/tcp
canary-frontend     registry.cn-shenzhen.aliyuncs.com/cnmirror/canary-header-frontend:v1.0     "/docker-entrypoint.…"   frontend     10 minutes ago   Up 10 minutes   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
root@ubuntu:/data/git/canary-flow-app# 

灰度流量分流

Kong通过routes--headers将流量按header分配到v1和v2后端,实现灰度发布。通过kong网关多次请求接口进行验证:

root@ubuntu:/data/apps/kong# curl -s -H "X-App-Version: v1" http://192.168.73.11:8000/admin | jq
{"version": "v1","message": "Hello from backend v1!"
}
root@ubuntu:/data/apps/kong# 
root@ubuntu:/data/apps/kong# curl -s -H "X-App-Version: v2" http://192.168.73.11:8000/admin | jq
{"version": "v2","message": "Hello from backend v2!"
}
root@ubuntu:/data/apps/kong# curl -s http://192.168.73.11:8000/admin | jq
{"version": "v1","message": "Hello from backend v1!"
}
root@ubuntu:/data/apps/kong# 

浏览器访问frontend验证:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88204.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88204.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言gin框架原理

在gin框架中&#xff0c;最关键的就是前缀树&#xff0c;是很重要的。gin框架本质上是在http包的基础之上&#xff0c;对其的一个二次封装。这里借鉴一下小徐先生的图&#xff0c;可能当前版本的gin可能内容有所改变&#xff0c;但大致思想还是这样。gin框架所做的就是提供一个…

4、Sending Messages

本节介绍如何发送消息。Using KafkaTemplate本节介绍如何使用KafkaTemplate发送消息。OverviewKafkaTemplate封装了一个生产者&#xff0c;并提供了向Kafka主题发送数据的便利方法。以下列表显示了KafkaTemplate的相关方法&#xff1a;CompletableFuture<SendResult<K, V…

CSS长度单位问题

在 CSS 中&#xff0c;100px 的逻辑长度在不同分辨率的手机屏幕上是否表现一致&#xff0c;取决于 设备的像素密度&#xff08;devicePixelRatio&#xff09; 和 视口&#xff08;viewport&#xff09;的缩放设置。以下是详细分析&#xff1a;1. 核心概念 CSS 像素&#xff08;…

基于Java+SpringBoot的图书管理系统

源码编号&#xff1a;S606源码名称&#xff1a;基于SpringBoot的图书管理系统用户类型&#xff1a;双角色&#xff0c;用户、管理员数据库表数量&#xff1a;12 张表主要技术&#xff1a;Java、Vue、ElementUl 、SpringBoot、Maven运行环境&#xff1a;Windows/Mac、JDK1.8及以…

XTOM工业级蓝光三维扫描仪用于笔记本电脑背板模具全尺寸检测

镁合金具有密度小、强度高、耐腐蚀性好等优点&#xff0c;成为笔记本电脑外壳主流材料。冲压模具作为批量生产笔记本电脑镁合金背板的核心工具&#xff0c;其精度直接决定了产品的尺寸一致性、结构可靠性与外观品质。微米级模具误差可能在冲压过程中被放大至毫米级&#xff08;…

运维打铁: MongoDB 数据库集群搭建与管理

文章目录思维导图一、集群基础概念1. 分片集群2. 副本集二、集群搭建1. 环境准备2. 配置副本集步骤 1&#xff1a;修改配置文件步骤 2&#xff1a;启动 MongoDB 服务步骤 3&#xff1a;初始化副本集3. 配置分片集群步骤 1&#xff1a;配置配置服务器副本集步骤 2&#xff1a;启…

HCIP-Datacom Core Technology V1.0_5 OSPF特殊区域及其他特性

在前面的章节中&#xff0c;OSPF可以划分区域&#xff0c;减轻单区域里面LSDB的规模&#xff0c;从而减轻路由器的负荷&#xff0c;虽然OSPF能够划分区域&#xff0c;但是依旧需要维护域间路由和外部路由&#xff0c;这样随着网络规模的不断扩大&#xff0c;路由器所维护的LSDB…

实时开发IDE部署指南

&#x1f525;&#x1f525; AllData大数据产品是可定义数据中台&#xff0c;以数据平台为底座&#xff0c;以数据中台为桥梁&#xff0c;以机器学习平台为中层框架&#xff0c;以大模型应用为上游产品&#xff0c;提供全链路数字化解决方案。 ✨杭州奥零数据科技官网&#xff…

深入解析 RAGFlow:文件上传到知识库的完整流程

在 RAGFlow 这样的检索增强生成&#xff08;RAG&#xff09;系统中&#xff0c;知识库是其核心。用户上传的文档如何高效、可靠地转化为可检索的知识&#xff0c;是系统稳定运行的关键。今天&#xff0c;我们就来深入探讨 RAGFlow 中文件上传到知识库的完整流程&#xff0c;揭秘…

cad_recognition 笔记

Hubch/cad_recognition | DeepWiki https://github.com/Hubch/cad_recognition winget install python.python.3.10 python -m venv venv micromamba activate ./venv pip install paddleocr2.9.0 pip install poetry pip install moviepy1.0.3 下次要用conda建环境 或者…

基于odoo17的设计模式详解---构建模式

大家好&#xff0c;我是你的Odoo技术伙伴。在Odoo开发中&#xff0c;创建一个简单的记录可能只需要一行 self.env[res.partner].create({name: New Partner})。但如果我们要创建一个复杂的对象&#xff0c;比如一个包含了特定上下文、具有多个可选配置、并且需要执行一系列关联…

暑假算法日记第四天

目标​&#xff1a;刷完灵神专题训练算法题单 阶段目标&#x1f4cc;&#xff1a;【算法题单】滑动窗口与双指针 LeetCode题目:2953. 统计完全子字符串1016. 子串能表示从 1 到 N 数字的二进制串其他: 今日总结 往期打卡 2953. 统计完全子字符串 跳转: 2953. 统计完全子字符串…

Linux 常用命令大全(2025简明版)

&#x1f9ed; 一、文件和目录操作命令说明ls列出目录内容ls -l以列表形式显示&#xff08;含权限&#xff09;cd /path切换目录pwd显示当前路径mkdir dir创建目录mkdir -p dir/subdir递归创建目录rm file删除文件rm -r dir删除目录&#xff08;递归&#xff09;rm -rf dir强制…

React Ref 指南:原理、实现与实践

前言 React Ref&#xff08;引用&#xff09;是React中一个强大而重要的概念&#xff0c;它为我们提供了直接访问DOM元素或组件实例的能力。虽然React推崇声明式编程和数据驱动的理念&#xff0c;但在某些场景下&#xff0c;我们仍需要直接操作DOM或访问组件实例。本文将深入探…

4.权重衰减(weight decay)

4.1 手动实现权重衰减 import torch from torch import nn from torch.utils.data import TensorDataset,DataLoader import matplotlib.pyplot as plt def synthetic_data(w,b,num_inputs):Xtorch.normal(0,1,size(num_inputs,w.shape[0]))yXwbytorch.normal(0,0.1,sizey.shap…

OpenCV开发-初始概念

第一章 OpenCV核心架构解析1.1 计算机视觉的基石OpenCV&#xff08;Open Source Computer Vision Library&#xff09;作为跨平台计算机视觉库&#xff0c;自1999年由Intel发起&#xff0c;已成为图像处理领域的标准工具。其核心价值体现在&#xff1a;跨平台性&#xff1a;支持…

LeetCode 930.和相同的二元子数组

给你一个二元数组 nums &#xff0c;和一个整数 goal &#xff0c;请你统计并返回有多少个和为 goal 的 非空 子数组。 子数组 是数组的一段连续部分。 示例 1&#xff1a; 输入&#xff1a;nums [1,0,1,0,1], goal 2 输出&#xff1a;4 解释&#xff1a; 有 4 个满足题目要求…

【论文解读】Referring Camouflaged Object Detection

论文信息 论文题目&#xff1a;Referring Camouflaged Object Detection 论文链接&#xff1a;https://arxiv.org/pdf/2306.07532 代码链接&#xff1a;https://github.com/zhangxuying1004/RefCOD 录用期刊&#xff1a;TPAMI 2025 论文单位&#xff1a;南开大学 ps&#xff1a…

Spring中过滤器和拦截器的区别及具体实现

在 Spring 框架中&#xff0c;过滤器&#xff08;Filter&#xff09; 和 拦截器&#xff08;Interceptor&#xff09; 都是用于处理 HTTP 请求的中间件&#xff0c;但它们在作用范围、实现方式和生命周期上有显著区别。以下是详细对比和实现方式&#xff1a;核心区别特性过滤器…

CANFD 数据记录仪在新能源汽车售后维修中的应用

一、前言随着新能源汽车市场如火如荼和新能源汽车电子系统的日益复杂&#xff0c;传统维修手段在面对复杂和偶发故障时往往捉襟见肘&#xff0c;CANFD 数据记录仪则凭借其独特优势&#xff0c;为售后维修带来新的解决方案。二、 详细介绍在新能源汽车领域&#xff0c;CANFD 数据…