【kubernetes/k8s源码分析】 rook operator agent源码分析

本文介绍了rook ceph agent的启动命令和默认参数,每个k8s node启动rook agent并配置Flexvolume插件处理存储操作。详细分析了startAgent函数,包括创建客户端和上下文、处理flexvolume driver事件、启动FlexvolumeServer及创建ClusterController等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

启动命令

    rook ceph agent

启动默认参数

    --help=false, --log-flush-frequency=5s, --log-level=INFO

    挂载路经:/usr/libexec/kubernetes/kubelet-plugins/volume/exec

每个 k8s node 中都启动 rook agent,接受 rook operator 管理,每个agent都配置一个Flexvolume插件,该插件与Kubernetes的卷控制器框架集成在一起。处理节点上所需的所有存储操作,例如附加网络存储设备,安装卷和格式化文件系统

所有代码一个模式,直接分析startAgent函数

 

1. 创建客户端,创建上下文

clientset, apiExtClientset, rookClientset, err := rook.GetClientset()
if err != nil {
	rook.TerminateFatal(fmt.Errorf("failed to get k8s client. %+v", err))
}

logger.Infof("starting rook ceph agent")
context := &clusterd.Context{
	Executor:              &exec.CommandExecutor{},
	ConfigDir:             k8sutil.DataDir,
	NetworkInfo:           clusterd.NetworkInfo{},
	Clientset:             clientset,
	APIExtensionClientset: apiExtClientset,
	RookClientset:         rookClientset,
}

  1.1 attachement.New

    创建CRD controller管理CRD资源,实现了Attachment接口

  • Create(volumeAttachment *rookalpha.Volume) error
  • Get(namespace, name string) (*rookalpha.Volume, error)
  • List(namespace string) (*rookalpha.VolumeList, error) Update(volumeAttachment *rookalpha.Volume) error
  • Delete(namespace, name string) error
volumeAttachmentController, err := attachment.New(a.context)
if err != nil {
	return fmt.Errorf("failed to create volume attachment controller: %+v", err)
}

  1.2 NewVolumeManager

    NewVolumeManager对于ceph卷创建attacher

// NewVolumeManager create attacher for ceph volumes
func NewVolumeManager(context *clusterd.Context) (*VolumeManager, error) {
	vm := &VolumeManager{
		context:          context,
		devicePathFinder: &devicePathFinder{},
	}
	err := vm.Init()
	return vm, err
}

    1.2.1 Init函数

     使用系统调用cat /lib/modules/3.10.0-957.el7.x86_64/modules.builtin | grep rbd,rbd没有加载内和模块

// check if the rbd is a builtin kernel module, if it is then we don't need to load it manually
in, err := sys.IsBuiltinKernelModule(rbdKernelModuleName, vm.context.Executor)
if err != nil {
	return err
}
if in == true {
	logger.Noticef("volume manager is a builtin kernel module, don't load it manually")
	return nil
}

   1.2.2 执行系统调用命令 modinfo -F parm rbd

    # modinfo -F parm rbd
       single_major:Use a single major number for all rbd devices (default: true) (bool)

func CheckKernelModuleParam(name, param string, executor pkgexec.Executor) (bool, error) {
	out, err := executor.ExecuteCommandWithOutput(false, "check kmod param", "modinfo", "-F", "parm", name)
	if err != nil {
		return false, fmt.Errorf("failed to check for %s module %s param: %+v", name, param, err)
	}

	result := Grep(out, fmt.Sprintf("^%s", param))
	return result != "", nil
}

   1.2.3 执行系统调用命令 odprobe rbd single_major=Y 

func LoadKernelModule(name string, options []string, executor pkgexec.Executor) error {
	if options == nil {
		options = []string{}
	}

	args := append([]string{name}, options...)

	if err := executor.ExecuteCommand(false, fmt.Sprintf("modprobe %s", name), "modprobe", args[:]...); err != nil {
		return fmt.Errorf("failed to load kernel module %s: %+v", name, err)
	}

	return nil
}

 

2. 创建controller来处理flexvolume driver的事件

     Controller实现了 Attach Detach方法,FlexvolumeServer 包裹了 Controller

flexvolumeController := flexvolume.NewController(a.context, volumeAttachmentController, volumeManager, mountSecurityMode)

flexvolumeServer := flexvolume.NewFlexvolumeServer(
	a.context,
	flexvolumeController,
)

 

3. FlexvolumeServer Start函数

    注册rook,rook-ceph的driver name,监听socker与driver通信,路径为/flexmnt,宿主机路径/usr/libexec/kubernetes/kubelet-plugins/volume/exec 

    创建 socket

flexDriverVendors := []string{flexvolume.FlexvolumeVendor, flexvolume.FlexvolumeVendorLegacy}
for i, vendor := range flexDriverVendors {
	if i > 0 {
		// Wait before the next driver is registered. In 1.11 and newer there is a timing issue if flex drivers are registered too quickly.
		// See https://github.com/rook/rook/issues/1501 and https://github.com/kubernetes/kubernetes/issues/60694
		time.Sleep(time.Second)
	}

	err = flexvolumeServer.Start(vendor, driverName)
	if err != nil {
		return fmt.Errorf("failed to start flex volume server %s/%s, %+v", vendor, driverName, err)
	}

	// Wait before the next driver is registered
	time.Sleep(time.Second)

	// Register drivers both with the name of the namespace and the name "rook"
	// for the volume plugins not based on the namespace.
	err = flexvolumeServer.Start(vendor, flexvolume.FlexDriverName)
	if err != nil {
		return fmt.Errorf("failed to start flex volume server %s/%s. %+v", vendor, flexvolume.FlexDriverName, err)
	}
}

  

4. NewClusterController函数

    创建一个controller实例,watch集群事件,rook-ceph名下的CephCluster资源

// NewClusterController creates a new instance of a ClusterController
func NewClusterController(context *clusterd.Context, flexvolumeController flexvolume.VolumeController,
	volumeAttachment attachment.Attachment) *ClusterController {

	return &ClusterController{
		context:              context,
		volumeAttachment:     volumeAttachment,
		flexvolumeController: flexvolumeController,
	}
}

 

 

 
<think>我们正在解决一个关于Rook工具执行时的格式错误问题。用户遇到的错误信息是"exec /usr/local/bin/rook exec format error"。这个错误通常意味着在尝试执行二进制文件时,系统无法识别其格式,可能的原因包括: 1. 二进制文件与当前系统的架构不匹配(例如,在ARM系统上运行x86的二进制文件,或者反之)。 2. 二进制文件损坏或不完整。 3. 缺少必要的动态链接库(虽然错误信息不是直接关于动态链接库的,但也是可能的原因之一)。 4. 在错误的平台上运行(比如在Linux上运行Windows的二进制文件,但这里路径是Linux的,所以可能是跨架构问题)。 根据引用[5]中的错误信息,我们还可以看到另一个相关错误:"Failed to provision volume with StorageClass 'storageclass01': failed to create rbd image: executable file not found in $PATH, command output:"。这个错误提示我们,可能是由于rook工具在环境变量中找不到,或者无法执行(包括格式错误)导致的。 结合用户的问题,我们重点解决格式错误。 解决步骤: 1. 确认二进制文件的架构与操作系统匹配。 - 在运行rook的节点上,执行 `uname -m` 查看系统架构(常见的有x86_64, aarch64等)。 - 然后检查rook二进制文件的架构,可以使用 `file /usr/local/bin/rook` 命令。 2. 如果架构不匹配,需要下载对应架构的rook二进制文件。 3. 如果架构匹配,则可能是文件损坏。可以重新下载rook二进制文件,并确保下载完整。 4. 检查文件的权限,确保有可执行权限。使用 `ls -l /usr/local/bin/rook` 查看权限,如果没有执行权限,使用 `chmod +x /usr/local/bin/rook` 添加。 5. 检查动态链接库依赖(如果不是静态编译的二进制文件)。使用 `ldd /usr/local/bin/rook` 查看依赖的库是否都存在。如果缺少某些库,需要安装相应的库。 6. 如果以上步骤都无法解决,考虑是否在容器环境中运行?如果是,确保容器内的基础镜像与rook二进制文件兼容。 另外,引用[1]中提到了rook的官方文档,我们可以参考官方文档中关于安装rook工具的部分,确保安装步骤正确。 根据引用[1]的文档链接,我们可以查看rook的快速入门指南,特别是关于部署rook工具箱(toolbox)的部分,因为工具箱中包含了rook的常用工具。如果rook是通过工具箱运行的,那么需要确保工具箱的镜像与节点系统架构匹配。 具体步骤: 步骤1:检查系统架构和二进制文件架构 - 在节点上运行:`uname -m` - 检查rook二进制文件:`file /usr/local/bin/rook` 步骤2:重新下载或安装rook - 从rook的GitHub release页面下载对应架构的二进制文件:https://github.com/rook/rook/releases 步骤3:检查权限并添加执行权限(如果需要) - `chmod +x /usr/local/bin/rook` 步骤4:检查依赖 - 运行 `ldd /usr/local/bin/rook`,如果提示不是动态可执行文件(比如静态编译),则无需依赖库。如果显示缺少某些库,则安装这些库。 步骤5:如果是在容器中运行,确保容器镜像的基础环境与二进制文件兼容。例如,如果二进制文件是动态链接的,而基础镜像没有所需的库,则需要添加。 如果用户是通过rook工具箱运行命令,那么可能需要检查工具箱的镜像。在rook的文档中,工具箱的部署方式如下(引用[1]中的链接): - 部署工具箱:`kubectl create -f toolbox.yaml` - 然后进入工具箱:`kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') bash` 如果工具箱的镜像与节点架构不匹配,也会出现类似问题。因此,需要确保工具箱镜像的拉取与节点架构一致。 另外,引用[5]的错误信息中提到了“executable file not found in $PATH”,这可能是由于格式错误导致系统认为不是可执行文件,从而被当作不存在处理。因此,我们的解决方案应着重于二进制文件本身。 如果以上步骤都尝试了仍然无法解决,可以考虑在相同架构的机器上重新编译rook。 生成相关问题: 1. 如何确认Linux系统的架构? 2. Rook工具箱部署失败的可能原因有哪些? 3. 如何为不同架构的节点部署Rook? 4. 在Kubernetes中如何检查Pod运行节点的架构? 5. 如何静态编译Rook以避免动态链接库的问题?</think>### 解决 Rook 二进制文件格式错误的方法 出现 `exec /usr/local/bin/rook exec format error` 错误通常由以下原因导致,请按步骤排查: --- #### 1. **架构不匹配(最常见原因)** - **问题**:Rook 二进制文件与当前系统 CPU 架构(如 x86_64 和 ARM)不兼容。 - **解决方法**: 1. 确认系统架构: ```bash uname -m # 输出示例: x86_64 或 aarch64 ``` 2. 从 [Rook GitHub Releases](https://github.com/rook/rook/releases) 下载匹配架构的二进制文件。 3. 替换旧文件: ```bash mv rook /usr/local/bin/rook chmod +x /usr/local/bin/rook ``` --- #### 2. **文件损坏或不完整** - **问题**:二进制文件在下载/传输过程中损坏。 - **解决方法**: 1. 重新下载文件并验证校验和: ```bash wget https://github.com/rook/rook/releases/download/v1.13.0/rook-v1.13.0-linux-amd64.tar.gz sha256sum rook-v1.13.0-linux-amd64.tar.gz # 与官方校验和对比 ``` 2. 解压后替换原文件。 --- #### 3. **动态链接库缺失** - **问题**:二进制文件依赖的库未安装(常见于非静态编译版本)。 - **解决方法**: 1. 检查依赖项: ```bash ldd /usr/local/bin/rook # 查看未找到的库(如 libc.musl) ``` 2. 安装缺失的库: ```bash # Ubuntu/Debian sudo apt install libc6 # CentOS/RHEL sudo yum install glibc ``` --- #### 4. **容器环境兼容性问题** - **问题**:在容器中运行 Rook 时未使用匹配的基础镜像(如 Alpine 与 Glibc 不兼容)。 - **解决方法**: 1. 确保容器镜像与 Rook 二进制编译环境一致(如使用 `ubuntu` 而非 `alpine`)。 2. 或在 Dockerfile 中安装兼容库: ```dockerfile FROM alpine:latest RUN apk add --no-cache libc6-compat # 针对 Alpine 的兼容层 COPY rook /usr/local/bin/ ``` --- #### 5. **文件权限问题** - **问题**:缺少可执行权限。 - **解决方法**: ```bash chmod +x /usr/local/bin/rook ``` --- #### 6. **验证是否解决** ```bash /usr/local/bin/rook version # 成功应输出版本信息 ``` > **关键提示**:若问题仍存在,检查 Rook 部署日志以确认环境: > ```bash > kubectl logs -n rook-ceph deploy/rook-ceph-operator > ``` --- ### 相关问题 1. 如何检查 Kubernetes 节点的 CPU 架构? 2. Rook 部署 Ceph 时出现 `executable file not found in $PATH` 错误如何解决?[^5] 3. 如何为不同架构的 Kubernetes 节点定制化部署 Rook? 4. Rook 工具箱(toolbox)无法启动的可能原因有哪些?[^1] 5. 在混合架构集群(ARM/x86)中部署 Rook 需要注意什么? [^1]: 通过 Rook 部署和对接 Ceph,使用 Kubernetes 提供 Ceph 服务。官方文档详细说明了部署步骤和常见问题修复方法。 [^5]: 当 StorageClass 配置错误或 Rook 二进制不可执行时,会出现 `executable file not found in $PATH` 错误,需检查二进制兼容性和路径配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值