Cilium Hubble Relay 本地端口转发:从 kubectl 手动操作到 Hubble CLI-P自动转发的完整实践
【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium
在 Cilium 集群中,Hubble Relay 服务将各节点 Cilium agent 的流量观测数据汇聚为集群级 API,但该服务通常只暴露给集群内部。Documentation/observability/hubble/port-forward.rst这份文档正是为了解决“本地如何访问 Hubble Relay”这一具体问题:它介绍了 Hubble CLI 的-P(--port-forward)标志自动转发机制,以及cilium hubble port-forward与kubectl port-forward两种手动建立本地通道(端口 4245)的方式。读完本文,你将掌握三种端口转发方案的命令细节与适用场景,并理解从 Cilium CLI 到 Hubble CLI 的完整源码调用链,能够独立排查本地访问 Relay 失败的问题。
为什么需要端口转发
从 Hubble 的整体架构看(见 Documentation/observability/hubble/index.rst):默认情况下 Hubble API 只运行在单个节点上,Hubble CLI 通过本地 Unix Domain Socket 查询本机 agent;部署 Hubble Relay 后,网络可视范围扩展到整个集群乃至 ClusterMesh 场景,此时 Hubble CLI(hubble)需要连接 Hubble Relay 服务才能获取集群级数据。
Hubble Relay 在 Kubernetes 中是一个 Service,其端点地址(如hubble-relay.kube-system.svc)通常只能从集群网络内部解析和访问。要让运行在本地的hubble命令连上它,最通用的手段就是把 Relay 服务的 80 端口(其首个配置端口)映射到本机的 4245 端口——这也是 Hubble 生态约定的 Relay 本地端口,在源码hubble/pkg/defaults/defaults.go中可以看到默认服务地址即localhost:4245:
// hubble/pkg/defaults/defaults.go ServerAddress = "localhost:4245"方式一:手动端口转发(Cilium CLI)
按照原文档,你可以直接使用 Cilium CLI 建立转发通道:
$ cilium hubble port-forward ℹ️ Hubble Relay is available at 127.0.0.1:4245该命令的行为在 cilium-cli/cli/hubble.go 中定义(newCmdPortForwardCommand,第 32–56 行):
- 命令注册在
cilium hubble子命令组下,短描述为 “Forward the relay port to the local machine”; - 提供一个
--port-forward整型标志,默认值 4245,帮助文案明确说明 “0 will select a random port”(传 0 则由系统随机分配本地端口); - 通过
signal.NotifyContext监听SIGINT/SIGKILL,因此按Ctrl+C即可干净地退出转发; - 实际执行委托给 cilium-cli/hubble/relay.go 中的
RelayPortForwardCommand。
RelayPortForwardCommand的核心实现只有几行,但把整条链路的语义都交代清楚了:
// cilium-cli/hubble/relay.go func (p *Parameters) RelayPortForwardCommand(ctx context.Context, k8sClient *k8s.Client) error { // default to first port configured on the service when svcPort is set to 0 res, err := k8sClient.PortForwardService(ctx, p.Namespace, "hubble-relay", int32(p.PortForward), 0) if err != nil { return fmt.Errorf("failed to port forward: %w", err) } p.Log("ℹ️ Hubble Relay is available at 127.0.0.1:%d", res.ForwardedPort.Local) <-ctx.Done() return nil }其中几个值得注意的实现细节(见 cilium-cli/k8s/dialer.go 第 18–24 行):
- 固定转发目标为指定命名空间下的
hubble-relayService(命名空间取自全局-n/--namespace参数,默认为kube-system); localPort传 0 时选择随机本地端口;svcPort传 0 时使用 Service 上配置的第一个端口——这正是文档中4245:80之所以不用写死的原因,只要 Relay Service 首个端口是 80 即可;- 转发在后台 goroutine 中执行,取消 context 即可停止转发;
- 成功后打印
127.0.0.1:<本地端口>,端口以实际转发结果为准(随机端口场景下可能不是 4245)。
方式二:手动端口转发(kubectl)
不依赖 Cilium CLI 时,原文档给出等价的原生 kubectl 命令:
$ kubectl -n kube-system port-forward service/hubble-relay 4245:80 Forwarding from 127.0.0.1:4245 -> 4245 Forwarding from [::1]:4245 -> 4245要点:
-n kube-system指定 Hubble 所在命名空间,与 Cilium CLI 的全局-n参数语义一致(-P模式下 Hubble CLI 的--kube-namespace默认值同样是kube-system);4245:80表示把本地 4245 端口映射到hubble-relayService 的 80 端口,即hubble-relayService 的第一个配置端口;- 输出中同时列出 IPv4(
127.0.0.1:4245)和 IPv6([::1]:4245)两条转发规则,说明本地回环两种地址族均可访问。
方式三:Hubble CLI 的-P标志(自动转发)
三种方式中最省事的,是在 Hubble 命令上直接加-P(--port-forward)标志,由 Hubble CLI 自行建立到 Relay Pod 的转发通道,无需先起一个手动转发进程。例如:
# 列出集群流量(等价于先 cilium hubble port-forward 再 hubble observe) $ hubble observe -P # 查询 Relay/节点状态 $ hubble status -P $ hubble list nodes -P-P及一组配套标志在 hubble/cmd/common/config/flags.go 的initServerFlags中统一注册,完整参数如下:
| 标志 | 类型/默认值 | 作用 |
|---|---|---|
-P, --port-forward | bool,默认false | 自动把 relay 端口转发到本机。源码注释:“Analoguous to running: 'cilium hubble port-forward'.” |
--port-forward-port | uint16,默认4245 | 本地转发端口;设为0时随机选择端口。仅在--port-forward开启时生效 |
--kube-context | string,默认空 | Kubernetes 配置上下文。仅在--port-forward开启时生效 |
--kube-namespace | string,默认kube-system | Cilium/Hubble 所在命名空间。仅在--port-forward开启时生效 |
--kubeconfig | string,默认空 | kubeconfig 文件路径。仅在--kube-namespace同级条件生效,即仅--port-forward时考虑 |
--server | string,默认localhost:4245 | Hubble 服务器地址;当提供--port-forward或--input-file时被忽略 |
这些描述与hubble observe的帮助输出(hubble/cmd/observe_help.txt 第 156–162 行)完全一致,可直接作为参数速查表。
源码链路:-P是如何工作的
Hubble CLI 的连接创建逻辑集中在 hubble/cmd/common/conn/conn.go 的NewWithFlags(第 127–157 行):
func NewWithFlags(ctx context.Context, vp *viper.Viper) (*grpc.ClientConn, error) { server := vp.GetString(config.KeyServer) if vp.GetBool(config.KeyPortForward) { kubeContext := vp.GetString(config.KeyKubeContext) kubeconfig := vp.GetString(config.KeyKubeconfig) kubeNamespace := vp.GetString(config.KeyKubeNamespace) localPort := vp.GetUint16(config.KeyPortForwardPort) pf, err := newPortForwarder(kubeContext, kubeconfig) // ... // default to first port configured on the service when svcPort is set to 0 res, err := pf.PortForwardService(ctx, kubeNamespace, "hubble-relay", int32(localPort), 0) // ... server = fmt.Sprintf("127.0.0.1:%d", res.ForwardedPort.Local) } conn, err := New(server) // ... }从源码结构看,-P的工作流程是:
- 用
--kube-context/--kubeconfig构造 Kubernetes clientset(NewK8sClient,第 159–179 行); - 以
--kube-namespace(默认kube-system)中的hubble-relayService 为目标执行端口转发,svcPort传 0 即取 Service 首个端口,与 Cilium CLI 的实现策略完全相同; - 把 gRPC 目标地址改写为
127.0.0.1:<实际本地端口>,再调用New建立普通 gRPC 连接。
这也解释了为什么--server在-P模式下被“忽略”:服务器地址在转发建立后由本地转发结果动态决定,而非用户输入。
三种方式对比与选择建议
| 方式 | 命令 | 特点 |
|---|---|---|
| Cilium CLI 手动转发 | cilium hubble port-forward | 端口由--port-forward控制(默认 4245,0 为随机);独立前台进程,转发一次、多命令复用;Ctrl+C停止 |
| kubectl 手动转发 | kubectl -n kube-system port-forward service/hubble-relay 4245:80 | 不依赖 Cilium CLI,只要求 kubectl 可达集群;显式指定 4245:80 映射 |
Hubble CLI-P | hubble <cmd> -P | 一条命令完成“转发 + 查询”,转发随命令生命周期存在;支持--kube-namespace/--kube-context/--kubeconfig定位集群 |
实践上的取舍:
- 临时查一次状态(
hubble status、hubble list flows):直接用-P最简洁; - 持续观察多条流(
hubble observe长时间运行):可以先cilium hubble port-forward保持一个长连接,再运行不带-P的hubble observe连接localhost:4245,避免每次查询都重建转发; - 本机没有 Cilium CLI、只有 kubectl:用方式二,注意端口映射写成
4245:80,即本地 4245 到 Service 80 端口。
排错要点
结合上述源码实现,本地访问 Relay 失败时可按以下顺序排查:
- 命名空间不对:
-P模式默认在kube-system中查找hubble-relay,若 Hubble 安装在其他命名空间,需显式传--kube-namespace <ns>(kubectl 方式则对应-n <ns>); - 本地端口冲突:4245 被占用时,
cilium hubble port-forward --port-forward 0或hubble observe -P --port-forward-port 0会随机选一个端口,注意以命令输出/转发结果中的实际端口为准(源码中日志打印的是res.ForwardedPort.Local,即真实本地端口); - 集群不可达:
-P依赖 kubeconfig 上下文,多集群环境需确认--kube-context/--kubeconfig指向的目标集群中确实部署了 Hubble Relay(可通过hubble status -P验证 Relay 与各 agent 的连通状态); - 确认 Service 首端口为 80:Cilium CLI 与 Hubble CLI 均按“Service 首个配置端口”转发,若 Relay Service 的端口定义被定制过,kubectl 方式的
4245:80需相应调整目标端口。
小结
port-forward.rst文档给出的三种访问方式——hubble -P自动转发、cilium hubble port-forward手动转发、kubectl port-forward原生转发——共享同一套底层实现:在kube-system(或指定命名空间)中对hubble-relayService 建立本地端口映射,并以 Service 首个端口(80)作为目标,本地默认落在 4245。理解了 cilium-cli/k8s/dialer.go、hubble/cmd/common/conn/conn.go 中的PortForwardService调用链和 hubble/cmd/common/config/flags.go 中的参数定义后,你可以按场景自由选择方式,并在端口冲突、命名空间差异等情况下快速定位问题。Hubble Relay 打通本地访问通道后,即可结合 hubble-cli.rst 中的observe/list/status等命令,以及 setup.rst 中 Relay 的部署与 TLS 配置,完成集群级流量观测的完整闭环。
【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考