Kmesh-daemon 深度解析:服务网格数据面的核心引擎
Kmesh-daemon 深度解析:服务网格数据面的核心引擎
1. 使用背景
Kmesh-daemon 是 Kmesh 服务网格的核心守护进程,作为连接控制面和数据面的桥梁,负责管理整个 Kmesh 系统的运行时状态。在现代云原生环境中,服务网格已成为微服务架构的关键基础设施,而 Kmesh 作为基于 eBPF 技术的高性能服务网格实现,其核心组件 Kmesh-daemon 扮演着至关重要的角色。
1.1 与其他组件的关系
Kmesh 整体架构由三大核心组件组成:
- Kmesh-daemon:核心守护进程,负责 eBPF 编排生命周期管理、xDS 协议集成、可观察性等功能
- eBPF Orchestration:数据面流量编排,基于 eBPF 实现的高性能流量管理
- Waypoint:基于 Istio 的 waypoint 适配 Kmesh 协议,负责 L7 流量管理
Kmesh-daemon 与其他组件的关系如下:
- 向上:与控制面(如 Istio Pilot)通过 xDS 协议通信,接收服务发现和配置信息
- 向下:管理 eBPF 程序的加载、更新和卸载,控制数据面行为
- 横向:与 Waypoint 组件配合,提供完整的 L4/L7 流量管理能力
1.2 技术背景
传统的服务网格实现(如 Istio)通常依赖于 Sidecar 代理模式,这种方式在带来功能丰富性的同时,也引入了显著的性能开销。Kmesh 采用 eBPF 技术栈,将流量管理逻辑下沉到 Linux 内核,大幅提升性能并降低资源消耗。
Kmesh-daemon 作为这一架构的中枢神经系统,负责协调各个部分的工作,确保整个系统高效、稳定运行。它不仅要处理复杂的配置管理,还要应对动态的服务发现,同时保证 eBPF 程序的正确加载和执行。
2. 架构设计
Kmesh-daemon 采用模块化、分层的架构设计,确保系统的可扩展性和可维护性。下面详细分析其架构设计:
2.1 核心架构层次
┌─────────────────────────────────────────────────────────┐
│ 命令行接口 │
│ (daemon/main.go, daemon/manager/manager.go) │
├─────────────────────────────────────────────────────────┤
│ 配置管理层 │
│ (daemon/options/options.go) │
├─────────────────────────────────────────────────────────┤
│ 核心控制器 │
│ (pkg/controller/controller.go) │
├─────────────────────────────────────────────────────────┤
│ BPF加载层 │
│ (pkg/bpf/bpf.go) │
├─────────────────────────────────────────────────────────┤
│ 数据面实现 │
│ (pkg/bpf/ads/, pkg/bpf/workload/) │
└─────────────────────────────────────────────────────────┘
2.2 主要模块设计
2.2.1 命令行接口层
命令行接口层是 Kmesh-daemon 的入口点,负责解析命令行参数、初始化配置并启动核心服务。主要组件包括:
- main.go:程序入口,创建并执行命令
- manager.go:命令管理,处理启动、停止等操作
- 子命令:包括卸载、版本等辅助功能
2.2.2 配置管理层
配置管理层负责管理 Kmesh-daemon 的各种配置选项,包括:
- BootstrapConfigs:统一的配置结构,包含多个子配置
- BpfConfig:eBPF 相关配置
- CniConfig:CNI 插件配置
- ByPassConfig:旁路配置
- SecretManagerConfig:密钥管理配置
2.2.3 核心控制器层
核心控制器是 Kmesh-daemon 的大脑,负责协调各个子系统的工作。主要功能包括:
- XDS 客户端:与控制面通信,接收配置更新
- 工作负载控制器:管理服务和工作负载信息
- IPsec 控制器:处理加密通信
- DNS 代理:提供服务发现功能
- 监控管理:收集和暴露指标
2.2.4 BPF加载层
BPF加载层负责 eBPF 程序的生命周期管理,包括:
- BpfLoader:加载和管理 eBPF 程序
- 版本管理:处理版本更新和回滚
- 模式管理:支持内核原生模式和双引擎模式
- 资源管理:内存锁定、BPF 映射管理
2.3 工作流程设计
Kmesh-daemon 的典型工作流程如下:
-
初始化阶段:
- 解析命令行参数和配置
- 移除内存锁定限制
- 初始化 BPF 加载器
-
启动阶段:
- 加载 eBPF 程序
- 初始化核心控制器
- 启动各种子控制器
- 建立与控制面的连接
-
运行阶段:
- 处理 xDS 配置更新
- 管理服务发现和负载均衡
- 监控系统状态
- 处理 DNS 查询
-
关闭阶段:
- 接收信号并开始清理
- 停止各种子控制器
- 卸载 eBPF 程序
- 释放资源
2.4 模式支持
Kmesh-daemon 支持两种运行模式:
-
内核原生模式 (Kernel Native Mode):
- 适用于较新的 Linux 内核
- 直接使用内核提供的 eBPF 功能
- 性能更高,但功能相对有限
-
双引擎模式 (Dual Engine Mode):
- 适用于更广泛的内核版本
- 结合了用户空间和内核空间的处理
- 功能更丰富,兼容性更好
3. 使用方式
Kmesh-daemon 提供了灵活的使用方式,适应不同的部署场景和需求。
3.1 基本使用
3.1.1 启动命令
# 基本启动
kmesh-daemon
# 指定配置启动
kmesh-daemon --mode dual-engine --enable-monitoring
# 查看帮助信息
kmesh-daemon --help
3.1.2 主要配置选项
| 配置项 | 说明 | 默认值 |
|---|---|---|
--mode |
运行模式 (kernel-native/dual-engine) | dual-engine |
--enable-monitoring |
启用监控 | false |
--enable-ipsec |
启用 IPsec 加密 | false |
--enable-dns-proxy |
启用 DNS 代理 | false |
--enable-mda |
启用 MDA 功能 | false |
--bpf-fs-path |
BPF 文件系统路径 | /sys/fs/bpf |
3.1.3 子命令
Kmesh-daemon 提供了两个主要子命令:
# 卸载 Kmesh
kmesh-daemon uninstall
# 查看版本信息
kmesh-daemon version
3.2 部署方式
3.2.1 Kubernetes 部署
Kmesh-daemon 通常作为 DaemonSet 部署在 Kubernetes 集群中:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kmesh
namespace: kmesh-system
spec:
selector:
matchLabels:
app: kmesh
template:
metadata:
labels:
app: kmesh
spec:
hostNetwork: true
containers:
- name: kmesh-daemon
image: kmesh/kmesh-daemon:latest
securityContext:
privileged: true
args:
- --mode
- dual-engine
- --enable-monitoring
3.2.2 配置管理
Kmesh-daemon 的配置可以通过多种方式管理:
- 命令行参数:直接在启动命令中指定
- 环境变量:设置对应的环境变量
- 配置文件:通过配置文件指定详细配置
3.3 集成与扩展
3.3.1 与 Istio 集成
Kmesh-daemon 可以与 Istio 无缝集成,作为其数据面的替代方案:
- 部署 Istio 控制面
- 部署 Kmesh-daemon 作为数据面
- 配置 Istio 指向 Kmesh-daemon
3.3.2 自定义扩展
Kmesh-daemon 提供了扩展点,可以通过以下方式进行自定义:
- 插件机制:通过插件扩展功能
- 钩子函数:在关键流程中添加自定义逻辑
- 配置覆盖:通过配置文件覆盖默认行为
4. 源码原理
Kmesh-daemon 的源码实现非常复杂,涉及多个模块和层次。下面深入分析其核心源码原理:
4.1 命令行处理与启动流程
4.1.1 入口点实现
Kmesh-daemon 的入口点在 daemon/main.go:
func main() {
var log = logger.NewLoggerScope("main")
cmd := manager.NewCommand()
if err := cmd.Execute(); err != nil {
log.Error(err)
os.Exit(1)
}
}
这个简单的入口点创建并执行了一个命令对象,实际的工作在 manager 包中处理。
4.1.2 命令管理实现
daemon/manager/manager.go 中的 NewCommand 函数创建了命令对象:
func NewCommand() *cobra.Command {
configs := options.NewBootstrapConfigs()
cmd := &cobra.Command{
Use: "kmesh-daemon",
Short: "Start kmesh daemon",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
printFlags(cmd.Flags())
if err := configs.ParseConfigs(); err != nil {
return err
}
return Execute(configs)
},
// 其他配置...
}
addFlags(cmd, configs)
// 添加子命令
cmd.AddCommand(uninstall.NewCmd())
cmd.AddCommand(version.NewCmd())
return cmd
}
这里使用了 cobra 库来处理命令行参数,创建了主命令和子命令。
4.1.3 核心执行流程
Execute 函数是 Kmesh-daemon 的核心启动流程:
func Execute(configs *options.BootstrapConfigs) error {
// 移除内存锁定限制
err := rlimit.RemoveMemlock()
if err != nil {
log.Warn("rlimit.RemoveMemlock failed")
}
// 初始化 BPF 加载器
bpfLoader := bpf.NewBpfLoader(configs.BpfConfig)
defer bpfLoader.Stop()
if err := bpfLoader.Start(); err != nil {
return err
}
log.Info("bpf loader start successfully")
// 创建停止通道
stopCh := make(chan struct{})
defer close(stopCh)
// 初始化核心控制器
c := controller.NewController(configs, bpfLoader)
if err := c.Start(stopCh); err != nil {
return err
}
log.Info("controller start successfully")
defer c.Stop()
// 启动状态服务器
statusServer := status.NewServer(c, configs, bpfLoader)
statusServer.StartServer()
defer func() {
_ = statusServer.StopServer()
}()
// 启动 CNI 安装器
cniInstaller := cni.NewInstaller(configs.BpfConfig.Mode, configs.BpfConfig.EnableIPsec,
configs.CniConfig.CniMountNetEtcDIR, configs.CniConfig.CniConfigName, configs.CniConfig.CniConfigChained, configs.CniConfig.ServiceAccountPath)
if err := cniInstaller.Start(); err != nil {
return err
}
defer cniInstaller.Stop()
log.Info("start cni successfully")
// 设置信号处理
setupSignalHandler()
// 设置退出类型
restart.SetExitType(restart.InferNextStartType())
return nil
}
这个函数完成了以下关键步骤:
- 移除内存锁定限制,为 eBPF 程序做准备
- 初始化并启动 BPF 加载器
- 创建核心控制器并启动
- 启动状态服务器和 CNI 安装器
- 设置信号处理和退出类型
4.2 配置管理系统
Kmesh-daemon 使用结构化的配置管理系统,确保配置的一致性和可扩展性。
4.2.1 配置结构
daemon/options/options.go 中定义了核心配置结构:
type BootstrapConfigs struct {
BpfConfig *BpfConfig
CniConfig *cniConfig
ByPassConfig *byPassConfig
SecretManagerConfig *secretConfig
}
func NewBootstrapConfigs() *BootstrapConfigs {
return &BootstrapConfigs{
BpfConfig: &BpfConfig{},
CniConfig: &cniConfig{},
ByPassConfig: &byPassConfig{},
SecretManagerConfig: &secretConfig{},
}
}
这种结构化的配置方式使得各个部分的配置相互独立,同时又能统一管理。
4.2.2 配置解析
配置解析过程确保所有配置项都被正确处理:
func (c *BootstrapConfigs) ParseConfigs() error {
if err := c.BpfConfig.ParseConfig(); err != nil {
return fmt.Errorf("parse BpfConfig failed, %v", err)
}
if err := c.CniConfig.ParseConfig(); err != nil {
return fmt.Errorf("parse CniConfig failed, %v", err)
}
return nil
}
4.3 核心控制器实现
核心控制器是 Kmesh-daemon 的大脑,负责协调各个子系统的工作。
4.3.1 控制器结构
pkg/controller/controller.go 中定义了控制器结构:
type Controller struct {
mode string
bpfAdsObj *bpfads.BpfAds
bpfWorkloadObj *bpfwl.BpfWorkload
client *XdsClient
ipsecController *ipsec.IPSecController
enableByPass bool
enableSecretManager bool
bpfConfig *options.BpfConfig
loader *bpf.BpfLoader
dnsServer *dnsclient.LocalDNSServer
dnsProxyMu sync.Mutex
}
这个结构包含了控制器需要的所有组件,包括 BPF 对象、XDS 客户端、IPsec 控制器等。
4.3.2 启动过程
控制器的启动过程非常复杂,涉及多个子系统的初始化:
func (c *Controller) Start(stopCh <-chan struct{}) error {
// 创建 Kubernetes 客户端
clientset, err := kube.CreateKubeClient("")
if err != nil {
return err
}
// 初始化 IPsec 控制器(如果启用)
if c.bpfConfig.EnableIPsec {
// ... IPsec 初始化代码 ...
}
// 初始化 Kmesh 管理控制器
var kmeshManageController *manage.KmeshManageController
if c.mode == constants.DualEngineMode {
// 双引擎模式初始化
var secertManager *security.SecretManager
if c.enableSecretManager {
secertManager, err = security.NewSecretManager()
if err != nil {
return fmt.Errorf("secretManager create failed: %v", err)
}
go secertManager.Run(stopCh)
}
kmeshManageController, err = manage.NewKmeshManageController(clientset, secertManager, c.bpfWorkloadObj.XdpAuth.XdpAuthz.FD(), tcFd, c.mode)
} else {
// 内核原生模式初始化
kolog.KmeshModuleLog(stopCh)
kmeshManageController, err = manage.NewKmeshManageController(clientset, nil, -1, tcFd, c.mode)
}
if err != nil {
return fmt.Errorf("failed to start kmesh manage controller: %v", err)
}
go kmeshManageController.Run(stopCh)
// 初始化旁路控制器(如果启用)
if c.enableByPass {
c := bypass.NewByPassController(clientset)
go c.Run(stopCh)
}
// 启动日志读取器(如果内核版本支持)
if !helper.KernelVersionLowerThan5_13() {
if c.mode == constants.KernelNativeMode {
logger.StartLogReader(ctx, c.bpfAdsObj.SockConn.KmLogEvent)
} else if c.mode == constants.DualEngineMode {
logger.StartLogReader(ctx, c.bpfWorkloadObj.SockConn.KmLogEvent)
}
}
// 初始化监控配置
if !c.bpfConfig.EnableMonitoring {
if err := c.loader.UpdateEnableMonitoring(constants.DISABLED); err != nil {
return fmt.Errorf("failed to update config in order to start metric: %v", err)
}
}
// 初始化 XDS 客户端
c.client, err = NewXdsClient(c.mode, c.bpfAdsObj, c.bpfWorkloadObj, c.bpfConfig.EnableMonitoring, c.bpfConfig.EnableProfiling)
if err != nil {
return fmt.Errorf("failed to create XDS client: %w", err)
}
// 启动工作负载控制器和 DNS 代理
if c.client.WorkloadController != nil {
enableDnsProxy := c.bpfConfig.EnableDnsProxy || workload.EnableDNSProxy
c.client.WorkloadController.SetDnsProxyTrigger(enableDnsProxy)
if err := c.client.WorkloadController.Run(ctx, stopCh); err != nil {
return fmt.Errorf("failed to start workload controller: %+v", err)
}
if err := c.setupDNSProxy(); err != nil {
return fmt.Errorf("failed to start dns proxy: %+v", err)
}
} else {
c.client.AdsController.StartDnsController(stopCh)
}
// 运行 XDS 客户端
return c.client.Run(stopCh)
}
这个启动过程包含了多个关键步骤:
- 创建 Kubernetes 客户端,用于与集群交互
- 初始化 IPsec 控制器(如果启用了加密)
- 根据运行模式初始化不同的管理控制器
- 启动各种子控制器
- 配置监控和日志
- 初始化 XDS 客户端,建立与控制面的连接
- 启动工作负载控制器和 DNS 代理
4.4 BPF加载器实现
BPF加载器负责 eBPF 程序的生命周期管理,是 Kmesh-daemon 的核心组件之一。
4.4.1 加载器结构
pkg/bpf/bpf.go 中定义了 BPF 加载器:
type BpfLoader struct {
config *options.BpfConfig
obj *ads.BpfAds
workloadObj *workload.BpfWorkload
versionMap *ebpf.Map
}
func NewBpfLoader(config *options.BpfConfig) *BpfLoader {
return &BpfLoader{
config: config,
versionMap: NewVersionMap(config),
}
}
4.4.2 程序加载
BPF 程序的加载过程根据运行模式不同而不同:
func (l *BpfLoader) Start() error {
var err error
if l.config.KernelNativeEnabled() {
// 内核原生模式
if l.obj, err = ads.NewBpfAds(l.config); err != nil {
return err
}
if err = l.obj.Start(); err != nil {
return err
}
} else if l.config.DualEngineEnabled() {
// 双引擎模式
if l.workloadObj, err = workload.NewBpfWorkload(l.config); err != nil {
return err
}
if err = l.workloadObj.Start(); err != nil {
return err
}
l.setBpfProgOptions()
}
// 启动 MDA(如果启用)
if l.config.EnableMda {
if err = StartMda(); err != nil {
return err
}
}
return nil
}
4.4.3 版本管理
BPF 加载器实现了复杂的版本管理机制,支持热更新:
func NewVersionMap(config *options.BpfConfig) *ebpf.Map {
var versionPath string
var kmBpfPath string
var versionMap *ebpf.Map
if config.KernelNativeEnabled() {
versionPath = filepath.Join(config.BpfFsPath, constants.VersionPath)
kmBpfPath = filepath.Join(config.BpfFsPath, constants.KmKernelNativeBpfPath)
} else if config.DualEngineEnabled() {
versionPath = filepath.Join(config.BpfFsPath, constants.WorkloadVersionPath)
kmBpfPath = filepath.Join(config.BpfFsPath, constants.KmDualEngineBpfPath)
}
versionMapPinPath := filepath.Join(versionPath, "kmesh_version")
_, err := os.Stat(versionPath)
if err == nil {
versionMap = recoverVersionMap(versionMapPinPath)
if versionMap != nil {
restart.SetStartStatus(versionMap)
}
}
switch restart.GetStartType() {
case restart.Restart:
return versionMap
case restart.Update:
if updateVersionMap := restart.UpdateMapHandler(versionMap, versionPath, config); updateVersionMap != nil {
return updateVersionMap
}
default:
}
// 清理目录
err = os.RemoveAll(kmBpfPath)
if err != nil {
log.Errorf("Clean bpf maps and progs failed, err is:%v", err)
return nil
}
// 创建新的版本映射
mapSpec := &ebpf.MapSpec{
Name: "kmesh_version",
Type: ebpf.Array,
KeySize: 4,
ValueSize: 4,
MaxEntries: 1,
}
m, err := ebpf.NewMap(mapSpec)
if err != nil {
log.Errorf("Create kmesh_version map failed, err is %v", err)
return nil
}
// 存储版本信息
storeVersionInfo(m)
log.Infof("kmesh start with Normal")
restart.SetStartType(restart.Normal)
return m
}
这个版本管理机制确保了 Kmesh-daemon 能够正确处理重启和更新,保持系统的连续性。
4.5 XDS 协议集成
Kmesh-daemon 通过 XDS 协议与控制面通信,接收服务发现和配置信息。
4.5.1 XDS 客户端
XDS 客户端负责与控制面的通信,处理各种资源的更新:
c.client, err = NewXdsClient(c.mode, c.bpfAdsObj, c.bpfWorkloadObj, c.bpfConfig.EnableMonitoring, c.bpfConfig.EnableProfiling)
if err != nil {
return fmt.Errorf("failed to create XDS client: %w", err)
}
// 运行 XDS 客户端
return c.client.Run(stopCh)
4.5.2 资源处理
XDS 客户端处理多种类型的资源,包括:
- 集群配置
- 监听器配置
- 路由配置
- 端点配置
这些资源被转换为 eBPF 程序可以理解的格式,并加载到相应的映射中。
4.6 监控与可观察性
Kmesh-daemon 提供了丰富的监控和可观察性功能,帮助运维人员了解系统状态。
4.6.1 监控配置
// 初始化监控配置
if !c.bpfConfig.EnableMonitoring {
if err := c.loader.UpdateEnableMonitoring(constants.DISABLED); err != nil {
return fmt.Errorf("failed to update config in order to start metric: %v", err)
}
}
// 启动指标控制器
if c.client.WorkloadController != nil {
c.MetricController = telemetry.NewMetric(c.Processor.WorkloadCache, c.Processor.ServiceCache, enableMonitoring)
if enablePerfMonitor {
c.OperationMetricController = telemetry.NewBpfProgMetric()
c.MapMetricController = telemetry.NewMapMetric()
}
}
4.6.2 指标收集
Kmesh-daemon 收集多种类型的指标:
- BPF 程序执行指标
- 映射使用指标
- 服务调用指标
- 系统资源指标
这些指标可以通过 Prometheus 等监控系统进行采集和分析。
4.7 DNS 代理实现
Kmesh-daemon 实现了 DNS 代理功能,用于服务发现和负载均衡。
4.7.1 DNS 代理设置
func (c *Controller) setupDNSProxy() error {
if !c.client.WorkloadController.GetDnsProxyTrigger() {
return nil
}
server, err := dnsclient.NewLocalDNSServer(kmeshNamespace, clusterDomain, ":53", dnsForwardParallel)
if err != nil {
return fmt.Errorf("failed to start local dns server: %v", err)
}
debounceTime := time.Second
timer := time.NewTimer(0)
<-timer.C
h := func(rsp *service_discovery_v3.DeltaDiscoveryResponse) error {
if timer.Reset(debounceTime) {
return nil
}
go func() {
<-timer.C
c.updateDnsLookupTable()
}()
return nil
}
c.client.WorkloadController.Processor.WithResourceHandlers(workload.AddressType, h)
server.StartDNS()
c.dnsServer = server
return nil
}
4.7.2 DNS 查找表更新
DNS 代理会根据服务发现信息动态更新查找表:
func (c *Controller) updateDnsLookupTable() {
c.dnsProxyMu.Lock()
server := c.dnsServer
c.dnsProxyMu.Unlock()
if server == nil {
return
}
ntb := dns.NewNameTableBuilder(c.client.WorkloadController.Processor.ServiceCache, c.client.WorkloadController.Processor.WorkloadCache)
server.UpdateLookupTable(ntb.BuildNameTable())
log.Debugf("trigger name table update")
}

浙公网安备 33010602011771号