ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Volcano SSH Plugin 详解:Job 内部免密 SSH 互信的密钥生成机制、参数配置与 MPI 实战

Volcano SSH Plugin 详解:Job 内部免密 SSH 互信的密钥生成机制、参数配置与 MPI 实战 Volcano SSH Plugin 详解Job 内部免密 SSH 互信的密钥生成机制、参数配置与 MPI 实战【免费下载链接】volcanoA Cloud Native Batch System (Project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/vol/volcanoVolcano 的 SSH Plugin 为同一 Job 内的所有 Pod 自动建立免密 SSH 通道它会自动生成或采用你提供的RSA 密钥对、创建 Secret、挂载进每个容器并生成一份包含全部主机名映射的 SSH config使 MPI 等分布式训练框架能够直接在 Pod 之间免密登录。读完本篇你将理解 SSH Plugin 从 Job 创建、Pod 生成到销毁的完整源码调用链、四个参数的确切语义与默认值并掌握一个可直接运行的 MPI Job 配置示例与结果验证方法。1. 背景与定位SSH Plugin 是 Volcano Job 控制器层面的插件之一专为 MPI 等需要节点间免密互信的分布式负载设计。它常与SVCPlugin 配合使用SSH Plugin 负责能不能免密登录SVC Plugin 负责域名怎么解析为 Pod 设置hostname/subdomain并创建 Headless Service。从源码结构看插件在 factory.go 的init()中完成注册func init() { RegisterPluginBuilder(ssh, ssh.New) RegisterPluginBuilder(env, env.New) RegisterPluginBuilder(svc, svc.New) ... }每个插件实现 PluginInterface 接口提供四个生命周期回调OnJobAddJob 创建时、OnPodCreate每个 Pod 创建前、OnJobDeleteJob 删除时、OnJobUpdateJob 更新时。Job 控制器在 job_controller_plugins.go 中遍历spec.plugins声明的插件并依次调用对应回调参数以--flagvalue形式传入。2. 工作机制源码级完整调用链SSH 插件的全部实现在 ssh.go 与 const.go 中可拆为Job 级与Pod 级两条主线。2.1 OnJobAdd生成密钥对并创建 SecretOnJobAdd 在 Job 首次进入控制器时执行核心逻辑端口校验先调用 validateSSHPort若ssh-port配置值不在 1~65535 范围内打印告警并回落到默认端口 22对应测试用例 TestInvalidSSHPortFallsBackToDefault。生成或采用密钥若用户配置了ssh-private-key走 withUserProvidedRsaKey直接使用用户提供的私钥/公钥字符串否则走 generateRsaKey用crypto/rsa现场生成一对2048 位 RSA密钥私钥编码为 PKCS1 PEMRSA PRIVATE KEY公钥用ssh.MarshalAuthorizedKey编码为authorized_keys格式。写入 SecretSecret 的四个 key 由 const.go 定义分别是Secret Key内容id_rsa私钥PEM 格式id_rsa.pub公钥ssh-rsa 格式authorized_keys公钥与id_rsa.pub内容相同config由 generateSSHConfig 生成的 SSH 客户端配置默认自动生成路径下authorized_keys的内容就是同一 Job 内所有 Pod 共享的公钥因此任一 Pod 都能用同一把私钥登录其他任意 Pod。幂等控制Secret 命名为job-name-sshsecretName创建成功后在job.Status.ControlledResources[plugin-ssh]打标记重复调用时直接返回。2.2 generateSSHConfig主机名清单的生成规则generateSSHConfig 遍历spec.tasks及其副本数为每个 Pod 生成一段 Host 配置。规则与 SVC 插件 一致hostName默认取 Pod 名即jobhelpers.MakePodName生成的job-task-index也可通过template.spec.hostname显式指定subdomain默认为 Job 名也可由template.spec.subdomain覆盖生成的配置以两行全局选项开头StrictHostKeyChecking no与UserKnownHostsFile /dev/null即跳过指纹确认、不写 known_hosts这正是免密体验的直接来源。生成结果形如示例 Job 为mpi-job1 个 master 2 个 workerStrictHostKeyChecking no UserKnownHostsFile /dev/null Host mpi-job-mpimaster-0 HostName mpi-job-mpimaster-0.mpi-job Port 22 Host mpi-job-mpiworker-0 HostName mpi-job-mpiworker-0.mpi-job Port 22 Host mpi-job-mpiworker-1 HostName mpi-job-mpiworker-1.mpi-job Port 22其中Port一行由ssh-port参数控制见 TestGenerateSSHConfigWithCustomPort 验证了Port 2026的输出。注意HostName hostName.subdomain是短域名形式它能否解析完全依赖 SVC Plugin 创建的 Headless Service见第 4 节。2.3 OnPodCreate把 Secret 挂进每个容器OnPodCreate 调用 mountRsaKey对 Pod 做两件事追加一个名为job-ssh的 Volume类型为 Secret通过Items精确映射上述四个 key 到.ssh/相对路径下DefaultMode默认为0600对所有containers和initContainers追加 VolumeMountMountPath为ssh-key-file-path默认/root/.sshSubPath为.ssh。由于使用SubPath挂载Secret 更新不会同步进容器——源码中 OnJobUpdate 因此被有意留空注释中引用了相关 issue 说明这一限制。另外当ssh-key-file-path不是默认的/root/.ssh意味着容器可能以非 root 用户运行时文件权限会从0600放宽为0644以便非 root 用户可读。2.4 OnJobDelete资源清理OnJobDelete 依据ControlledResources标记判断该 Secret 是否由本插件创建若是则删除job-sshSecret 并移除标记保证 Job 销毁后不残留敏感凭据。3. 插件参数详解以下参数均在 Job 的spec.plugins.ssh列表中以--flagvalue形式传入解析入口addFlags测试覆盖见 TestSSHPluginID参数类型默认值必填说明示例1ssh-key-file-pathString/root/.ssh否存放 SSH 私钥/公钥的路径ssh: [--ssh-key-file-path/home/user/.ssh]2ssh-private-keyString自动生成2048 位 RSA否用户提供的私钥字符串ssh: [--ssh-private-key-----BEGIN RSA PRIVATE KEY-----\n...]3ssh-public-keyString由私钥推导否用户提供的公钥字符串ssh-rsa 格式ssh: [--ssh-public-keyssh-rsa AAAAB3... roothost]4ssh-portInt22否写入生成的 SSH config 的端口适用于 22 端口被占用的场景ssh: [--ssh-port2026]几点必须注意的约束与源码行为一一对应Volcano 不会校验ssh-key-file-path它只做挂载不检查路径是否可写、目录是否存在请自行保证正确性最省事的做法是不传参数留空时 Volcano 自动生成密钥对并完成全部配置对应ssh: []的注册方式若配置了ssh-private-key请同时确认ssh-public-key与之配套且内容正确Volcano 同样不做密钥合法性校验ssh-port取值必须在 1~65535 之间非法值会被静默回落为 22 并打印 Warning 日志。4. 与 SVC Plugin 的配合主机名从哪来SSH Plugin 生成的 config 中只写了hostname.subdomain形式的短域名域名解析需要 SVC Plugin 补齐。从 svc.go 的实现看它在OnPodCreate中为 Pod 补齐hostname缺省为 Pod 名与subdomain缺省为 Job 名从而获得 FQDNhostname.subdomain.namespace.svc.cluster.local在OnJobAdd中创建一个ClusterIP: None的同名 Headless Service使 KubeDNS 返回 Pod IP 的 A 记录同时除非显式--disable-network-policy创建一个 NetworkPolicy把该 Job 的网络访问限制在 Job 内部 Pod 之间。SVC Plugin 还会把各 task 的主机清单写入 ConfigMapjob-svc并挂载到/etc/volcano/见 const.go每个 task 一个task.host文件并通过环境变量VC_TASK_HOSTS逗号分隔与VC_TASK_NUM暴露主机列表——MPI 示例里的cat /etc/volcano/mpiworker.host正是这一机制。5. 实战部署一个免密互信的 MPI Job下面这个完整示例创建 1 个mpimaster 2 个mpiworker的 Job启用ssh与svc两个插件原始示例亦收录于 how_to_use_ssh_plugin.mdapiVersion: batch.volcano.sh/v1alpha1 kind: Job metadata: name: mpi-job spec: minAvailable: 3 schedulerName: volcano plugins: ssh: [] ## SSH plugin register svc: [] tasks: - replicas: 1 name: mpimaster template: spec: containers: - command: - /bin/bash - -c - | mkdir -p /var/run/sshd; /usr/sbin/sshd; MPI_HOSTcat /etc/volcano/mpiworker.host | tr \n ,; sleep 10; mpiexec --allow-run-as-root --host ${MPI_HOST} -np 2 --prefix /usr/local/openmpi-3.1.5 python /tmp/gpu-test.py; sleep 3600; image: lyd911/mindspore-gpu-example:0.2.0 name: mpimaster ports: - containerPort: 22 name: mpijob-port workingDir: /home restartPolicy: OnFailure - replicas: 2 name: mpiworker template: spec: containers: - command: - /bin/bash - -c - | mkdir -p /var/run/sshd; /usr/sbin/sshd -D; image: lyd911/mindspore-gpu-example:0.2.0 name: mpiworker resources: limits: nvidia.com/gpu: 1 ports: - containerPort: 22 name: mpijob-port workingDir: /home restartPolicy: OnFailure要点说明ssh: []与svc: []均以空列表注册即全部使用默认值默认路径/root/.ssh、自动生成密钥、端口 22master 容器先从 SVC Plugin 挂载的/etc/volcano/mpiworker.host读出 worker 主机清单拼成MPI_HOST再用mpiexec拉起 2 个进程——MPI 的远程执行底层正是依赖 SSH 免密登录镜像中必须能启动sshd所有容器都要保证sshd服务可用示例中 worker 用sshd -D前台常驻同时容器声明containerPort: 22作为 SSH 端口的语义声明。5.1 验证生成的 SSH config由于默认挂载路径为/root/.ssh进入任意 Pod 后直接查看$ cat /root/.ssh/config StrictHostKeyChecking no UserKnownHostsFile /dev/null Host mpi-job-mpimaster-0 HostName mpi-job-mpimaster-0.mpi-job Port 22 Host mpi-job-mpiworker-0 HostName mpi-job-mpiworker-0.mpi-job Port 22 Host mpi-job-mpiworker-1 HostName mpi-job-mpiworker-1.mpi-job Port 22该文件即 2.2 节generateSSHConfig的输出每个 Host 别名是短主机名HostName是hostname.subdomainPort是ssh-port值。若你自定义了ssh-port2026此处所有Port行都会变为2026。5.2 免密登录其他 Pod在 master Pod 中直接输入主机名别名即可登录同 Job 的任意 Pod无需密码[rootmpi-job-master-0 /]# ssh mpi-job-mpiworker-0 Warning: Permanently added mpi-job-mpiworker-0.mpi-job,X.X.X.X (ECDSA) to the list of known hosts. Welcome to Ubuntu 18.04.3 LTS ... Last login: Thu Apr 14 07:19:05 2022 from 10.244.0.67 rootmpi-job-mpiworker-0:~#登录成功的完整条件是三者齐备密钥已挂载SSH Plugin、域名可解析SVC Plugin 的 Headless Service hostname/subdomain、容器内 sshd 正在监听镜像/启动命令保证。三者缺一不可。6. 使用注意与常见排错点sshd 必须可用所有参与互信的容器都需要运行sshd并监听 config 中声明的端口插件不会替你安装或启动它Job 重建会换密钥密钥 Secret 随 Job 生命周期创建与删除同名 Job 重新提交时OnJobAdd会重新生成密钥并覆盖 Secret通过CreateOrUpdateSecret更新旧 Pod 因SubPath挂载限制不会感知更新自定义挂载路径的权限差异ssh-key-file-path偏离默认/root/.ssh时文件权限从0600变为0644mountRsaKey这是为非 root 用户场景做的妥协安全敏感度高的场景建议保持默认路径与 root 用户端口冲突当 Pod 内 22 端口已被占用时用ssh-port指定自定义端口同时确保 sshd 也监听同一端口网络策略限制SVC Plugin 默认创建的 NetworkPolicy 只允许 Job 内部 Pod 互访除非--disable-network-policytrue这意味着 Job 外部无法 SSH 进来Job 内部登录不受影响。更多插件参数与组合用法可参考仓库中的 example/job-plugin.yaml含env/ssh/svc三个插件的参数注释SSH 插件参数解析行为的完整用例见 ssh_test.go。【免费下载链接】volcanoA Cloud Native Batch System (Project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/vol/volcano创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表