在裸金属上创建集群
本文介绍如何使用裸金属 provider 在物理服务器上创建 Kubernetes 集群。目前,整个工作流仅使用 YAML,Fleet Essentials UI 尚不支持裸金属集群。
目录
前提条件1. 安装必需的插件2. 导入 OS 镜像并填充镜像目录3. 网络连接4. 主机时间同步5. TPM 决策6. 业务集群镜像 Registry7. 主机磁盘和启动准备8. 节点标签和污点集群创建工作流解析占位符值步骤 1:构建 SeedImage 并注册主机首次安装前调整 COS_STATE 大小可选:准备托管数据磁盘第 2 步:创建MachineInventoryPool 资源第 3 步:创建控制平面集群资源第 4 步:部署 Worker 节点集群验证使用 kubectl验证控制平面端点预期结果常见故障模式后续步骤附录完整的 KubeadmControlPlane 配置前提条件
创建集群之前,请确保满足以下所有前提条件。
1. 安装必需的插件
在 global 集群上安装以下插件:
- Alauda Container Platform Kubeadm Provider
- Alauda Container Platform Bare Metal Infrastructure Provider(umbrella chart,会同时安装裸金属管理器和
elemental-operator)
详情请参阅安装指南。
2. 导入 OS 镜像并填充镜像目录
创建任何集群资源之前,请先将两个裸金属 OS 镜像导入目标平台 registry,然后将目标 Kubernetes 版本添加到 elemental-image-catalog。这两个步骤都不会自动完成:provider 软件包不包含 OS 镜像,而 provider chart 创建的镜像目录为空。
只导入其中一个镜像并不足够。添加镜像目录条目或 SeedImage 引用,并不会导入相应的镜像。
导入镜像。 与 ACP 版本对应的 Bare Metal OS 下载包是一个 OCI 镜像布局归档,其中两个镜像使用同一标签;请参阅各 Provider 的镜像格式。在具有 containerd 且能够访问平台 registry 的主机上以 root 身份运行导入操作,例如在 global 控制平面节点上;Alauda OS 附带 ctr,但不附带 skopeo。/var/lib/containerd 所需的可用空间至少应与归档大小相同。将归档导入专用的 containerd 命名空间,然后列出创建的镜像名称:
输出会列出 baremetal-base-image:<os-image-tag> 和 baremetal-base-image-iso:<os-image-tag>。推送两个镜像,并确认 registry 中都列出了相应标签。--skip-verify 需要 --local:
最后一条命令会在两个镜像均成功推送后删除本地副本。对于 global 集群的 registry,admin 密码存储在 cpaas-system/registry-admin Secret 中。在灾难恢复对中,请将镜像导入两个 global 集群各自的 registry;请参阅将 global 集群准备为管理集群。
导入后,<base-image> 为 <registry-address>/tkestack/baremetal-base-image:<os-image-tag>,<base-image-iso> 为 <registry-address>/tkestack/baremetal-base-image-iso:<os-image-tag>。两个镜像必须来自同一归档。不要将集群资源指向构建 registry,不要混用来自不同归档的镜像,也不要替换为独立构建的镜像。
填充镜像目录。 cpaas-system 中的 elemental-image-catalog ConfigMap 会将 Machine.spec.version 映射到用于(重新)配置节点的 elemental upgrade 镜像。Provider chart 创建的该 ConfigMap 不包含任何条目,因此在添加目标版本之前,无法配置任何节点。请对 ConfigMap 执行修补而不是替换,以保留现有条目,然后检查结果:
作为 Machine.spec.version 使用的每个值(包括控制平面和工作节点的 MachineDeployment 资源)都必须是此 ConfigMap 中的键,保留开头的 v,并解析为已导入的 base-image。Provider 会在重新配置时,通过将条目中的 registry 部分替换为平台 registry 地址来解析镜像。如果缺少目标版本,则不会写入 reprovision 计划,并且 BaremetalMachine 最终会处于 Failed / Reason=ImageCatalogMiss 状态。之后再添加条目也不会清除此状态;请删除受影响的 Machine,使其所有者重新创建该资源。
3. 网络连接
裸金属主机完全通过网络注册、安装并加入集群,因此在第一台主机启动 SeedImage ISO 之前,必须开放下表中的所有网络路径。
Alauda OS 节点上的主机防火墙已预先配置并由平台维护,您无需管理它;此表也不是节点防火墙规则集。请参阅管理防火墙端口。您需要规划的是主机与其访问的端点之间的网络:主机子网、平台和 registry 之间的站点防火墙、安全组及路由器 ACL。
仅开放 443 不足以满足业务主机的要求
elemental-register 和 elemental-system-agent 都通过平台访问地址访问平台,因此注册和计划轮询只需要开放平台 HTTPS 端口。但这并非全部要求。相同的主机仍需通过 DNS 解析名称,从 11443 上的 registry 拉取操作系统和平台镜像,通过控制平面端点端口加入 API server,并与其他节点交换集群流量。如果防火墙审批只涵盖 443,主机可能会成功注册,随后却在安装或加入集群时失败,而且届时更难查明原因。
表格适用范围。 这些路径适用于业务集群主机,也就是本页创建的集群。以下两个相邻场景在其他文档中介绍,不包含在上表中:
- 引导。 当
global本身仍在安装时,其主机会向临时引导端点注册,适用的端口也有所不同;请参阅引导节点网络。 - 交接后的
global主机。global主机的系统智能体使用 Global 控制平面端点,而非平台入口路径;在 DR 对中,它会直接使用6443上的本地控制平面 VIP。请参阅端点和身份。
在引导阶段创建的 SeedImage 指向引导端点,交接后不得重复使用;请在活动的 global 集群上创建新的 MachineRegistration 和 SeedImage 对象。在 global 集群上创建的业务 SeedImage 在交接后仍然有效,因为其注册 URL 指向平台域名,而非引导地址。
控制平面端点。
- 对于
InternalSelf-built VIP,VIP 必须位于与控制平面节点 IP 相同的 Layer-2 广播域中。vrid在该域中必须唯一,网络必须允许 VRRP 和 gratuitous ARP 更新,并且节点镜像必须公开 IPVS,并允许 Alive 设置net.ipv4.conf.all.arp_accept=1和net.ipv4.vs.conntrack=1。 - 对于
ExternalLoadBalancer,请在创建集群之前预配 listener 和控制平面后端。请遵循规划控制平面端点。
首次启动时配置地址。
如果目标 VM 或物理主机启动到 live ISO 后未能通过 DHCP 获取地址,请在等待注册之前,从主机控制台手动配置网络。先检查 NetworkManager 连接名称,然后应用特定于站点的地址、网关和 DNS 值:
4. 主机时间同步
所有将成为集群节点的主机(包括控制平面和工作节点)在启动 SeedImage ISO 时都必须已经设置正确时间。平台对跨节点的要求是:每个集群节点使用统一时区,且节点间的时间同步误差不超过 10 秒;请参阅 Node Checks。该要求针对集群节点,因此也适用于此处,但此流程中没有任何步骤会替您验证这一点:该页面上的快速配置脚本和节点检查针对的是平台通过 SSH 加入的传统操作系统主机,不会在由 elemental-operator 安装的 Alauda OS 主机上运行。
请将时间同步作为步骤 1之前的门槛:
- 确保主机子网可以访问站点 NTP 服务器,并按照网络连接中的说明开放 UDP
123。生产集群不应依赖公共 NTP。 - 通过固件设置时钟,而不是通过操作系统。此时安装磁盘已按照主机磁盘和启动准备中的说明擦除,因此主机上没有可用于运行命令的操作系统。请在 BIOS/UEFI 设置中或通过 BMC 校正时间,并将硬件时钟保持为 UTC,以便安装 Alauda OS 后时区能够一致地应用。
- 不要只与参考时间比较,还要比较各主机之间的时间。在同一集群的所有目标主机中,任何主机启动 ISO 之前,时间差都必须保持在 10 秒的要求范围内。
- 节点达到
Ready后,在每个节点上使用timedatectl确认结果——它会报告时区以及时钟是否已同步;再使用chronyc tracking查看时间源和当前偏差。
整个集群的 PKI 都继承运行 kubeadm init 的主机时钟。kubeadm 根据该主机的当前时间设置证书颁发机构的 NotBefore,每个叶证书都会继承该 NotBefore,而每个证书的 NotAfter 也由此推导。时钟超前的主机会签发 PKI,其他节点和客户端会将其视为尚未生效,直到自身时钟追上;时钟落后的主机则会签发有效期短于配置值所表示期限的证书。硬件时钟从未同步过的服务器通常会偏差数分钟或数小时,而非数秒,导致控制平面完全无法启动——并且这一问题会在控制平面启动阶段才暴露,远晚于引入错误时钟的注册步骤。
Day-2 chrony MachineConfig 不能替代此步骤
配置 Chrony 时间服务会为已运行并加入集群的节点写入 /etc/chrony.conf。这是为集群配置站点 NTP 服务器以支持持续运行的正确方式,但它与此处的要求不同:它无法校正仍在安装 Alauda OS 或运行 kubeadm 的主机时钟。将时间同步推迟到此步骤会使安装和加入集群期间缺少保护。
5. TPM 决策
根据主机是否具有真实硬件 TPM(/dev/tpm0)设置 MachineRegistration.spec.config.elemental.registration.emulate-tpm,而不是根据主机是物理机还是虚拟机来决定:
emulate-tpm: false(或省略此字段)——仅适用于具有正常工作的硬件 TPM 的主机,以便elemental-register使用它进行auth: tpm。- 对于任何不具有硬件 TPM 的主机,使用
emulate-tpm: true和emulated-tpm-seed: -1。这包括虚拟机,也包括未配备 TPM 模块的物理服务器(例如 Dell R620)。在此类主机上,auth: tpm与emulate-tpm: false配合使用会导致elemental-register的 TPM 证明失败,且不会发送注册请求,因此elemental-operator记录的注册 POST 请求数为零。
6. 业务集群镜像 Registry
启动集群不需要 registry 凭证。裸金属主机仅使用平台 registry 地址安装操作系统并加入集群,因此无需配置凭证即可访问其 Node 全部处于 Ready 状态的集群。
下一步安装新集群上的平台组件时才需要凭证。这些组件会从 registry 拉取镜像,而需要身份验证的 registry 要求提供集群可用的凭证。
默认情况下,集群使用 global 集群的 registry;如果该 registry 需要身份验证,则由 public-registry-credential Secret 提供支持。若要改为从专用 registry 拉取平台组件镜像,请遵循为业务集群选择镜像 Registry。
凭证可以稍后配置,但必须提前选择 registry。集群在创建时即与其 registry 绑定,现有集群无法迁移到其他 registry。请在应用以下清单之前做出决定,即使您要稍后才安装平台组件也不例外。
无论选择哪种方案,都不会影响上述操作系统镜像。主机在 elemental install 期间以及每次重新预配时,都会从平台 registry 拉取 base-image 和 base-image-iso;此时尚未建立任何集群级绑定。
7. 主机磁盘和启动准备
启动 SeedImage ISO 之前,请对每台主机上的所有磁盘和虚拟磁盘 (VD) 进行分类。记录哪个设备是操作系统安装目标,以及哪些设备(如有)必须保留应用数据:
- 擦除选定的操作系统安装磁盘和任何其他过时的启动磁盘,确保不留有可启动的旧操作系统。主机必须启动 ISO,而不是磁盘上的旧操作系统。将
MachineRegistration.spec.config.elemental.install.device设置为准确的操作系统磁盘。 - 如果数据磁盘要通过
Adopt策略进行管理,则不要擦除该磁盘。请独立备份该磁盘,记录其稳定 ID 和文件系统 UUID,并确保不会将其选为安装设备。 - 用于
InitializeIfBlank的磁盘必须可丢弃,且必须明确为空。格式化操作仍需在主机注册后单独获得初始化批准;注册清单并未授权格式化。 - 从所有磁盘中移除残留的 Elemental 分区标签——
COS_STATE、COS_PERSISTENT、COS_OEM、COS_RECOVERY,而不只是预期的安装磁盘。Elemental 根据标签解析分区(blkid -L COS_STATE);第二个磁盘上残留的标签(例如来自先前安装或遗留的多路径成员)会使其解析到错误设备,导致重新预配快照器失败。 - 对于同一磁盘可能通过多个路径显示的主机(多路径),请确保这些路径都不会暴露仍带有
COS_*标签的磁盘;任何路径上的残留标签都可能优先于预期安装磁盘被解析。请清理磁盘,而不要禁用多路径——镜像会保持多路径启用,以支持从网络附加存储启动。 - 对于具有多个磁盘的主机,不要将
install.device留空,也不要将/dev/sda用作持久标识。请遵循在多磁盘裸金属主机上选择固定系统磁盘,以便重复使用同一个 ISO,并通过 WWN 选择每台主机的系统磁盘。 - 设置启动顺序,使主机优先从虚拟 CD / ISO 启动。
仅使用已注册 inventory 报告的稳定存储标识。/dev/sdX、/dev/vdX、/dev/nvmeXnY 和 /dev/mapper/mpathX 等 Linux 路径是运行时路径,不得放入 MachineInventory.spec.storage。
8. 节点标签和污点
若要为某个池中的节点设置专属标签、注解或污点(例如为监控、日志记录或入口流量预留专用池),请按照在节点上配置注解、标签和污点中的说明,在该池的资源上声明这些设置。请在创建池之前进行规划:只有在 capi-controller-manager 上启用标签同步后,Machine 标签才会传递到其 Node;该页面也介绍了此内容。
集群创建工作流
使用 YAML 时,先导入成对的 OS 镜像,然后依次完成五个必需的资源步骤;在加入节点池之前,还可以选择执行存储准备步骤。每个 Kubernetes 资源都必须应用到 cpaas-system 命名空间中。
重要的命名空间要求
所有裸金属资源都必须应用到 cpaas-system 命名空间中。provider 和 elemental-operator 只会协调该命名空间中的对象。
业务集群命名
业务 cluster-name 不得为 global。该名称保留给 global 集群,重复使用会导致业务集群的资源与 global 集群在 cpaas-system 中的资源发生冲突。作为约定,请将 CAPI Cluster 和 BaremetalCluster 的名称严格设置为 <cluster-name>,并为依赖资源(KubeadmControlPlane、KubeadmConfigTemplate、MachineDeployment、machine 模板、池、注册)添加 <cluster-name>- 前缀。
解析占位符值
下面的示例清单使用 <placeholder> 语法表示特定环境的值:
步骤 1:构建 SeedImage 并注册主机
创建一个描述注册 URL 和首次安装 cloud-config 的 MachineRegistration,以及一个将 elemental-operator 指向匹配 ISO 基础镜像的 SeedImage。
将 SeedImage.spec.baseImage 设置为导入的 base-image-iso 的最终目标平台 registry 引用。它必须与 image catalog 用于后续重新配置的导入 base-image 配对:两个镜像都必须来自同一个 OS 存档,不能来自不同存档。
首次安装前调整 COS_STATE 大小
state 分区存放正在运行的系统以及所有保留的快照。Elemental 默认的 8192 MiB 不足:同一镜像的快照会共享扩展区,但升级到不同镜像时,必须同时容纳两个大小约为 3.5 GiB 且互不相关的系统,并会在中途因 no space left on device 失败,导致每次重试都会留下一个不完整的快照。每次集群升级都会经过 elemental upgrade,而分区大小在安装时固定,因此该问题只会在之后暴露——此时集群已经投入生产,若不重新安装就无法重新分区。
请在安装时将其大小调整为至少 20480 MiB(20 GiB)。
该片段必须位于 SeedImage.spec.cloud-config 中的 stages.boot 下。将其放在 MachineRegistration.spec.config.cloud-config 中或任何其他阶段下,都会保留 8 GiB 分区,且不会报告错误。
请在部署其余主机之前,在第一台已安装主机上验证结果:
不要将 /etc/resolv.conf 添加到 SeedImage.spec.cloud-config。保持 ISO 通用;仅当首次启动注册路径需要时,才将站点特定的 resolver 配置放入 MachineRegistration.spec.config.cloud-config。在经过测试的 Global 部署流程中,ISO 不包含 resolver 文件;节点 DNS 随后由 kubeadm bootstrap 数据配置。
install.device、install.eject-cd 和 install.reboot 是有意设置的。如果省略目标磁盘,elemental install 可能会选择非预期设备。在多磁盘物理主机上,请使用固定系统磁盘工作流,而不要使用会变化的 /dev/sdX 名称。如果 eject-cd 或 reboot 为 false,主机可能会在首次安装后停留在 live 环境中,永远无法成为 Cluster API 可用的 inventory。
应用 manifest 并等待 SeedImage 构建完成:
不要使用 status.state 作为成功条件;当前 controller 不会填充该字段。只有当 SeedImageReady=True 的 reason 为 SeedImageBuildSuccess,且 status.downloadURL 和 status.checksumURL 均非空时,才能继续操作。下载生命周期已过期的 SeedImage 仍可能报告 SeedImageReady=True,但其 reason 会发生变化,且其 URL 会被清除。
从此 ISO 启动每台目标主机。elemental-register 首先运行(创建 MachineInventory 并上传 observedNetwork),随后 elemental install 将 OS 写入磁盘。安装完成后,主机会继续可用于执行 plan。如果 live ISO 环境没有 DHCP 地址,请按照网络连接中的说明,在主机控制台上手动配置 NetworkManager,然后再等待 MachineInventory。
确认注册:
计划使用的每个 inventory 都必须:
- 显示
Ready=True。 - 具有非空的
status.plan.secretRef.name。 - 具有与主机预期 NIC 匹配的
spec.observedNetwork(仅当需要在重新置备后保留安装时 IP 时才需要)。 - 需要托管数据磁盘时,运行支持 observer 的 OS image,报告最新的
status.observedStorage,并在分配到池之前达到status.storage.phase=Prepared。
记录准确的 MachineInventory 名称——下一步将按名称引用它们。
可选:准备托管数据磁盘
托管存储属于长期运行的 MachineInventory,而不属于 CAPI Machine 或 BaremetalMachineTemplate。请在 inventory 尚未分配、且尚未将其添加到生产池之前进行配置。
按照管理裸金属主机上的数据磁盘执行以下操作:
- 验证
elemental-storage-observer.service并检查status.observedStorage。 - 使用稳定 ID 选择每个设备,并选择
Adopt或InitializeIfBlank。 - 使用匹配的
storagectl二进制文件进行验证,并以原子方式修补声明,以及在需要时修补其初始化批准。 - 等待
StoragePrepared=True/AllRequiredVolumesPrepared和status.storage.phase=Prepared。
如果不应管理任何磁盘,请省略 spec.storage 或将其设置为 volumes: []。存储 controller 会将该 inventory 收敛到 Unmanaged,并使用 StoragePrepared=True/NoManagedVolumes,不会执行任何磁盘操作。
第 2 步:创建 MachineInventoryPool 资源
每个角色创建一个池。池 reconciler 会验证每个成员是否存在,计算容量计数器,并将 baremetal.alauda.io/pool=<pool-name> annotation 写入 inventory。
关键参数:
应用并验证:
健康的池会报告 Ready=True、total = len(spec.machineInventories) 和 available = total - allocated - preparing - reprovisioning - unavailable。在 spec.machineInventories 中列出但未通过验证的 inventory(缺失、plan secret 缺失、Ready=False 或存储未准备就绪)会增加池的 unavailable 计数器,并显示在 MembersValid 条件中。非空存储声明是分配门控条件:只有在基于最新 observation 成功完成 Prepare 后,inventory 才会被视为 Available 到 CAPI。
将控制平面池的大小设置为至少 KubeadmControlPlane.spec.replicas。将 worker 池的大小设置为至少 MachineDeployment.spec.replicas。对于滚动升级,池必须容纳完整的副本数——provider 使用同一池中的先删除后添加语义,绝不会同时容纳两者。
第 3 步:创建控制平面集群资源
创建 BaremetalCluster(声明所选的控制平面端点模式)、控制平面 BaremetalMachineTemplate(指向控制平面池)、KubeadmControlPlane(副本数 + kubeadm 配置)以及 CAPI Cluster。
Bare Metal API 在同一工作流中支持两种端点模式:
Internal:provider 部署 Alive,并协调 VIP 和控制平面后端成员关系。External:provider 跳过 Alive;负载均衡器所有者维护监听器、健康检查和后端成员关系。
不存在旧版 provider 版本选项卡,因为 Bare Metal 没有需要保留的早期 provider 版本。在下面的 manifest 中使用 <control-plane-load-balancer-type> 选择模式。
使用 OS image 中内置的 Kubernetes images
受支持的裸金属 OS image 会在 cloud.alauda.io/alauda 下预加载 kubeadm 控制平面、CoreDNS 和 etcd images。在 KCP 配置中保留该 repository,并使用 OS Support Matrix 中的组件标签。不要将其替换为 <registry-address>/tkestack:这会生成与 OS 中预加载 images 不匹配的 image 引用。OS 会通过 containerd 配置其内置的 pause image;不要将 pod-infra-container-image 添加到 KCP kubelet 参数中。
完整配置参考
下面的示例使用最小化的 KubeadmControlPlane。如需生产环境推荐的完整加固配置(包括 admission、audit、kubelet 补丁和 encryption provider),请参阅附录中的完整 KubeadmControlPlane 配置。
集群 annotations。 裸金属 provider 在协调期间依赖一组 Cluster annotations。operator 必须设置的权威 annotations 如下:
BaremetalCluster 参数:
应用并观察:
每个新的控制平面 BaremetalMachine 都会推进 Pending → Allocated → Reprovisioning → Running。请观察:
BaremetalMachine.status.machineInventoryRef.name— 被选中的 inventory。BaremetalMachine.status.planSecretRef.name— 正在驱动的 plan secret。该 secret 携带 annotationbaremetal.alauda.io/plan.type=reprovision。MachineInventory.status.plan.state— 主机完成cloud-init clean、elemental upgrade、重启以及kubeadm init/join后变为Applied。BaremetalCluster.status.conditions[EndpointReady]— 配置的控制平面端点可访问后变为 true。
裸金属 provider 不支持单节点控制平面。至少置备三个控制平面副本(KubeadmControlPlane.spec.replicas: 3),以便 etcd 保持法定人数。在 Internal 模式下,相同节点还会参与 Alive VIP 仲裁。
第 4 步:部署 Worker 节点
控制平面 Ready 后,创建 worker BaremetalMachineTemplate、worker KubeadmConfigTemplate 和 MachineDeployment。完整的 worker YAML 和参数表请参阅在裸金属上管理节点 → Worker 节点部署。
集群验证
使用 kubectl
验证控制平面端点
确认配置的模式和端点:
对于 Internal,验证 Alive 和节点先决条件:
在每个控制平面节点上运行以下命令,而不是在管理集群上运行:
对于 External,根据外部 LoadBalancer 合约验证负载均衡器前端和每个后端。确认负载均衡器所有者已注册当前所有控制平面节点,并且对每个后端执行 HTTPS /healthz 会返回 HTTP 200。
预期结果
成功创建的集群应显示:
Cluster.status.conditions[Ready]=True。KubeadmControlPlane个副本全部为Ready。- 每个
BaremetalMachine.status.phase=Running和status.ready=true。 - 每个使用的
MachineInventory.status.plan.state=Applied的 plan secret 都带有 annotationbaremetal.alauda.io/plan.type=reprovision(这是 annotation,而不是 label —-o jsonpath='{.metadata.annotations}')。 - 每个使用的、
spec.storage.volumes[]非空的 inventory 都报告status.storage.phase=Active、StoragePrepared=True和StorageActive=True;对应的BaremetalMachine报告StorageReady=True/AllVolumesReady。 MachineInventoryPool.status满足available + allocated + preparing + reprovisioning + unavailable = total。- Kubernetes Nodes 均为 Ready。
- 对于
Internal,Alive Pods 均为 Ready,并且可通过 Self-built VIP 访问 API。 - 对于
External,负载均衡器前端可访问,并且其后端列表与当前控制平面节点匹配。
常见故障模式
如需查看完整的 operator 侧状态机参考(每个 condition reason 和恢复操作),请参阅Provider 概览 → clean / reprovision plans。
后续步骤
创建集群后:
附录
完整的 KubeadmControlPlane 配置
适用于生产裸金属集群的强化配置,包含准入控制、审计策略、kubelet 补丁、加密提供程序和 IPv6 绑定地址。请替换解析占位符值表中的占位符。
只有从 Kubernetes 1.35 开始才需要 imagePullCredentialsVerificationPolicy: NeverVerify。使用 Kubernetes 1.34 或更早版本创建集群时,请省略此参数。
Worker bootstrap 配置与此对称 — 有关 worker KubeadmConfigTemplate,请参阅在裸金属上管理节点 → Bootstrap 模板。