在 Huawei DCS 上创建集群

本文档说明如何在 Huawei DCS 平台上创建 Kubernetes 集群。可通过 manifest 提供基于 YAML 的集群创建功能。如果已安装 Fleet Essentials,并且 Alauda Container Platform DCS Infrastructure Provider 版本为 1.0.13 或更高,还可以通过 Web UI 创建集群。如果工作流依赖由池管理的持久磁盘,请使用 DCS provider v1.0.16 或更高版本。在 v1.0.16 中,DCSIpHostnamePool 上的 persistentDisk 声明仅可通过 YAML 使用,Web UI 中不暴露该字段。

INFO

Web UI 提供带校验的引导式工作流,而 YAML 提供更灵活的自动化能力。

先决条件

在创建集群之前,请确保满足以下所有先决条件:

1. 基础设施资源

在创建集群之前,请先配置以下基础设施资源:

  • Cloud Credential - DCS 平台访问信息
  • IP Pool - 集群节点、附加 NIC 以及任何 IP 槽位持久磁盘(例如 /var/cpaas)的网络配置
  • Machine Template - 控制平面和 worker 节点的 VM 规格,不包括由池管理的持久磁盘

有关详细配置说明,请参见 Huawei DCS 的基础设施资源

2. 必需插件安装

global 集群上安装以下插件:

  • Alauda Container Platform Kubeadm Provider
  • Alauda Container Platform DCS Infrastructure Provider

有关详细安装说明,请参见 安装指南

3. 虚拟机模板准备

在进行 Kubernetes 安装时,必须:

  • 将 Alauda OS 镜像上传到 DCS 平台
  • 基于该镜像创建虚拟机模板
  • 确保模板包含所有必要的 Kubernetes 组件
  • 如果计划使用持久磁盘,请使用 DCS VM 模板 4.2.1 或更高版本,因为安全关机和磁盘卸载依赖 guest tools
  • 对于任何依赖池管理的持久磁盘的集群,请使用逐个替换方式。保持控制平面和 worker 节点池上的 maxSurge: 0

有关每个 VM 镜像中包含的 Kubernetes 组件详情,请参见 OS Support Matrix

4. 网络连通性

global 集群节点必须能够到达 DCS 平台上的两个不同目标:

来源目标端口目的
global 集群节点DCS VRM 虚拟 IPTCP/7443DCS REST API。涵盖集群生命周期调用以及文件上传的第一步(applyUpload)。
global 集群节点DCS 物理主机 MGMT IP(可能接收克隆的每台主机)DCS 返回的端口;通常为 TCP/8443;请向 DCS 管理员确认Ignition ISO 的文件流上传。provider 将文件流式传输到 applyUpload 响应返回的 URL。

文件上传是一个两步流程:provider 先在 VRM 虚拟 IP(TCP/7443)上调用 applyUpload;DCS 平台随后返回一个指向特定物理主机管理 IP 和端口的 URL;然后 provider 将文件流式传输到该 URL。在创建集群之前,两个目标都必须可以端到端连通。

如果 global 集群节点使用多 NIC 布局(例如,一块 NIC 位于 ACP 集群网络,另一块 NIC 位于部署 DCS 的客户管理网络),请确保 这两个 目标——VRM 虚拟 IP 以及每个 DCS 物理主机 MGMT IP——都可以从相应 NIC 路由到达。

要求:集群创建和管理必须同时连通这两个目标。

5. LoadBalancer 配置

在创建集群之前,请为 Kubernetes API Server 配置一个 LoadBalancer。LoadBalancer 负责在控制平面节点之间分发 API server 流量,以确保高可用性。

DCS provider 不会创建此负载均衡器。请在创建集群之前自行预置,并在 DCSCluster.spec.controlPlaneLoadBalancer 中引用其地址。对于 API server 前方没有负载均衡器的单控制平面部署,请参见 单控制平面(无外部 LB)布局

6. 公共镜像仓库配置

请配置公共镜像仓库凭证。这包括:

  • 镜像仓库地址配置
  • 正确的身份验证凭证设置

使用 Web UI

WARNING

Fleet Essentials UI 不支持 ACP 4.3 集群升级

Fleet Essentials UI 工作流尚未适配 ACP 4.3 中引入的 Cluster Version Operator(CVO)机制。请勿使用 Fleet Essentials UI 升级 ACP 4.3 上的 DCS 集群。

两种受支持的替代方式:

通过 Fleet Essentials UI 进行的集群创建和节点池管理不受此限制影响。

版本要求:此工作流需要 Fleet Essentials 和 Alauda Container Platform DCS Infrastructure Provider 1.0.13 或更高版本。如果 provider 版本早于 1.0.13,请使用 YAML manifest。如果使用池管理的持久磁盘,请使用 DCS provider v1.0.16 或更高版本。在 v1.0.16 中,由于 Web UI 不暴露该字段,请通过 YAML 配置 DCSIpHostnamePool.spec.pool[].persistentDisk

如果新集群将依赖池管理的持久磁盘,请先使用 YAML 创建或更新底层 DCSIpHostnamePool,然后再使用 Web UI 完成其余集群工作流。

创建工作流

集群创建遵循一个 5 步向导:

Step 1: Basic Info

Step 2: Control Plane Node Pool

Step 3: Worker Node Pools

Step 4: Networking

Step 5: Review

导航路径:Clusters → Clusters → Create Cluster → Select Huawei DCS

步骤 1:基本信息

字段类型必填描述
Infrastructure Credentialdropdown选择现有的 Cloud Credential
Nametext唯一的集群标识符(小写字母、数字、连字符)
Display Nametext用于便于识别的自定义描述
Distribution Versionreadonly-ACP 版本(与 global 集群一致)
Kubernetes Versionreadonly-由 Distribution Version 决定
Cluster API Addresstext格式:https://<load-balancer-address>:6443

先决条件检查

在创建集群之前,请确保:

  • DCS 平台中已存在 DCS VM Templates,并且 Alauda OS 版本与 Kubernetes 版本匹配
  • 已为 Kubernetes API Server 配置好 LoadBalancer

版本约束:仅可创建平台支持的最新 Kubernetes 版本。

步骤 2:控制平面节点池

控制平面节点池为高可用固定配置 3 个副本。

字段类型必填描述
Machine Templatedropdown按 Type: Control Plane 和兼容的 Kubernetes 版本筛选模板
Replicasreadonly-固定为 3
SSH Authorized Keystext添加多个 SSH 公钥用于节点访问

校验:关联的 IP Pool 必须具有足够的可用 IP 地址(≥ 3)。

步骤 3:worker 节点池

可以添加多个 worker 节点池。每个池具有以下配置:

字段类型必填描述
Pool Nametext此节点池的唯一标识符
Machine Templatedropdown按 Type: Worker Node 和兼容的 Kubernetes 版本筛选模板
Replicasnumber默认值:3
Max Surgenumber默认值:0,必须 ≥ 0。如果节点池将使用池管理的持久磁盘,请将此值保持为 0
Max Unavailablenumber默认值:1,必须 ≥ 0。当 maxSurge = 0 时,maxUnavailable 必须 > 0 且 ≤ Replicas
SSH Authorized Keystext添加多个 SSH 公钥

校验规则

  • 节点池名称在集群内必须唯一
  • IP Pool 必须具有足够的可用 IP 地址(≥ Replicas)
  • maxSurge 和 maxUnavailable 必须满足约束:如果 maxSurge = 0,则 maxUnavailable > 0
  • 如果集群将依赖池管理的持久磁盘,请保持 maxSurge = 0,以便在未来升级时逐个替换节点

提示:将节点池名称以前缀为集群名称的连字符开头(例如 mycluster-worker-1),以避免不同集群之间发生命名冲突。

步骤 4:网络

字段类型必填描述
Pods CIDRCIDRPod 网络地址范围
Services CIDRCIDRService 网络地址范围
Join CIDRCIDRKube-OVN join CIDR 参数

校验:Pods CIDR 和 Services CIDR 不能重叠。

步骤 5:审查

在创建集群之前,请审查所有配置项:

基本信息

  • Name、Display Name、Infrastructure Credential
  • Distribution Version、Kubernetes Version
  • Cluster API Address

控制平面节点池

  • Machine Template,包括 VM Template Name、OS Version、Kubernetes Version
  • CPU、Memory、Replicas、SSH Keys

worker 节点池(列表视图):

  • Pool Name、Machine Template、Replicas
  • Max Surge、Max Unavailable、SSH Keys

如果集群将依赖池管理的持久磁盘,请将 worker 节点池的 Max Surge 保持为 0

网络

  • Pods CIDR、Services CIDR、Join CIDR

单击 Create 开始集群创建过程。


使用 YAML

集群创建工作流

使用 YAML 时,需要在 global 集群中创建 Cluster API 资源,以预置基础设施并引导一个可正常工作的 Kubernetes 集群。

WARNING

重要的命名空间要求

为确保作为业务集群正确集成,所有资源必须部署到 cpaas-system 命名空间。在其他命名空间中部署资源可能会导致集成问题。

WARNING

业务集群命名

业务 cluster-name 不能global。该名称保留给 global 集群,重复使用会导致业务集群的资源在 cpaas-system 中与 global 集群资源发生冲突。global- 前缀保留给 global 集群的 DR 工作流所拥有的资源;请参见 通用先决条件。请勿将 global- 用于业务集群资源,因为故障切换操作可能会将这些资源当作属于 global 集群而进行选择。

按照约定,CAPI Cluster 和 provider 的集群资源(DCSCluster)应完全命名为 <cluster-name>,而非根级的 CAPI 和 provider 资源(KubeadmControlPlaneKubeadmConfigTemplateMachineDeployment、machine templates、IP/hostname pools 等)应以前缀 <cluster-name>- 命名——例如,示例 manifest 使用 <cluster-name>-kcp。这是一种建议,而不是控制器强制的规则,但它可以防止当多个业务集群位于 cpaas-system 中时发生同命名空间冲突,并且在操作过程中能使资源归属更清晰。

配置工作流

请按以下顺序执行,以预置一个可用集群(控制平面 worker 节点):

  1. 配置 KubeadmControlPlane(控制平面规格和 kubeadm bootstrap)。
  2. 配置 DCSCluster(基础设施绑定和负载均衡器引用)。
  3. 创建 Cluster 资源(连接上述两者的顶层 CAPI 对象)。
  4. 配置 worker 资源:KubeadmConfigTemplate(worker bootstrap)、worker DCSMachineTemplate、worker DCSIpHostnamePoolMachineDeployment只有控制平面并不能构成可用集群。 有关四个 worker YAML 资源,请参见 Huawei DCS 上的节点管理

注意:基础设施资源(Secret、控制平面的 DCSIpHostnamePool、控制平面的 DCSMachineTemplate)应单独配置。有关说明,请参见 Huawei DCS 的基础设施资源

如果需要让任何磁盘在滚动替换期间保留,请在对应的 DCSIpHostnamePool.spec.pool[].persistentDisk 条目中声明它。这也包括平台要求的 /var/cpaas 磁盘。provider 会创建新的持久卷作为独立的普通持久卷。当 DCS 环境要求显式 thin-provisioning 设置时,请设置 persistentDisk[].isThin;如果省略该字段,provider 将不发送 isThin,而 DCS 将使用平台默认值。

如果集群需要附加 NIC,请在相应 Machines 创建之前,在 DCSIpHostnamePool.spec.pool[].additionNic[] 中声明。provider 仅在新建 VM 时应用附加 NIC。后续编辑 Pool 时,现有 VM 不会获得热添加的 NIC。

解决占位符值

下面的示例 manifest 使用 <placeholder> 语法表示环境相关的值。其中有些值具有规范的事实来源,应该通过查询获取,而不是手动指定:

占位符事实来源获取方式
<control-plane-kubernetes-version> / <worker-kubernetes-version>位于 cpaas-system 命名空间中的 cpaas.io/dcs-vm-template ConfigMap,每个发行版版本对应一个。kubectl -n cpaas-system get cm -l cpaas.io/dcs-vm-template -o yaml — 读取 data.kubernetesVersion
<dns-image-tag>同一个 ConfigMap,data.corednsTag同上 kubectl get cm 查询。
<etcd-image-tag>同一个 ConfigMap,data.etcdTag同上 kubectl get cm 查询。
<vm-template-name>(在 DCSMachineTemplate.spec.template.spec.vmTemplateName 中)ConfigMap 的 cpaas.io/dcs-vm-template 标签值(必须与 DCS 平台中注册的 VM 模板名称一致)。同上 kubectl get cm 查询 — 读取该标签。
encryption-provider.conf 中的 <base64-encoded-secret>在本地生成;将其视为真实的集群 Secret。head -c 32 /dev/urandom | base64 — 安全存储,并在同一集群的所有控制平面副本间复用。
<ssh-authorized-keys>由操作员提供。每个条目都是一行 OpenSSH 格式的公钥(ssh-ed25519 AAAA… / ssh-rsa AAAA…)。该字段是 ignition 验证器要求的,且不能为空。对于不需要交互式 SSH 的测试或 PoC 集群,可提供任意语法有效的公钥(无需持有对应私钥);在生产环境中,请使用操作团队的签名密钥。n/a — 由操作员生成或提供。
<auth-secret-name>您在 基础设施 → Cloud Credentials 中创建的 Secret。kubectl -n cpaas-system get secret <name>
<cluster-name>由操作员选择;必须满足 DNS-1123 且 不能global(该名称保留给 global 集群)。该名称会复用于 ClusterDCSCluster,以及每个 Machine 上的 cluster.x-k8s.io/cluster-name 标签。KubeadmControlPlane 使用带前缀的形式 <cluster-name>-kcp。有关完整约定,请参见 业务集群命名n/a
<load-balancer-ip-or-domain-name>由操作员提供:客户端用于访问集群 API server 的 IP / 主机名。对于没有外部 LB 的单控制平面集群,这里是唯一 master 节点的 IP(请参见 单控制平面布局)。n/a
<pods-cidr> / <services-cidr> / <kube-ovn-join-cidr>由操作员提供。不得与宿主机网络、global 集群的 CIDR 或任何计划互联的其他 CAPI 集群 CIDR 重叠。留空时会回退到 global 集群随附的 kube-ovn 默认值,这在生产环境中不推荐:显式指定 CIDR 可避免当多个业务集群位于同一个 global 集群上时发生静默冲突。n/a

魔法 Token 占位符

示例 manifest 中有少数值看起来像占位符,但它们实际上是 DCS Provider 在机器加入时替换的字面 token。请保持其原样:

字面 token含义替换者
PROVIDER_ID每个 Machine 的 provider ID(例如 dcs://<dcsmachine-name>)。DCS Provider — 在 kubeadm init / kubeadm join 运行前覆盖生成的 kubelet 配置。
NODE_IP从附加到该 Machine 的 DCSIpHostnamePool 条目分配的节点 IP。DCS Provider — 使用 DCSIpHostnamePool.spec.pool[].ip 的值进行覆盖。

手动替换或给这些 token 加引号会破坏加入流程,并导致节点始终无法向控制平面注册。

网络规划和负载均衡器

在创建控制平面资源之前,请规划网络架构并部署负载均衡器以实现高可用性。

要求

  • 网络分段:为控制平面节点规划 IP 地址范围
  • 附加 NIC:如果节点需要存储、管理或隔离的应用网络,请为每个 IP 槽位规划 DCSIpHostnamePool.spec.pool[].additionNic[] 的值,包括 DVS 和 Port Group 名称
  • 负载均衡器:部署并配置对 API server 的访问
  • API server 地址:准备一个稳定的 VIP 或负载均衡器地址用于 Kubernetes API Server
  • 连通性:确保所有组件之间网络互通

配置 KubeadmControlPlane

KubeadmControlPlane 资源定义了控制平面配置,包括 Kubernetes 版本、节点规格和 bootstrap 设置。

TIP

完整配置参考

下面的示例为便于阅读而截断了较长的配置文件。完整配置(包括默认审计策略、准入控制和文件内容)请参见附录中的 完整 KubeadmControlPlane 配置

kubeadmcontrolplane.yaml
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: KubeadmControlPlane
metadata:
  name: <cluster-name>-kcp
  namespace: cpaas-system
  annotations:
    controlplane.cluster.x-k8s.io/skip-coredns: ""
    controlplane.cluster.x-k8s.io/skip-kube-proxy: ""
spec:
  rolloutStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 0 # Required when the cluster relies on pool-managed persistent disks
  kubeadmConfigSpec:
    users:
    - name: boot
      sshAuthorizedKeys:
      - "<ssh-authorized-keys>"
    format: ignition
    files:
    - path: /etc/kubernetes/admission/psa-config.yaml
      owner: "root:root"
      permissions: "0644"
      content: |
        # ... (Admission Configuration Content) ...
    - path: /etc/kubernetes/patches/kubeletconfiguration0+strategic.json
      owner: "root:root"
      permissions: "0644"
      content: |
        {
          "apiVersion": "kubelet.config.k8s.io/v1beta1",
          "kind": "KubeletConfiguration",
          "_comment": "... (Kubelet Configuration Content) ..."
        }
    # ... (other files) ...
    clusterConfiguration:
      imageRepository: cloud.alauda.io/alauda
      dns:
        imageTag: <dns-image-tag>
      etcd:
        local:
          imageTag: <etcd-image-tag>
      # ... (apiServer, controllerManager, scheduler) ...
    initConfiguration:
      patches:
        directory: /etc/kubernetes/patches
      nodeRegistration:
        kubeletExtraArgs:
          node-labels: "kube-ovn/role=master"
          provider-id: PROVIDER_ID
          volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
          protect-kernel-defaults: "true"
    joinConfiguration:
      patches:
        directory: /etc/kubernetes/patches
      nodeRegistration:
        kubeletExtraArgs:
          node-ip: NODE_IP
          node-labels: "kube-ovn/role=master"
          provider-id: PROVIDER_ID
          volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
          protect-kernel-defaults: "true"
  machineTemplate:
    nodeDrainTimeout: 1m
    nodeDeletionTimeout: 5m
    infrastructureRef:
      apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
      kind: DCSMachineTemplate
      name: <cp-dcs-machine-template-name>
  replicas: 3
  version: <control-plane-kubernetes-version>

参数说明

参数类型描述必填
.spec.kubeadmConfigSpecobjectkubeadm bootstrap provider 启动参数
.spec.machineTemplate.infrastructureRefobjectDCSMachineTemplate 引用
.spec.replicasint控制平面副本数。必须满足 1 ≤ replicas ≤ IP Pool size。开发 / PoC 单控制平面部署请设置为 1(参见 单控制平面布局)。生产环境通常使用 3 以实现 HA。
.spec.versionstringKubernetes 版本(必须与 VM 模板一致 — 参见 解决占位符值

有关组件版本(例如 <dns-image-tag><etcd-image-tag>),请参见 OS Support Matrix

配置 DCSCluster

DCSCluster 是基础设施集群声明,用于引用负载均衡器和 DCS 平台凭证。

dcscluster.yaml
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DCSCluster
metadata:
  name: "<cluster-name>"
  namespace: cpaas-system
spec:
  controlPlaneLoadBalancer:
    host: <load-balancer-ip-or-domain-name>
    port: 6443
    type: external
  credentialSecretRef:
    name: <auth-secret-name>
  controlPlaneEndpoint:
    host: <load-balancer-ip-or-domain-name>
    port: 6443
  networkType: kube-ovn
  site: <site>

参数说明

参数类型描述必填
.spec.controlPlaneLoadBalancerobject控制平面 API server 暴露方式
.spec.controlPlaneLoadBalancer.typestring当前仅支持 "external"
.spec.controlPlaneLoadBalancer.hoststring负载均衡器 IP 或域名
.spec.credentialSecretRef.namestringDCS 身份验证 Secret 名称。该 Secret 定义 DCS Provider 以接口互联用户(默认)还是域用户进行身份验证 — 请参见 Credential User Types
.spec.networkTypestring当前仅支持 "kube-ovn"
.spec.sitestringDCS 平台站点 ID

单控制平面(无外部 LB)布局

对于开发、PoC 或任何控制平面只有 一个 副本(KubeadmControlPlane.spec.replicas: 1)的部署,API server 前并没有真正的负载均衡器。不过,仍有两个字段需要填写值:

  • .spec.controlPlaneLoadBalancer.host.spec.controlPlaneEndpoint.host — 两者都设置为 唯一 master 节点的 IP(也就是在控制平面 DCSIpHostnamePool 中分配给 master 的同一个 IP)。
  • .spec.controlPlaneLoadBalancer.type — 保持为 external(该 type 字段没有其他受支持的值)。

具体如下:

spec:
  controlPlaneLoadBalancer:
    host: 10.226.82.150     # same IP as the master node from the IP pool
    port: 6443
    type: external
  controlPlaneEndpoint:
    host: 10.226.82.150     # same as above
    port: 6443

这种布局没有 HA——一旦单个 master 丢失,集群 API 就会不可达,直到 master 恢复。生产环境请使用 replicas: 3 并配备真实负载均衡器。

配置 Cluster

Cluster 资源用于声明集群,并引用控制平面和基础设施资源。

cluster.yaml
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
  annotations:
    capi.cpaas.io/resource-group-version: infrastructure.cluster.x-k8s.io/v1beta1
    capi.cpaas.io/resource-kind: DCSCluster
    cpaas.io/kube-ovn-join-cidr: <kube-ovn-join-cidr>
  labels:
    cluster-type: DCS
  name: <cluster-name>
  namespace: cpaas-system
spec:
  clusterNetwork:
    pods:
      cidrBlocks:
      - <pods-cidr>
    services:
      cidrBlocks:
      - <services-cidr>
  controlPlaneRef:
    apiVersion: controlplane.cluster.x-k8s.io/v1beta1
    kind: KubeadmControlPlane
    name: <cluster-name>-kcp
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
    kind: DCSCluster
    name: <cluster-name>

参数说明

参数类型描述必填
.spec.clusterNetwork.pods.cidrBlocks[]stringPod CIDR。CAPI schema 中为可选项,但建议显式设置,以便多个 CAPI 集群可以无重叠共存。如果不设置,kube-ovn 会回退到默认值,这可能与同一个 global 上的另一个集群冲突。推荐
.spec.clusterNetwork.services.cidrBlocks[]stringService CIDR。与 Pod CIDR 一样,建议显式设置以避免跨集群冲突。推荐
.spec.controlPlaneRefobject控制平面引用
.spec.infrastructureRefobject基础设施集群引用

Cluster 注解

上面的示例展示了三个注解,但完整的 Cluster 资源还包含一些其他注解。下表列出的是 操作员作者 需要设置的注解(另一些由 ACP 控制器写入,不应预先设置):

注解必填值来源目的
capi.cpaas.io/resource-group-version字面量 infrastructure.cluster.x-k8s.io/v1beta1告诉 CAPI 基础设施绑定应使用哪个 API group。
capi.cpaas.io/resource-kind字面量 DCSCluster告诉 CAPI 基础设施绑定要绑定到哪个 kind。
cpaas.io/kubernetesKubeadmControlPlane.spec.versionMachineDeployment.spec.template.spec.version 相同的值。展示标签,也会被某些升级和清单工具消费。事实来源是 cpaas.io/dcs-vm-template ConfigMap 的 kubernetesVersion
cpaas.io/kube-ovn-join-cidr由操作员选择的 /16 CIDR,不能与 pod / service CIDR 或任何其他集群的 join CIDR 重叠。Kube-OVN 节点间隧道网络。
cpaas.io/kube-ovn-versionglobal 集群所附带的 kube-ovn 发行版本。请从 global CAPI Cluster 上的 cpaas.io/kube-ovn-version 注解读取(kubectl get cluster global -n cpaas-system -o jsonpath='{.metadata.annotations.cpaas\.io/kube-ovn-version}')。同一 global 集群上的每个健康业务集群都具有相同值,因此如果这些集群存在,也可以从任意一个读取。固定业务集群中安装的 kube-ovn 版本。
cpaas.io/registry-addressglobal 集群使用的镜像仓库(通常为 <registry-host>:11443)。请从 global CAPI Cluster 上的 cpaas.io/registry-address 注解读取(kubectl get cluster global -n cpaas-system -o jsonpath='{.metadata.annotations.cpaas\.io/registry-address}')。业务集群从该镜像仓库拉取平台镜像(CoreDNS、kube-proxy、kube-ovn)。
cpaas.io/nodes-mode对于由 DCS Provider 预置的集群,字面量为 self-managed标记该集群的节点生命周期由 CAPI + 此 provider 管理。

ACP 控制器在集群启动后可能会写入额外的只读注解(如 cpaas.io/cpu-cores-numbercpaas.io/memoriescpaas.io/nodes-number 等)——这些值是计算得出的,不应在您提交的 YAML 中预先设置。

部署节点

有关部署 worker 节点的说明,请参见 Huawei DCS 上的节点管理


集群验证

部署完所有集群资源后,请验证集群是否已成功创建并正常运行。

使用控制台

  1. 导航到 ClustersClusters
  2. 在集群列表中找到新创建的集群
  3. 验证集群状态显示为 Running
  4. 检查所有控制平面和 worker 节点是否为 Ready

使用 kubectl

也可以使用 kubectl 命令验证集群:

# Check cluster status
kubectl get cluster -n cpaas-system <cluster-name>

# Verify control plane
kubectl get kubeadmcontrolplane -n cpaas-system <cluster-name>-kcp

# Check machine status
kubectl get machines -n cpaas-system

# Verify cluster deployment
kubectl get clustermodule <cluster-name> -o jsonpath='{.status.base.deployStatus}'

对于使用附加 NIC 的集群,还应验证 provider 是否已将其记录到对应的 DCSMachine 对象中:

kubectl -n cpaas-system get dcsmachine -l cluster.x-k8s.io/cluster-name=<cluster-name> \
  -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.networkConfig.ip}{"\t"}{.status.additionalNic}{"\n"}{end}'

预期结果

成功创建的集群应显示:

  • 集群状态:RunningProvisioned
  • 所有控制平面机器:Running
  • 所有 worker 节点(如果已部署):Running
  • Kubernetes 节点:Ready
  • 集群模块状态:Completed
  • 对于多 NIC 集群,每个创建的 VM 都应在 DCSMachine.status.additionalNic 中具有预期的附加 NIC,且 guest OS 中会显示相应的 ethN 接口。

附录

完整 KubeadmControlPlane 配置

下面是完整的 KubeadmControlPlane 配置,包括所有默认审计策略、准入控制和文件内容。

apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: KubeadmControlPlane
metadata:
  name: <cluster-name>-kcp
  namespace: cpaas-system
  annotations:
    controlplane.cluster.x-k8s.io/skip-coredns: ""
    controlplane.cluster.x-k8s.io/skip-kube-proxy: ""
spec:
  rolloutStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 0 # Required when the cluster relies on pool-managed persistent disks
  kubeadmConfigSpec:
    users:
    - name: boot
      sshAuthorizedKeys:
      - "<ssh-authorized-keys>"
    format: ignition
    files:
    - path: /etc/kubernetes/admission/psa-config.yaml
      owner: "root:root"
      permissions: "0644"
      content: |
        apiVersion: apiserver.config.k8s.io/v1
        kind: AdmissionConfiguration
        plugins:
        - name: PodSecurity
          configuration:
            apiVersion: pod-security.admission.config.k8s.io/v1
            kind: PodSecurityConfiguration
            defaults:
              enforce: "privileged"
              enforce-version: "latest"
              audit: "baseline"
              audit-version: "latest"
              warn: "baseline"
              warn-version: "latest"
            exemptions:
              usernames: []
              runtimeClasses: []
              namespaces:
              - kube-system
              - cpaas-system
    - path: /etc/kubernetes/patches/kubeletconfiguration0+strategic.json
      owner: "root:root"
      permissions: "0644"
      content: |
        {
          "apiVersion": "kubelet.config.k8s.io/v1beta1",
          "kind": "KubeletConfiguration",
          "protectKernelDefaults": true,
          "tlsCertFile": "/etc/kubernetes/pki/kubelet.crt",
          "tlsPrivateKeyFile": "/etc/kubernetes/pki/kubelet.key",
          "streamingConnectionIdleTimeout": "5m",
          "clientCAFile": "/etc/kubernetes/pki/ca.crt"
        }
    - path: /etc/kubernetes/encryption-provider.conf
      owner: "root:root"
      append: false
      permissions: "0644"
      content: |
        apiVersion: apiserver.config.k8s.io/v1
        kind: EncryptionConfiguration
        resources:
        - resources:
          - secrets
          providers:
          - aescbc:
              keys:
              - name: key1
                secret: <base64-encoded-secret>
    - path: /etc/kubernetes/audit/policy.yaml
      owner: "root:root"
      append: false
      permissions: "0644"
      content: |
        apiVersion: audit.k8s.io/v1
        kind: Policy
        omitStages:
        - "RequestReceived"
        rules:
        - level: None
          users:
          - system:kube-controller-manager
          - system:kube-scheduler
          - system:serviceaccount:kube-system:endpoint-controller
          verbs: ["get", "update"]
          namespaces: ["kube-system"]
          resources:
          - group: ""
            resources: ["endpoints"]
        - level: None
          nonResourceURLs:
          - /healthz*
          - /version
          - /swagger*
        - level: None
          resources:
          - group: ""
            resources: ["events"]
        - level: None
          resources:
          - group: "devops.alauda.io"
        - level: None
          verbs: ["get", "list", "watch"]
        - level: None
          resources:
          - group: "coordination.k8s.io"
            resources: ["leases"]
        - level: None
          resources:
          - group: "authorization.k8s.io"
            resources: ["subjectaccessreviews", "selfsubjectaccessreviews"]
          - group: "authentication.k8s.io"
            resources: ["tokenreviews"]
        - level: None
          resources:
          - group: "app.alauda.io"
            resources: ["imagewhitelists"]
          - group: "k8s.io"
            resources: ["namespaceoverviews"]
        - level: Metadata
          resources:
          - group: ""
            resources: ["secrets", "configmaps"]
        - level: Metadata
          resources:
          - group: "operator.connectors.alauda.io"
            resources: ["installmanifests"]
          - group: "operators.katanomi.dev"
            resources: ["katanomis"]
        - level: RequestResponse
          resources:
          - group: ""
          - group: "aiops.alauda.io"
          - group: "apps"
          - group: "app.k8s.io"
          - group: "authentication.istio.io"
          - group: "auth.alauda.io"
          - group: "autoscaling"
          - group: "asm.alauda.io"
          - group: "clusterregistry.k8s.io"
          - group: "crd.alauda.io"
          - group: "infrastructure.alauda.io"
          - group: "monitoring.coreos.com"
          - group: "operators.coreos.com"
          - group: "networking.istio.io"
          - group: "extensions.istio.io"
          - group: "install.istio.io"
          - group: "security.istio.io"
          - group: "telemetry.istio.io"
          - group: "opentelemetry.io"
          - group: "networking.k8s.io"
          - group: "portal.alauda.io"
          - group: "rbac.authorization.k8s.io"
          - group: "storage.k8s.io"
          - group: "tke.cloud.tencent.com"
          - group: "devopsx.alauda.io"
          - group: "core.katanomi.dev"
          - group: "deliveries.katanomi.dev"
          - group: "integrations.katanomi.dev"
          - group: "artifacts.katanomi.dev"
          - group: "builds.katanomi.dev"
          - group: "versioning.katanomi.dev"
          - group: "sources.katanomi.dev"
          - group: "tekton.dev"
          - group: "operator.tekton.dev"
          - group: "eventing.knative.dev"
          - group: "flows.knative.dev"
          - group: "messaging.knative.dev"
          - group: "operator.knative.dev"
          - group: "sources.knative.dev"
          - group: "operator.devops.alauda.io"
          - group: "flagger.app"
          - group: "jaegertracing.io"
          - group: "velero.io"
            resources: ["deletebackuprequests"]
          - group: "connectors.alauda.io"
          - group: "operator.connectors.alauda.io"
            resources: ["connectorscores", "connectorsgits", "connectorsocis"]
        - level: Metadata
    preKubeadmCommands:
    - while ! ip route | grep -q "default via"; do sleep 1; done; echo "NetworkManager started"
    - mkdir -p /run/cluster-api && restorecon -Rv /run/cluster-api
    - if [ -f /etc/disk-setup.sh ]; then bash /etc/disk-setup.sh; fi
    postKubeadmCommands:
    - chmod 600 /var/lib/kubelet/config.yaml
    clusterConfiguration:
      imageRepository: cloud.alauda.io/alauda
      dns:
        imageTag: <dns-image-tag>
      etcd:
        local:
          imageTag: <etcd-image-tag>
      apiServer:
        extraArgs:
          audit-log-format: json
          audit-log-maxage: "30"
          audit-log-maxbackup: "10"
          audit-log-maxsize: "200"
          profiling: "false"
          audit-log-mode: batch
          audit-log-path: /etc/kubernetes/audit/audit.log
          audit-policy-file: /etc/kubernetes/audit/policy.yaml
          tls-cipher-suites: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
          encryption-provider-config: /etc/kubernetes/encryption-provider.conf
          admission-control-config-file: /etc/kubernetes/admission/psa-config.yaml
          tls-min-version: VersionTLS12
          kubelet-certificate-authority: /etc/kubernetes/pki/ca.crt
        extraVolumes:
        - name: vol-dir-0
          hostPath: /etc/kubernetes
          mountPath: /etc/kubernetes
          pathType: Directory
      controllerManager:
        extraArgs:
          bind-address: "::"
          profiling: "false"
          tls-min-version: VersionTLS12
          flex-volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
      scheduler:
        extraArgs:
          bind-address: "::"
          tls-min-version: VersionTLS12
          profiling: "false"
    initConfiguration:
      patches:
        directory: /etc/kubernetes/patches
      nodeRegistration:
        kubeletExtraArgs:
          node-labels: "kube-ovn/role=master"
          provider-id: PROVIDER_ID
          volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
          protect-kernel-defaults: "true"
    joinConfiguration:
      patches:
        directory: /etc/kubernetes/patches
      nodeRegistration:
        kubeletExtraArgs:
          node-ip: NODE_IP
          node-labels: "kube-ovn/role=master"
          provider-id: PROVIDER_ID
          volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/"
          protect-kernel-defaults: "true"
  machineTemplate:
    nodeDrainTimeout: 1m
    nodeDeletionTimeout: 5m
    infrastructureRef:
      apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
      kind: DCSMachineTemplate
      name: <cp-dcs-machine-template-name>
  replicas: 3
  version: <control-plane-kubernetes-version>
TIP

替代方案:引用集中管理的 Secret,而不是内联内容

Alauda Container Platform DCS Infrastructure Provider 插件会在 cpaas-system 命名空间中提供一个名为 dcs-kubernetes-<kubernetes-major-minor>-files 的 Secret(例如,Kubernetes 1.33 对应 dcs-kubernetes-1.33-files)。它包含 psa-config.yamlcontrol-plane-kubelet-patch.jsonaudit-policy.yaml 的规范内容,并会随每次发布一起更新。

当该 Secret 存在时,您可以将三个内联的 files 条目替换为 contentFrom.secret 引用。内联形式和引用 Secret 的形式在功能上等价;使用 Secret 可以使文件内容与已安装的 plugin 版本保持一致,并避免在集群升级时进行手动更新。

files:
- contentFrom:
    secret:
      key: psa-config.yaml
      name: dcs-kubernetes-1.33-files
  owner: "root:root"
  path: /etc/kubernetes/admission/psa-config.yaml
  permissions: "0644"
- contentFrom:
    secret:
      key: control-plane-kubelet-patch.json
      name: dcs-kubernetes-1.33-files
  owner: "root:root"
  path: /etc/kubernetes/patches/kubeletconfiguration0+strategic.json
  permissions: "0644"
- contentFrom:
    secret:
      key: audit-policy.yaml
      name: dcs-kubernetes-1.33-files
  owner: "root:root"
  path: /etc/kubernetes/audit/policy.yaml
  permissions: "0644"
- path: /etc/kubernetes/encryption-provider.conf
  owner: "root:root"
  append: false
  permissions: "0644"
  content: |
    apiVersion: apiserver.config.k8s.io/v1
    kind: EncryptionConfiguration
    resources:
    - resources:
      - secrets
      providers:
      - aescbc:
          keys:
          - name: key1
            secret: <base64-encoded-secret>

encryption-provider.conf 不由该 Secret 提供。您可以保留上面所示的内联形式(并提供自己的 <base64-encoded-secret>),也可以完全省略内联文件,而依赖 DCS VM 模板镜像中已内置的版本——两种方式都有效;当 VM 模板的默认密钥适合您的环境时,后者更简单。

最低插件版本:此 Secret 从 DCS Provider 插件 v1.0.13 开始提供。在更早版本的插件中,该 Secret 不存在;此时请保留内联 content: 形式。在决定使用哪种形式之前,可先检查目标集群上是否存在该 Secret:

# Replace <kubernetes-major-minor> with the value matching this cluster
# (for example, 1.33 for Kubernetes v1.33.x).
K8S_MM=<kubernetes-major-minor>
kubectl -n cpaas-system get secret "dcs-kubernetes-${K8S_MM}-files" >/dev/null 2>&1 \
  && echo "Secret present — contentFrom.secret form is supported" \
  || echo "Secret missing — use inline content form"

后续步骤

创建集群后:

故障排查

如果集群达到 Provisioned 但始终未变为 Ready——例如,由于 CNI 未部署导致 worker 节点一直处于 NotReady——请参见 排查卡在 Provisioned 状态的业务集群