KubeEdge Viaduct 示例实战:基于 QUIC 与 WebSocket 的云边加密通信与双向消息演示
2026/9/17 11:59:31 网站建设 项目流程

KubeEdge Viaduct 示例实战:基于 QUIC 与 WebSocket 的云边加密通信与双向消息演示

【免费下载链接】kubeedgeKubernetes Native Edge Computing Framework (project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/ku/kubeedge

Viaduct(高架桥)是 KubeEdge 中连接云端(CloudHub)与边缘端(EdgeHub)的通信桥,支持以 QUIC 和 WebSocket 两种底层传输协议承载 beehive 消息。本文以仓库中的 chat 示例 为线索,完整讲解其证书生成、双端启动、命令行参数,并结合 Viaduct 源码 剖析连接建立、消息路由、协议打包等底层原理。读完本文,你将能够独立编译运行 Viaduct 通信示例,理解消息多路分发(mux)与 QUIC 多流模型,并能对照生产环境中的 CloudHub/EdgeHub 实现进一步验证。

一、Viaduct 是什么:云与边之间的"高架桥"

Viaduct 的名字取自"跨谷之桥":山谷是云(Cloud)与边(Edge)之间的网络鸿沟,桥梁就是跨越鸿沟的连接。它利用 protobuf3.0 序列化 beehive 中定义的消息模型,并提供连接(Connection)与消息读写(Message)两类 API,当前支持两种底层传输协议:

  • WebSocket:基于 gorilla/websocket,走标准的wss://加密通道;
  • QUIC:基于 quic-go,基于 UDP 的多路复用可靠传输。

该定位在 pkg/viaduct/README.md 中有明确说明。在生产环境中,CloudHub 服务端 与 EdgeHub 客户端 正是通过这一层完成云边通道的建立与消息收发。

二、示例概览:chat 与 mirror

examples/chat 目录是理解 Viaduct 的最佳入口,包含:

文件作用
config/config.go通过 Go 标准库flag解析全部命令行参数
main.go程序入口,根据--cmd-type分发到 server 或 client
server.go服务端:监听连接、注册消息路由、支持 stdin 交互发送
client.go客户端:建立连接、注册消息路由、支持 stdin 交互发送
common.go证书文件加载与双向 TLS 配置构造(GetTlsConfig

此外,同级的 mirror 示例 演示的是原始数据流(stream)模式:客户端把 stdin 数据原样推给服务端,服务端通过io.Copy回显到 stdout,可视为"管道回显器",与 chat 的消息模式形成对照。mirror 复用了 chat 的 config 包 来解析参数。

三、第一步:生成 CA 与证书对

chat 示例的 TLS 场景需要一张 CA 证书和一套证书/私钥对,同一套证书/私钥对可同时用于服务端和客户端。以下是 原文档 提供的完整 openssl 命令,按顺序执行即可:

# 1. 生成 CA 根私钥(4096 位,带 DES3 加密口令) openssl genrsa -des3 -out ca.key 4096 # 2. 生成 CA 根证书(SHA-256 签名,1024 天有效期) openssl req -x509 -new -nodes -key ca.key -sha256 -days 1024 -out ca.crt # 3. 生成通信实体私钥(2048 位) openssl genrsa -out chat.key 2048 # 4. 生成证书签名请求 csr,执行后会交互式询问国家/组织/通用名等,按要求填写即可 openssl req -new -key chat.key -out chat.csr # 5. 使用 CA 对 csr 签发证书(500 天有效期,SHA-256 签名) openssl x509 -req -in chat.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out char.crt -days 500 -sha256

命令要点说明:

  • genrsa -des3会为 CA 私钥设置口令,后续使用ca.key时(第 2、5 步)会提示输入;
  • -CAcreateserial会生成ca.srl序列号文件,用于保证每次签发证书的序列号唯一;
  • -days 1024-days 500分别为 CA 与实体证书的有效期,可按需调整。

注意:原文档第 5 步输出的文件名写作char.crt(拼写如此),而后续启动命令引用的是./chat.crt。仓库目录中实际存在的文件是 char.crt。若严格照抄命令执行,第 5 步会生成char.crt;请按你实际生成的文件名在启动命令中保持一致(即把--cert=./chat.crt改为--cert=./char.crt,或把第 5 步输出名改为chat.crt)。

证书在源码中如何被使用

common.go 中的 GetTlsConfig 展示了这三类文件的标准加载方式:读取ca文件加入x509.CertPool作为客户端 CA 池,读取cert/key通过tls.X509KeyPair组装成服务端证书,最终构造出启用tls.RequireAndVerifyClientCert(强制校验客户端证书)的tls.Config——这正是云边双向认证的典型形态。

需要说明的是:从当前源码看,chat 的 server.go 与 client.go 中GetTlsConfig的调用被注释掉,实际运行时分别使用测试用自签名证书(generateTLSConfig)和InsecureSkipVerify: true。因此--key/--cert/--ca三个参数目前仍会被解析并接受,但尚未真正注入 TLS 握手流程,这属于示例代码为了便于快速联调而做的简化,生产环境(CloudHub/EdgeHub)则严格加载证书文件,具体见后文"生产环境对照"。

四、第二步:编译并启动 chat 示例

编译

cd pkg/viaduct/examples/chat go build

编译成功后当前目录会生成可执行文件chat。由于 Viaduct 属于仓库内的独立 package,可直接在仓库根目录使用 Go Modules 完成构建(仓库已提供 go.mod 与 go.work)。

命令行参数一览

config.go 定义了全部参数,整理如下:

参数默认值说明
--cmd-typeserver运行模式,serverclient
--typequic传输协议,quicwebsocket
--addr127.0.0.1:9890服务端监听地址 / 客户端连接地址
--key私钥文件路径(如./chat.key
--cert证书文件路径(如./chat.crt
--caCA 证书文件路径(如./ca.crt

main.go依据--cmd-type分发:server调用StartServer,其余值走StartClient

QUIC 模式

先启动服务端:

./chat --cmd-type=server --key=./chat.key --cert=./chat.crt --ca=./ca.crt --type=quic --addr=localhost:9890

再启动客户端:

./chat --cmd-type=client --key=./chat.key --cert=./chat.crt --ca=./ca.crt --type=quic --addr=localhost:9890

WebSocket 模式

服务端:

./chat --cmd-type=server --key=./chat.key --cert=./chat.crt --ca=./ca.crt --type=websocket --addr=localhost:9890

客户端:

./chat --cmd-type=client --key=./chat.key --cert=./chat.crt --ca=./ca.crt --type=websocket --addr=wss://localhost:9890/test

WebSocket 模式的关键差异在于客户端地址必须是完整的wss://URL,且路径/test必须与服务端 WSServerOption.Path 中配置的路径一致(示例代码固定为/test),否则握手会失败。

交互方式

两端启动后,任一端在send message:提示符下输入一行文本并回车,消息会通过 Viaduct 通道发送到对端,对端打印receive message: <内容>。服务端构建消息时使用 model.NewMessage 设置路由("server", "", "viaduct_message", "update"),客户端使用("client", "", "viaduct_message", "update");若消息被标记为同步(IsSync()为真),收到方还会回写应答(服务端回success,客户端回ack)。

五、源码深读:chat 示例背后的 Viaduct 原理

1. 服务端:Server 组装与连接管理

server.go 的 StartServer 展示了服务端对象的组装方式:

server := server.Server{ Type: cfg.Type, // "quic" 或 "websocket" Addr: cfg.Addr, TLSConfig: tls, AutoRoute: true, // 收到消息后自动路由到已注册的 mux 处理函数 ConnMgr: connMgr, // 连接管理器,可遍历/查找所有活跃连接 ConnNotify: ConnNotify, // 新连接建立时的回调 ExOpts: exOpts, // 协议扩展参数 }

ExOpts按协议类型区分:QUIC 使用api.QuicServerOption{}(可配置MaxIncomingStreams),WebSocket 使用api.WSServerOption{Path: "/test"},见 api/server.go。

服务端在 goroutine 中调用ListenAndServeTLS("", "")启动监听(证书已通过TLSConfig注入,无需再传文件路径)。启动后进入 stdin 循环:每次输入都遍历connMgr中所有连接,通过conn.WriteMessageAsync(message)异步广播给每个已连接的客户端。connMgr底层是sync.Map,cmgr/connmgr.go 支持自定义连接 key 函数,默认以RemoteAddr()作为 key。

2. 客户端:Connect 与消息模式

client.go 的 StartClient 展示了客户端组装方式:

client := client.Client{ Options: client.Options{ Type: cfg.Type, Addr: cfg.Addr, TLSConfig: tls, AutoRoute: true, ConnUse: api.UseTypeMessage, // 连接仅用于消息模式 }, ExOpts: exOpts, }

其中ExOpts在 QUIC 下为api.QuicClientOption{Header: header},在 WebSocket 下为api.WSClientOption{Header: header},header 中携带client_id: client1这类自定义请求头,可用于服务端识别客户端身份(生产环境中 CloudHub 正是用node_idproject_id头标识节点)。调用client.Connect()后打印连接状态(ConnectionState),随后进入 stdin 循环发送消息。

client/client.go 的 Connect 内部按Type选择协议客户端(NewQuicClientNewWSClient),连接建立后以 goroutine 启动protoConn.ServeConn()持续接收对端消息,随后返回连接对象。

3. 消息路由:mux 模式匹配

chat 两端都通过 mux.Entry 注册了通配处理器:

mux.Entry(mux.NewPattern("*").Op("*"), handleServer) // 服务端 mux.Entry(mux.NewPattern("*").Op("*"), handleClient) // 客户端

这表示"匹配任意 resource、任意 operation"。收到消息时,MessageMux.dispatch 会遍历注册条目:先用 MessagePattern.Match 校验 resource 与 operation,再调用对应处理函数,处理函数通过ResponseWriter回写应答。除了通配符*,路由还支持{name}{name:regexp}形式的参数化路径——expr.go 会将其编译为正则表达式,并把捕获组注入MessageContainer.Parameter(name),这一点与 HTTP 路由框架的设计思路一致。若没有任何条目匹配,dispatch会返回错误。

路由分发之前还会经过可选的消息过滤器(filter/filter.go),过滤函数返回错误时消息被丢弃,用于实现消息级准入控制。

4. 消息序列化:protobuf 与翻译器

Viaduct 使用 protobuf3 定义线上消息格式,见 protos/message/message.proto:MessageMessageHeader(ID、ParentID、时间戳、同步标志、类型)与MessageRouter(Source、Group、Operation、Resouce)以及Content三部分组成。运行时由 translator/message.go 负责 beehive 的model.Message与 protobufmessage.Message之间的双向转换:Content支持[]bytestring,其他类型自动json.Marshal后写入。

5. 数据打包:packer 帧格式

QUIC 通道上的消息经过 packer 帧封装,包头共 10 字节:

字段长度说明
Version4 字节主/次/修复版本号,当前为 1.1.1(version.go)
PackageType1 字节0x01消息包、0x02流包、0x04用户自定义包
Flags1 字节标志位,0x80表示压缩
PayloadLen4 字节负载长度,上限 32 MiB(MaxPayloadLen

packer.go 的 Pack/Unpack 实现了大端序编解码。lane/quic.go 在每条 QUIC stream 上执行"packer 读写 + translator 编解码"的完整链路;而 lane/wsnopack.go 中 WebSocket 模式直接以 JSON 读写消息(ReadJSON/WriteJSON),无需额外打包。

6. QUIC 的并发模型:控制流、消息流与流管理器

QUIC 连接天然支持多路复用。conn/quic.go 的QuicConnection结构体现了三条通路:

  • 控制流(CtrlLane)serveControlLan循环读取控制消息并回ack,负责传递 header、config、ping/pong 等控制信息;
  • 会话服务(serveSession)AcceptStream循环接受对端新开的数据流,读取消息分发到 handler 或 FIFO;流关闭或会话异常时回调OnReadTransportErr(nodeID, projectID)通知上层;
  • 流管理器(StreamManager):smgr/smgr.go 维护消息流与二进制流两个池,NumStreamsMax = 99限制最大并发流数,支持池化复用与自动释放。

同步消息由 keeper/synckeeper.go 实现:发送同步消息前注册消息 ID 对应的 channel,响应消息到达时按ParentID找到 channel 并投递,从而实现WriteMessageSync的请求-应答语义。异步收到的消息则进入容量 100 的 fifo/msgfifo.go,溢出时丢弃最旧消息并告警。

7. Connection 接口:统一两种协议

conn/conn.go 定义了Connection统一接口,覆盖消息级与原始字节级操作:ReadMessage/WriteMessageAsync/WriteMessageSync用于消息模式;Read/Write用于原始数据流;SetReadDeadline/SetWriteDeadline控制超时;ConnectionState()返回连接状态与对端证书信息。具体实现由 factory.go 按协议类型分派到NewQuicConnNewWSConn

六、延伸:mirror 示例与原始数据流模式

若只想快速验证 QUIC/WebSocket 通道本身,可运行 mirror 示例:

cd pkg/viaduct/examples/mirror go build # quic:先服务端后客户端 ./mirror --cmd-type=server --type=quic --addr=localhost:9890 ./mirror --cmd-type=client --type=quic --addr=localhost:9890 # websocket ./mirror --cmd-type=server --type=websocket --addr=localhost:9890 ./mirror --cmd-type=client --type=websocket --addr=wss://localhost:9890/test

与 chat 不同,mirror 客户端使用api.UseTypeStream(client.go),把 stdin 通过io.Copy(conn, os.Stdin)原样写入连接;服务端在ConnNotify回调里通过io.Copy(loggerWriter{}, conn)把收到的原始字节流打印到 stdout。这演示了 Viaduct 的第二种连接用途:不解析消息、直接透传字节流,适合日志转发、端口代理等场景。协议类型常量定义在 api/type.go:连接用途分为UseTypeMessage(仅消息)、UseTypeStream(仅流)与UseTypeShare(消息+流共享),其中 WebSocket 模式暂不支持共享类型。

七、生产环境对照:CloudHub 与 EdgeHub 如何使用 Viaduct

chat 示例是 Viaduct API 的最小化演示,生产环境的用法完全一致,只是换上了真实的证书与鉴权头:

  • 云端 CloudHub:servers/server.go 分别按配置启动 WebSocket 服务(Path: "/")与 QUIC 服务(MaxIncomingStreams取自配置),两者都使用createTLSConfig构造强制双向证书校验(tls.RequireAndVerifyClientCert、TLS1.2 及以上、限定 ECDSA 密码套件)的tls.ConfigAutoRoute: true并将连接通知回调到messageHandler.HandleConnection
  • 边缘端 EdgeHub:quicclient.go 加载 CA 与证书/私钥构造tls.Config,通过api.QuicClientOption{Header}携带node_idproject_id请求头连接云端,Send使用WriteMessageAsyncReceive使用ReadMessage;WebSocket 客户端 则按wss://URL 连接,并同样在 Header 中注入节点标识。

可见,chat 示例中--key/--cert/--ca三个参数对应的正是生产环境下云边双向 TLS 认证所需的证书材料,示例的通信流程与 CloudHub/EdgeHub 的实际链路一一对应。

八、小结

通过 chat 与 mirror 两个示例,可以完整掌握 KubeEdge Viaduct 通信层的核心用法:

  1. 证书先行:openssl 生成 CA 与实体证书对,支撑双向 TLS 认证;
  2. 双协议可选:同一套 API 同时支持 QUIC 与 WebSocket,仅需切换--type与地址格式;
  3. 统一 Connection 接口:消息模式(WriteMessageAsync/ReadMessage)与流模式(Read/Write)覆盖云边通信的两种典型负载;
  4. mux 路由 + protobuf 序列化 + packer 封帧:构成 Viaduct 的传输协议栈,为 CloudHub/EdgeHub 生产链路提供了坚实底座。

后续可继续阅读 viaduct 包目录 下的serverclientconnlanepacker各子包源码,并结合 cloudhub 服务端 与 edgehub 客户端 验证示例与生产实现之间的一一对应关系。

【免费下载链接】kubeedgeKubernetes Native Edge Computing Framework (project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/ku/kubeedge

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询