管理裸金属上的节点

本文档说明如何在裸金属 provider 上部署 worker 节点、对其进行扩容和缩容、替换特定机器,以及恢复故障节点。节点管理通过 MachineDeployment 编排的 Cluster API Machine 资源实现;provider 会从池中为每个 Machine 绑定一个 MachineInventory,并通过 clean / reprovision 计划驱动主机。

前提条件

WARNING

重要前提条件

  • 控制平面必须已经运行。请参见 创建集群
  • worker MachineInventoryPool 中的 Available inventory 数量必须至少等于目标副本数,并且还要包含 rollout 策略所需的额外余量。
  • 目标 Machine.spec.version 必须是 elemental-image-catalog ConfigMap 中的一个 key。
  • 任何 spec.storage.volumes[] 非空的 inventory,在可以计为 Available 之前,必须已经报告 status.storage.phase=PreparedStoragePrepared=True。在将新注册的、由存储管理的 inventory 加入 worker 池之前,请先参考 在裸金属主机上管理数据盘
INFO

配置指南

在使用本文档中的配置时:

  • 仅修改 <> 括号内的值。
  • 将占位符值替换为与你的环境相匹配的设置。
  • 除非明确要求,否则保留所有其他默认配置。

概述

组成 worker 节点组的四个资源:

  1. MachineInventoryPool<cluster-name>-worker-pool)——允许使用的 MachineInventory 名称集合。已在 创建集群 → 步骤 2 中创建。
  2. BaremetalMachineTemplate<cluster-name>-worker-template)——指向 worker 池。CAPI 要求每当底层池引用或分配策略发生变化时,都必须替换此模板(使用新的 metadata.name)。
  3. KubeadmConfigTemplate<cluster-name>-worker-bootstrap)——用于 kubeadm join 的 cloud-init user-data。裸金属 provider 会在 reprovision 时对该 user-data 做标准化处理(hostname、provider-idcriSocket);operator 不应预先填写这些字段。
  4. MachineDeployment——控制副本数、版本和 rollout 策略。

受管理的数据盘不属于 BaremetalMachineTemplate。其声明和保留的数据都属于每个长期存在的 MachineInventory,因此同一 worker 池中的两个成员可能会暴露不同的主机本地数据集,除非 operator 对其存储声明进行标准化并验证。

Cluster API 对模板的约定:正在运行的 Machine 集合会保留上一版模板的内存快照,因此就地编辑模板不会触发 rollout。worker 升级会创建新的 BaremetalMachineTemplate,并 patch MachineDeployment.spec.template.spec.infrastructureRef.name 指向它。

worker 节点部署

步骤 1:确认 worker 池容量

kubectl -n cpaas-system get machineinventorypools.infrastructure.cluster.x-k8s.io <cluster-name>-worker-pool

status.available 必须至少等于目标副本数。如果你需要更多容量,请注册更多主机(在这些主机上启动 SeedImage ISO——参见 创建集群 → 步骤 1),在每个 inventory 仍未分配时为其准备好任何受管理存储,然后将它们的名称添加到 spec.machineInventories 中。

步骤 2:配置 worker BaremetalMachineTemplate

apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: BaremetalMachineTemplate
metadata:
  name: <cluster-name>-worker-template
  namespace: cpaas-system
spec:
  template:
    spec:
      machineInventoryPoolRef:
        name: <cluster-name>-worker-pool

关键参数:

参数类型描述必填
.spec.template.spec.machineInventoryPoolRef.namestringworker 池名称(同一 namespace)。模板创建后不可变。

allocationPolicy 预留给未来扩展。目前 provider 将每个池都视为 Ordered——它会按声明顺序选择第一个 Available inventory。

步骤 3:配置 bootstrap 模板

仅从 Kubernetes 1.35 开始才需要 imagePullCredentialsVerificationPolicy: NeverVerify。在使用 Kubernetes 1.34 或更早版本创建 worker 时,请省略此参数。

apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
kind: KubeadmConfigTemplate
metadata:
  name: <cluster-name>-worker-bootstrap
  namespace: cpaas-system
spec:
  template:
    spec:
      users:
        - name: boot
          sudo: ALL=(ALL) NOPASSWD:ALL
          shell: /bin/bash
          sshAuthorizedKeys:
            - "<ssh-authorized-keys>"
      files:
        - path: /etc/kubernetes/patches/kubeletconfiguration0+strategic.json
          owner: "root:root"
          permissions: "0644"
          content: |
            {
              "apiVersion": "kubelet.config.k8s.io/v1beta1",
              "kind": "KubeletConfiguration",
              "imagePullCredentialsVerificationPolicy": "NeverVerify",
              "protectKernelDefaults": true,
              "staticPodPath": null,
              "tlsCertFile": "/etc/kubernetes/pki/kubelet.crt",
              "tlsPrivateKeyFile": "/etc/kubernetes/pki/kubelet.key",
              "streamingConnectionIdleTimeout": "5m",
              "clientCAFile": "/etc/kubernetes/pki/ca.crt"
            }
      joinConfiguration:
        patches:
          directory: /etc/kubernetes/patches

provider 在将 bootstrap user-data 写入 reprovision 计划之前,会对其进行最小化标准化处理,因此请将以下字段排除在模板之外:

  • Hostname / FQDN —— 自动根据 MachineInventoryPool.spec.machineInventories[].hostname 设置(如果未提供,则使用 inventory 名称)。
  • kubeletExtraArgs.provider-id —— 自动设置为 baremetal:///<inventory-name>
  • nodeRegistration.criSocket —— 在未设置时自动设置为 unix:///var/run/containerd/containerd.sock

标准化后的 user-data 也会写回 bootstrap secret 的 data["resolved-value"] 中用于调试;原始的 data["value"] 保持不变。

步骤 4:配置 MachineDeployment

apiVersion: cluster.x-k8s.io/v1beta1
kind: MachineDeployment
metadata:
  name: <cluster-name>-workers
  namespace: cpaas-system
spec:
  clusterName: <cluster-name>
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 0        # Bare-metal pools cannot over-provision.
      maxUnavailable: 1
  selector:
    matchLabels: {}
  template:
    metadata:
      labels:
        cluster.x-k8s.io/cluster-name: <cluster-name>
        pool.name: <cluster-name>-workers
    spec:
      clusterName: <cluster-name>
      version: <kubernetes-version>
      nodeDrainTimeout: 5m
      nodeVolumeDetachTimeout: 5m
      bootstrap:
        configRef:
          apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
          kind: KubeadmConfigTemplate
          name: <cluster-name>-worker-bootstrap
          namespace: cpaas-system
      infrastructureRef:
        apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
        kind: BaremetalMachineTemplate
        name: <cluster-name>-worker-template
        namespace: cpaas-system

关键参数:

参数类型描述必填
.spec.clusterNamestring目标集群名称。
.spec.replicasintworker 节点数量。必须满足 replicas ≤ MachineInventoryPool.status.available + status.allocated(针对 worker 池)。
.spec.template.spec.versionstringworker Kubernetes 版本。必须是 elemental-image-catalog 中的一个 key。可以与控制平面版本不同,但需遵守标准的 kubelet skew 策略。
.spec.strategy.rollingUpdate.maxSurgeint裸金属不支持超额预留——请保持为 0。provider 没有多余的物理主机先启动额外节点。
.spec.strategy.rollingUpdate.maxUnavailableintmaxSurge=0 时必须大于 0。worker 会在该预算内逐个重建。

应用并观察:

kubectl apply -f workers.yaml
kubectl -n cpaas-system get machinedeployments.cluster.x-k8s.io
kubectl -n cpaas-system get baremetalmachines.infrastructure.cluster.x-k8s.io -w
kubectl get nodes -o wide                     # workload cluster

节点管理操作

扩容 worker 节点

添加 worker 节点

使用场景:增加集群容量。

前提条件

  • worker 池有足够的 Available inventory。如果没有,请注册额外的主机(启动 SeedImage ISO 并确认新的 MachineInventory 对象),准备好任何受管理存储,然后将它们追加到 MachineInventoryPool.spec.machineInventories[]

操作步骤

  1. 检查当前状态

    kubectl -n cpaas-system get machines.cluster.x-k8s.io \
      -l cluster.x-k8s.io/deployment-name=<cluster-name>-workers
    kubectl -n cpaas-system get machineinventorypools.infrastructure.cluster.x-k8s.io \
      <cluster-name>-worker-pool

    确认 MachineInventoryPool.status.available 足以支持计划中的增量。

  2. 当需要更多 inventory 时扩展 worker 池

    kubectl -n cpaas-system edit machineinventorypool <cluster-name>-worker-pool

    追加新的 MachineInventory 名称——它们必须已经注册并处于 Ready 状态。带有受管理卷的 inventory 也必须已 Prepared;否则它们会增加 status.total,但仍无法分配。保存并退出,然后确认 status.available 按预期增加。

  3. 扩容 MachineDeployment

    kubectl -n cpaas-system patch machinedeployment <cluster-name>-workers \
      --type='json' -p='[{"op":"replace","path":"/spec/replicas","value":<new-replica-count>}]'
  4. 监控

    kubectl -n cpaas-system get baremetalmachines.infrastructure.cluster.x-k8s.io -w
    kubectl get nodes                # workload cluster

    新的 BaremetalMachine 对象会按 Pending → Allocated → Reprovisioning → Running 推进;随着新节点被绑定,池的 available 计数会减少。

移除 worker 节点

支持两种策略,其形式与上游 Cluster API contract 一致:

策略适用场景
随机移除可以移除任意节点,例如临时降低容量。
定向移除需要释放特定物理主机,例如硬件维护、替换或 IP 恢复。
INFO

Inventory 回收

clean 计划会停止 kubelet、停用声明的存储挂载、清除 CRI workload,并停止 containerd。它不会擦除受管理的文件系统、Kubernetes 持久化目录,也不会重置 OS——OS 清理会在之后进行,当同一个或不同的 inventory 被选中用于新的 BaremetalMachine 并执行 reprovision 计划时才会发生。在此之前,inventory 会回到 Available,并且可以再次被分配。删除 Machine 执行的是 Deactivate,而不是存储 Release,因此该 inventory 上的存储声明、文件系统 UUID 和数据都会保留。

随机移除
kubectl -n cpaas-system patch machinedeployment <cluster-name>-workers \
  --type='json' -p='[{"op":"replace","path":"/spec/replicas","value":<new-replica-count>}]'

CAPI 会按其标准顺序选择要删除的机器。每个被选中的 BaremetalMachine 都会进入 Preparing,provider 会写入一个 clean 计划,并且当计划报告 Applied 后,inventory 会回到 Available

定向移除
  1. 识别要移除的机器

    kubectl -n cpaas-system get machines.cluster.x-k8s.io \
      -l cluster.x-k8s.io/deployment-name=<cluster-name>-workers
  2. 给目标机器添加注解

    kubectl -n cpaas-system patch machine <machine-name> \
      --type='merge' -p='{"metadata":{"annotations":{"cluster.x-k8s.io/delete-machine":"true"}}}'

    对每台想要移除的机器重复此操作。

  3. 缩容时精确减少与已注解机器数量相同的副本数

    kubectl -n cpaas-system patch machinedeployment <cluster-name>-workers \
      --type='json' -p='[{"op":"replace","path":"/spec/replicas","value":<new-replica-count>}]'

    减少得更少会保留已注解的机器;减少得更多则会让随机机器也经过 clean 计划。

  4. 验证清理

    kubectl -n cpaas-system get baremetalmachines.infrastructure.cluster.x-k8s.io
    kubectl -n cpaas-system get machineinventories.elemental.cattle.io <inventory-name> -o yaml

    释放后的 inventory 必须显示 baremetal.alauda.io/allocation-state=Availablebaremetal.alauda.io/owner-* 注解必须被清除,而池注解必须保留。MachineInventory 本身不会被删除。如果它声明了受管理卷,则必须回到 status.storage.phase=PreparedStorageActive=False/Inactive;其业务挂载路径必须处于 inactive 状态,同时文件系统 UUID 和数据保持不变。

替换单个故障节点

如果某个 BaremetalMachine 进入 Failed,最安全的恢复方式是删除失败的 Machine。CAPI 会立即创建一个替代 Machine(因为 replicas 未发生变化),而裸金属 provider 会从同一个池中选择一个 Available inventory。大多数情况下,替代实例会使用不同的 MachineInventory;provider 不保证刚刚释放的 inventory 会被重新选中。主机本地的受管理数据不会随替代 Machine 一起迁移。如果应用必须复用某个特定 inventory 的数据,请使用专用池或刻意排序的池,并在依赖这些数据之前验证 BaremetalMachine.status.machineInventoryRef

kubectl -n cpaas-system delete machine <machine-name>
kubectl -n cpaas-system get baremetalmachines.infrastructure.cluster.x-k8s.io -w

请单独调查最初的故障:读取运行该计划的主机上的 BaremetalMachine.status.conditionsMachineInventory.status.plan.state 以及失败的 plan secret 中的 failed-output key。常见根因记录在下面的 常见故障模式 部分。

升级机器基础设施

BaremetalMachineTemplate 只包含池引用和分配策略——模板中没有 CPU、内存或磁盘声明。受管理存储是在一个未分配、处于 inactive 状态的 MachineInventory 上单独修改的;请参见 在裸金属主机上管理数据盘。需要更换模板的基础设施侧变更仅限于:

  • MachineDeployment 移动到不同的池。
  • 调整分配策略(当后续增加更多策略时)。

如需安全地切换模板:

  1. 创建一个新的 BaremetalMachineTemplate,使用新的 metadata.name 并引用新的池。

  2. 应用新模板。

  3. Patch MachineDeployment

    kubectl -n cpaas-system patch machinedeployment <cluster-name>-workers \
      --type='merge' \
      -p='{"spec":{"template":{"spec":{"infrastructureRef":{"name":"<new-template-name>"}}}}}'
  4. 观察滚动替换完成(maxSurge=0,一次一个节点)。

更新 bootstrap 模板

KubeadmConfigTemplate 在含义上与 BaremetalMachineTemplate 一样,也是一个不可变模板。就地修改现有模板不会让已有机器滚动更新;只有新创建的机器才会使用这些更改。

要执行 bootstrap 变更的 rollout:

  1. 导出现有模板:

    kubectl -n cpaas-system get kubeadmconfigtemplate <cluster-name>-worker-bootstrap -o yaml \
      > new-worker-bootstrap.yaml
  2. 修改 metadata.name,删除由服务器生成的字段(resourceVersionuidcreationTimestampmanagedFieldskubectl.kubernetes.io/last-applied-configuration)以及整个 status,并编辑所需字段。对于 Kubernetes 1.35 或更高版本,请将 必需的 kubelet patch 设置 添加到 /etc/kubernetes/patches/kubeletconfiguration0+strategic.json

  3. 应用新模板:

    kubectl apply -f new-worker-bootstrap.yaml
  4. Patch MachineDeployment 以引用新模板:

    kubectl -n cpaas-system patch machinedeployment <cluster-name>-workers \
      --type='merge' \
      -p='{"spec":{"template":{"spec":{"bootstrap":{"configRef":{"name":"<new-template-name>"}}}}}}'

    这会触发滚动替换。

升级 Kubernetes 版本

关于裸金属上的 Kubernetes 升级,请参见 在裸金属上升级集群。升级路径始终会替换节点——不存在原地 kubeadm upgrade 步骤。


池和 inventory 可观测性

provider 在每个 MachineInventory 上维护的注解,是判断“这台主机当前正在被用于什么”的权威来源:

注解取值含义
baremetal.alauda.io/pool池名称该 inventory 归属于哪个池。
baremetal.alauda.io/allocation-stateAvailable / Allocated / Preparing / Reprovisioning / Unavailable从 provider 视角看,该 inventory 的生命周期阶段。
baremetal.alauda.io/owner-cluster集群名称当前正在使用该 inventory 的集群(释放时清空)。
baremetal.alauda.io/owner-machineMachine 名称所属的 Cluster API Machine
baremetal.alauda.io/owner-baremetalmachineBaremetalMachine 名称所属的 provider 机器。

每个 inventory 的默认 plan secret 还会携带 baremetal.alauda.io/plan.type。普通节点生命周期使用 cleanreprovision;inventory 存储协调还会使用 storage-preparestorage-release。在排查存储问题时,请结合 plan type 一起检查 MachineInventory.status.storage.conditions.operation


常见故障模式

场景预期条件需要检查什么
池不存在BaremetalMachine 停留在 PendingInventoryAllocated=False / Reason=PoolMissingBaremetalMachineTemplate.spec.template.spec.machineInventoryPoolRef.name 和 namespace
池耗尽BaremetalMachine 停留在 PendingInventoryAllocated=False / Reason=PoolExhaustedMachineInventoryPool.status.available;inventory 所有权注解
成员缺失MachineInventoryPool.MembersValid=False / Ready=False池的 status.unavailable、失败 condition 上的 message
Inventory 未 Ready计入 status.unavailableMachineInventory.status.conditions[Ready]、plan secret 是否存在
plan secret 缺失inventory 不符合分配条件MachineInventory.status.plan.secretRef、被引用 Secret 是否存在
存储未准备inventory 不计为 AvailableStoragePrepared=FalseMachineInventory.status.storagestatus.observedStorage 的新鲜度和内容,以及 storage-prepare plan 输出
bootstrap secret 缺失BootstrapReady=False / Reason=BootstrapWaitingMachine.spec.bootstrap.dataSecretName
catalog 缺失BaremetalMachine 进入 FailedImageResolved=False / Reason=ImageCatalogMiss,不会写入 planelemental-image-catalog 的 keys
registry 注解缺失ImageResolved=False / Reason=ImageRegistryMissingCluster.metadata.annotations["cpaas.io/registry-address"]
reprovision plan 失败BaremetalMachine 进入 Failed,inventory 标记为 Unavailableplan secret 的 failed-output;主机串口控制台;可访问的平台 registry
受管理卷激活失败BaremetalMachineStorageReady=False;所需卷的节点就绪被阻塞稳定的设备标识、文件系统 UUID、挂载单元、重启后的新鲜观测,以及 plan 的 failed-output
clean 或 Deactivate 失败删除被 finalizer 阻止;inventory 标记为 Unavailableclean 计划输出、主机挂载点,以及 MachineInventory.status.storage.operation

如需完整的 operator 侧状态机参考,请参见 Provider 概览 → BaremetalMachine


下一步