安装 global 集群

本文档介绍如何将 global 集群安装到不可变基础设施上。global 集群是平台控制平面,通过 Cluster API 进行部署。当平台控制平面必须运行在不可变操作系统(例如 Alauda OS)上时,请使用此路径。

何时使用此路径

当以下所有条件都满足时,请选择此安装路径:

  • 希望 global 集群运行在不可变操作系统上。当前支持的镜像是 Alauda OS。
  • 你的基础设施属于本文档支持的提供商之一:Huawei DCS、VMware vSphere、Huawei Cloud Stack 或 裸金属。
  • 你可以运行一个临时的 KIND 主机,并且它可以访问目标 IaaS 平台的网络。

对于 Ubuntu 或 RHEL 等传统操作系统,请改用 标准安装路径

通用前提条件

以下前提条件适用于所有提供商:

  • 一台满足最低硬件和网络要求的 KIND 主机。有关规格建议,请参见 概述
  • 来自 Customer Portal 的 Core Package。
  • Alauda Container Platform Kubeadm Provider 包。
  • 目标平台对应的基础设施提供商包。
  • KIND 主机与目标 IaaS 平台 API 端点之间的网络可达性。
  • global 控制平面和 worker 节点规划 IP 和主机名。有关各提供商使用的资源模型,请参见 基础设施资源
  • global 集群稳定的 Kubernetes API 端点,例如 VIP 或负载均衡器地址。
  • 平台访问地址、registry 地址,以及 Pod 和 Service CIDR 范围。
  • 对于使用 ACP 提供的 Alauda OS 镜像的 x86_64 节点,底层 CPU 必须支持 x86-64-v2 ISA 基线。请参见 操作系统支持矩阵
命名约定(必需)

此规则适用于此安装路径支持的 所有 基础设施提供商——Huawei DCS、Huawei Cloud Stack、VMware vSphere,以及未来新增的任何提供商。你在第 4 步中编写的每个 manifest 都必须遵循该规则。资源命名错误会导致两种不同的故障模式,下文会分别说明;一种会破坏初始部署,另一种仅在灾难恢复时显现。

  • CAPI Cluster 以及提供商的基础设施集群资源(例如 Huawei DCS 的 DCSCluster,Huawei Cloud Stack 的 HCSCluster;每个提供商都有各自对应的资源)必须精确命名为 globalcpaas-installer 会按字面名称查找它们,而 Huawei Cloud Stack 提供商仅在基础设施集群命名为 global 时才会分配全局 ELB 监听端口(registry 和 console 使用 11443,DR etcd 同步使用 2379,Web 访问使用 443)。使用其他名称会静默破坏 registry 拉取、DR etcd 同步和 Web 控制台。
  • 其他所有 CAPI 资源(KubeadmControlPlaneKubeadmConfigTemplateMachineDeployment)以及其他所有提供商基础设施资源(机器模板、IP/主机名池、机器配置池,以及任何其他按提供商划分的资源)必须使用带有 global- 前缀的名称。DR(故障切换)机制使用该前缀来识别属于 global 集群的资源。没有 global- 前缀的 global 集群资源对 DR 不可见,并会导致备用集群的机器在故障切换时被删除——集群会正常部署和运行,但在第一次执行 DR 时会丢失节点。这是硬性要求,不是风格约定。
  • Cluster.spec.controlPlaneRef.name 以及任何其他交叉引用都必须与带前缀的名称完全一致。

兼容性和版本输入

在安装之前,请记录交付包支持的版本集合:

输入目的
Core Package 版本提供安装器、本地 registry 和基础平台负载。
Kubeadm provider chart 版本必须与 global manifest 使用的 Cluster API 控制平面资源匹配。
基础设施 provider chart 版本使用随目标发布版本交付的 VMware vSphere、DCS、HCS 或 裸金属 provider chart 版本。
Alauda OS 镜像或 VM 模板必须包含 K8S_VERSION 所使用的 Kubernetes 版本。
K8S_VERSION使用与目标 Alauda OS 镜像匹配的带 v 前缀的 semver,例如 v<major>.<minor>.<patch>

操作步骤

第 1 步 — 准备通用变量

在 KIND 主机上设置通用变量。

export HOST_IP="<kind-host-ip>"
export LOCAL_REGISTRY_ADDRESS="127.0.0.1:11443"
export BOOTSTRAP_REGISTRY_ADDRESS="172.18.0.1:11443"
export NODE_REGISTRY_ADDRESS="${HOST_IP}:11443"
export CONTROL_PLANE_VIP="<global-control-plane-vip>"
export PLATFORM_HOST="<platform-access-domain-or-vip>"
export REGISTRY_DOMAIN="<platform-registry-domain-or-vip>:11443"
export CLUSTER_CIDR="100.3.0.0/16"
export SERVICE_CIDR="100.4.0.0/16"
export KUBE_OVN_JOIN_CIDR="<kube-ovn-join-cidr>"
export K8S_VERSION="<target-kubernetes-version>"
export INGRESS_CLASS_NAME="global-alb2"
export PROVIDER_SECRET_NAME="global-secret"
# Use v-prefixed semver that matches the target Alauda OS image.

从 KIND 主机推送包时使用 LOCAL_REGISTRY_ADDRESS。在 AppRelease chart repository values 中使用 BOOTSTRAP_REGISTRY_ADDRESS,因为 provider Pod 会从 bootstrap KIND 网络内部读取 chart repository。在 Cluster API registry 注解中使用 NODE_REGISTRY_ADDRESS,因为已部署的 global 节点必须通过其子网可达的地址拉取镜像。

第 2 步 — 引导 KIND 主机

运行 Core Package 提供的 bootstrap 脚本。这会在 KIND 主机上启动一个临时管理集群 minialauda

mkdir -p /root/cpaas-install
tar -xvf <core-package> -C /root/cpaas-install
cd /root/cpaas-install/installer
sh setup.sh
mkdir -p ~/.kube
cp /var/cpaas/data/alauda.kubeconfig ~/.kube/config

bootstrap 脚本会部署一个内嵌 registry、Cluster API 控制平面,以及驱动 global 集群安装的安装器组件。

第 3 步 — 上传并安装 provider 包

将 Kubeadm provider 包和基础设施 provider 包上传到本地 registry。

为什么所有提供商的 cluster.type 都是 Baremetal

下方各标签页中的 AppRelease values 都将 global.cluster.type 设置为 Baremetal。这是 chart 内部的分类器,不是 IaaS 提供商名称。对于 Huawei DCS、VMware vSphere、Huawei Cloud Stack 和 裸金属 global 安装,请始终保持 Baremetal。该值决定平台如何配置节点级组件;它不用于选择基础设施提供商。

Huawei DCS
VMware vSphere
Huawei Cloud Stack
裸金属

设置 provider 包路径和 chart 版本。

export DCS_PROVIDER_PACK="/root/cluster-api-provider-dcs.amd64.<version>.tgz"
export KUBEADM_PROVIDER_PACK="/root/cluster-api-provider-kubeadm.amd64.<version>.tgz"
export DCS_PROVIDER_VERSION="<dcs-provider-chart-version>"
export KUBEADM_PROVIDER_VERSION="<kubeadm-provider-chart-version>"

上传这些包。

/root/cpaas-install/installer/res/amd64/packtool pack push \
  -r "${LOCAL_REGISTRY_ADDRESS}" -c "${DCS_PROVIDER_PACK}"

/root/cpaas-install/installer/res/amd64/packtool pack push \
  -r "${LOCAL_REGISTRY_ADDRESS}" -c "${KUBEADM_PROVIDER_PACK}"

创建并应用 Kubeadm provider 和 DCS provider 的 AppRelease 资源。

mkdir -p /root/yamls
export DCS_PROVIDER_APPRELEASES="/root/yamls/dcs-provider-appreleases.yaml"

cat > "${DCS_PROVIDER_APPRELEASES}" <<EOF
---
apiVersion: operator.alauda.io/v1alpha1
kind: AppRelease
metadata:
  annotations:
    auto-recycle: "true"
    interval-sync: "true"
  name: cluster-api-provider-kubeadm
  namespace: cpaas-system
spec:
  destination:
    cluster: ""
    namespace: ""
  source:
    chartPullSecret: global-registry-auth
    charts:
      - name: ait/chart-cluster-api-provider-kubeadm
        releaseName: cluster-api-provider-kubeadm
        targetRevision: ${KUBEADM_PROVIDER_VERSION}
    repoURL: ${BOOTSTRAP_REGISTRY_ADDRESS}
  timeout: 120
  values:
    global:
      albName: ${INGRESS_CLASS_NAME}
      auth:
        default_admin: admin@cpaas.io
      cluster:
        isGlobal: true
        name: global
        networkType: kube-ovn
        type: Baremetal
      host: ${PLATFORM_HOST}
      ingress:
        ingressClassName: ${INGRESS_CLASS_NAME}
      labelBaseDomain: cpaas.io
      namespace: cpaas-system
      platformUrl: https://${PLATFORM_HOST}
      protectSecretFiles:
        enabled: false
      region: global
      registry:
        address: ${BOOTSTRAP_REGISTRY_ADDRESS}
        imagePullSecrets:
          - global-registry-auth
      replicas: 1
      scheme: https
---
apiVersion: operator.alauda.io/v1alpha1
kind: AppRelease
metadata:
  annotations:
    auto-recycle: "true"
    interval-sync: "true"
  name: cluster-api-provider-dcs
  namespace: cpaas-system
spec:
  destination:
    cluster: ""
    namespace: ""
  source:
    chartPullSecret: global-registry-auth
    charts:
      - name: ait/chart-cluster-api-provider-dcs
        releaseName: cluster-api-provider-dcs
        targetRevision: ${DCS_PROVIDER_VERSION}
    repoURL: ${BOOTSTRAP_REGISTRY_ADDRESS}
  timeout: 120
  values:
    global:
      albName: ${INGRESS_CLASS_NAME}
      auth:
        default_admin: admin@cpaas.io
      cluster:
        isGlobal: true
        name: global
        networkType: kube-ovn
        type: Baremetal
      host: ${PLATFORM_HOST}
      ingress:
        ingressClassName: ${INGRESS_CLASS_NAME}
      labelBaseDomain: cpaas.io
      namespace: cpaas-system
      platformUrl: https://${PLATFORM_HOST}
      protectSecretFiles:
        enabled: false
      region: global
      registry:
        address: ${BOOTSTRAP_REGISTRY_ADDRESS}
        imagePullSecrets:
          - global-registry-auth
      replicas: 1
      scheme: https
EOF

kubectl apply -f "${DCS_PROVIDER_APPRELEASES}"

until kubectl get crd kubeadmcontrolplanes.controlplane.cluster.x-k8s.io --ignore-not-found 2>/dev/null | grep -q kubeadmcontrolplanes.controlplane.cluster.x-k8s.io; do
  sleep 10
done

until kubectl get crd dcsclusters.infrastructure.cluster.x-k8s.io --ignore-not-found 2>/dev/null | grep -q dcsclusters.infrastructure.cluster.x-k8s.io; do
  sleep 10
done

第 4 步 — 配置 provider 专用的 global manifest

global 集群创建一个 provider 专用 manifest。该 manifest 使用与 workload cluster 相同的 provider 资源,但还必须包含平台控制平面所需的 global 专用标签、注解、registry 值、与安装器兼容的 kubeadm 设置以及持久化数据路径。

请使用以下 provider 创建指南作为详细的资源参考:

通用前提条件 中的命名约定应用到你在下方编写的 manifest 中的每个资源。

KubeadmControlPlane.spec.kubeadmConfigSpec.format 设置为目标 provider 接受的值。provider controller 会强制执行此项:

提供商bootstrap userdata 格式
Huawei DCSignition(由 provider 强制;DCS provider 会拒绝任何其他格式,并返回 invalid format, expected ignition, got <other>)。
VMware vSpherecloud-init(provider 默认值;不支持设置为 ignition)。
Huawei Cloud Stackcloud-init(由 provider 强制;HCS provider 会以 ignition format is not supported 拒绝 ignition)。
裸金属cloud-init(裸金属 provider 消费 CAPI bootstrap 数据并渲染 elemental plan)。
Huawei DCS
VMware vSphere
Huawei Cloud Stack
裸金属

在渲染 DCS global manifest 之前,先设置输出路径。

export GLOBAL_DCS_YAML="/root/yamls/new-global.yaml"

DCS global manifest 必须在 cpaas-system 命名空间中包含以下资源:

资源目的
Secrettype: CloudCredential存储 DCS API 访问所需的 authUserauthKeyendpointsite
用于控制平面节点的 DCSIpHostnamePool分配静态 IP、主机名、网络设置以及由池管理的持久磁盘。
用于控制平面节点的 DCSMachineTemplate定义 DCS VM 模板、folder、CPU、内存和模板本地磁盘。
KubeadmControlPlane引导 Kubernetes 控制平面。将 spec.version 设置为 ${K8S_VERSION}
DCSCluster定义 DCS 基础设施集群和控制平面端点。
Cluster将 Cluster API Cluster 连接到 DCSClusterKubeadmControlPlane
用于 worker 的 DCSIpHostnamePoolDCSMachineTemplateKubeadmConfigTemplateMachineDeployment创建 worker 节点。

请使用 在 Huawei DCS 上创建集群Huawei DCS 基础设施资源 中的 DCS 资源字段。对于 global 集群,请保留以下附加要求:

  • Cluster.metadata.nameDCSCluster.metadata.name 设置为 global(基础设施集群与 CAPI Cluster 同名)。其他所有 CAPI 资源和 provider 资源都要加上 global- 前缀;下方 wiring 片段使用 KubeadmControlPlane.metadata.name: global-kcp
  • DCSCluster.spec.credentialSecretRef.name 设置为 ${PROVIDER_SECRET_NAME}。第 7 步会将该 Secret 导入到最终的 global 集群中。
  • 添加 Cluster.metadata.labels.is-global: "true"Cluster.metadata.labels.cluster-type: DCS
  • 添加 Cluster.metadata.annotations["cpaas.io/registry-address"],值为 ${NODE_REGISTRY_ADDRESS}
  • 对 Alauda OS 将 KubeadmControlPlane.spec.kubeadmConfigSpec.format 设置为 ignition
  • 保留 release manifest 中非加密的 kubeadm 文件、kubelet patch、审计策略以及 installer RBAC 条目。
  • 对于普通的非 DR 部署,不要设置 DCSCluster.spec.encryptionProviderConfigRef,也不要将 /etc/kubernetes/encryption-provider.conf 添加到 KubeadmControlPlane.spec.kubeadmConfigSpec.files
  • /var/cpaas 保持为平台状态目录。如果你需要磁盘在滚动替换后继续保留,请在 DCSIpHostnamePool.spec.pool[].persistentDisk 中声明;不要依赖 DCSMachineTemplate 模板磁盘作为保留状态。
  • 对 DCS 本地存储使用具体的 datastoreName 值,除非你已经验证所选 datastore cluster 可以将卷放置到能够运行目标 VM 的主机上。
片段范围

下方 YAML 是一个差异片段,不是可以直接应用的完整 manifest。请将这些 global 专用变更合并到你根据 DCS create-cluster 参考准备的 manifest 中,然后再应用完整 manifest 文件。

下方片段展示了 global 专用的 Cluster API wiring。请使用上面的 DCS create-cluster 参考来填写 provider 资源字段。

apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
  name: global
  namespace: cpaas-system
  labels:
    cluster-type: DCS
    is-global: "true"
  annotations:
    capi.cpaas.io/resource-group-version: infrastructure.cluster.x-k8s.io/v1beta1
    capi.cpaas.io/resource-kind: DCSCluster
    cpaas.io/registry-address: "${NODE_REGISTRY_ADDRESS}"
spec:
  clusterNetwork:
    pods:
      cidrBlocks:
        - ${CLUSTER_CIDR}
    services:
      cidrBlocks:
        - ${SERVICE_CIDR}
  controlPlaneRef:
    apiVersion: controlplane.cluster.x-k8s.io/v1beta1
    kind: KubeadmControlPlane
    name: global-kcp
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
    kind: DCSCluster
    name: global
---
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: KubeadmControlPlane
metadata:
  name: global-kcp
  namespace: cpaas-system
  annotations:
    controlplane.cluster.x-k8s.io/skip-kube-proxy: ""
spec:
  replicas: 3
  version: ${K8S_VERSION}
  rolloutStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 0
  machineTemplate:
    nodeDrainTimeout: 1m
    nodeDeletionTimeout: 5m
    infrastructureRef:
      apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
      kind: DCSMachineTemplate
      name: global-master-template
  kubeadmConfigSpec:
    format: ignition
    clusterConfiguration:
      etcd:
        local:
          serverCertSANs:
            - "${CONTROL_PLANE_VIP}"
            - "${PLATFORM_HOST}"

第 5 步 — 应用 global manifest

将 provider 专用 manifest 应用到 minialauda

Huawei DCS
VMware vSphere
Huawei Cloud Stack
裸金属
kubectl apply -f "${GLOBAL_DCS_YAML}"

第 6 步 — 等待控制平面

等待 Cluster API provider 部署机器并启动 Kubernetes 控制平面。

kubectl get clusters.cluster.x-k8s.io -n cpaas-system
kubectl get kubeadmcontrolplane -n cpaas-system
kubectl get machines -n cpaas-system

KubeadmControlPlane 报告 Ready: TrueCluster 报告 Phase: Provisioned 时,控制平面即准备就绪。

第 7 步 — 导入 provider 资源

在触发安装器之前,对于需要额外资源导入的 provider,请先在 cpaas-system 命名空间中创建 dcs-import-extra-resources ConfigMap。尽管 provider 不是 Huawei DCS,这个 ConfigMap 名称仍保留 dcs 前缀,以兼容历史安装器。

Huawei DCS、VMware vSphere、Huawei Cloud Stack 和 裸金属 在正常安装和灾难恢复 global 安装中都需要这个 ConfigMap。对于 Huawei DCS,provider 资源会通过内置流程迁移,但 DCSCluster.spec.credentialSecretRef.name 引用的 Secret 必须显式导入。

Huawei DCS
VMware vSphere
Huawei Cloud Stack
裸金属

在触发安装器之前,创建并应用 DCS 导入 ConfigMap。请包含 DCSCluster.spec.credentialSecretRef.name 引用的 Secret。DCS provider 资源会通过内置流程迁移,但凭证 Secret 必须存在于最终的 global 集群中,这样 DCS provider 才能在 handoff 后继续调用 DCS API。

mkdir -p /root/yamls
cat > /root/yamls/dcs-import-extra-resources.yaml <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: dcs-import-extra-resources
  namespace: cpaas-system
data:
  resources.yaml: |
    resources:
    - resource: "secrets"
      names: ["${PROVIDER_SECRET_NAME}"]
      method: kubectl
EOF

kubectl apply -f /root/yamls/dcs-import-extra-resources.yaml

第 8 步 — 触发平台安装

将平台安装请求提交给内嵌安装器 REST API。安装器会将 Cluster API 资源导入新的 global 集群,部署基础 operator,并安装所选插件。

export INSTALLER_IP=$(kubectl get pods -n cpaas-system -l service_name=cpaas-installer \
  -o jsonpath='{.items[0].status.podIP}')
网络范围

INSTALLER_IPminialauda 中内嵌安装器的 Pod IP。该端点仅在安装期间使用。

在当前 KIND 主机上创建 provider 专用的安装器配置 JSON 文件,然后将其提交给安装器端点。此安装路径中的所有 provider 都使用相同的端点路径,但请求体不同。

字段Huawei DCSVMware vSphereHuawei Cloud Stack裸金属
端点路径/cpaas-installer/api/config/dcs/cpaas-installer/api/config/dcs/cpaas-installer/api/config/dcs/cpaas-installer/api/config/dcs
console.host本地 global HA VIP 列表空列表 []空列表 []本地 global 控制平面 VIP 列表
console.globalHost平台访问地址平台访问地址平台访问地址平台访问地址
cluster.clusterCIDRcluster.serviceCIDR必填不设置;cluster CIDR 在 VMware vSphere Cluster manifest 中声明不设置必填
cluster.features.ha必填,指向本地 HA VIP,且 isThirdParty: true不设置;控制平面端点在 VSphereCluster.spec.controlPlaneEndpoint.host 中声明不设置;HCS ELB 在 HCSCluster 中声明必填,指向裸金属控制平面 VIP,且 isThirdParty: true
hostIP当前 KIND 主机 IP当前 KIND 主机 IP当前 KIND 主机 IP当前 KIND 主机 IP
Huawei DCS
VMware vSphere
Huawei Cloud Stack
裸金属

DCS 安装器请求包含外部 HA VIP,因为 DCS 使用第三方控制平面 VIP。

mkdir -p /root/yamls
export INSTALLER_CONFIG_JSON="/root/yamls/installer-config-dcs.json"

cat > "${INSTALLER_CONFIG_JSON}" <<EOF
{
  "basic": {
    "username": "admin@cpaas.io",
    "password": "<base64-platform-admin-password>"
  },
  "registry": {
    "domain": "${REGISTRY_DOMAIN}",
    "username": "<registry-username>",
    "password": "<base64-registry-password>"
  },
  "console": {
    "host": [
      "${CONTROL_PLANE_VIP}"
    ],
    "globalHost": "${PLATFORM_HOST}",
    "httpPort": 80,
    "httpsPort": 443,
    "cert": {
      "selfSigned": {}
    }
  },
  "cluster": {
    "clusterCIDR": "${CLUSTER_CIDR}",
    "serviceCIDR": "${SERVICE_CIDR}",
    "features": {
      "ha": {
        "vip": "${CONTROL_PLANE_VIP}",
        "vport": 6443,
        "isThirdParty": true
      }
    }
  },
  "product": [
    "base",
    "acp"
  ],
  "deployMode": "normal",
  "hostIP": "${HOST_IP}"
}
EOF

curl -k -X POST "http://${INSTALLER_IP}:8080/cpaas-installer/api/config/dcs" \
  -H 'Content-Type: application/json' \
  -d @"${INSTALLER_CONFIG_JSON}"

console.hostcluster.features.ha.vip 设置为本地 global HA VIP。不要在 console.host 中使用平台域;请在 console.globalHost 中使用平台访问地址。

第三方控制台证书

示例使用的是自签名控制台证书。如果环境要求使用第三方证书,请在提交安装器请求之前,将 console.cert 替换为包含 base64 全量证书链、私钥以及可选 PKCS#12 值的 thirdParty 块。

DR 证书要求

对于主/备用 裸金属 global DR 部署,不要让两侧分别生成互不相关的自签名证书。请使用双方都信任的 thirdParty 证书链。证书 SAN 列表必须覆盖 ${PLATFORM_HOST}、主控制平面 VIP、备用控制平面 VIP,以及任何必需的平台 ingress 服务名称。否则,在 DNS 切换到备用集群后,现有 system-agent 可能会因 TLS 验证失败而报错。

第 9 步 — 监控安装

安装器接受请求后,安装会经历几个可从 KIND 主机观察到的阶段。典型的不可变 OS global 集群需要 30–60 分钟;总耗时取决于 IaaS 部署速度、镜像拉取时间以及所选插件数量。

你将观察到的阶段

阶段正在发生什么首先观察的位置
Bootstrapbootstrap KIND、内嵌 registry 和 Cluster API provider 正在 KIND 主机上运行。该步骤在第 2 步和第 3 步中已完成。KIND 主机终端;kubectl get pods -n cpaas-system
基础设施部署Cluster API provider 正在目标 IaaS 平台上使用 Alauda OS 模板创建 VM。kubectl get machines -n cpaas-system
控制平面引导KubeadmControlPlane 引导第一个控制平面节点,etcd 启动,其他控制平面节点加入集群。kubectl get kubeadmcontrolplane -n cpaas-system
网络和核心附加组件CAPI provider 正在新集群上协调 Kube-OVN、CoreDNS 和 kube-proxy。kubectl --kubeconfig <global-kubeconfig> get pods -n kube-system
平台安装安装器将 Cluster API 资源导入新的 global 集群,部署基础 operator,并安装所选插件。安装器进度 API;安装器日志
完成安装器将请求标记为 Success,并将最终集群状态写入 ClusterModule/global安装器进度 API;kubectl --kubeconfig <global-kubeconfig> get clustermodule global

安装期间的信号

请同时观察安装器进度 API 和安装器日志。如果其中一个看起来卡住,请直接在 bootstrap KIND 主机上检查底层 Cluster API 资源。

# Installer progress and live log
curl "http://${INSTALLER_IP}:8080/cpaas-installer/api/progress"
tail -f /var/cpaas/data/installer.log

# Cluster API resources on the bootstrap KIND host
kubectl get clusters.cluster.x-k8s.io -A
kubectl get kubeadmcontrolplane -A
kubectl get machines -A

安装器日志会记录每一次阶段切换。瞬时错误会在短时间间隔后重试;持续性错误会继续显示在日志中,并在进度 API 中体现为停滞阶段。

在安装器报告成功后,检查 global 集群。

kubectl --kubeconfig <global-kubeconfig> get nodes
kubectl --kubeconfig <global-kubeconfig> get pods -n cpaas-system
kubectl --kubeconfig <global-kubeconfig> get clustermodule global

常见卡顿及排查位置

症状首先查看的位置你要找的内容
Machines 一直处于 Pending 或根本未出现kubectl describe machine -n cpaas-system <machine>机器上 BootstrapInfrastructure conditions 中的 provider 专用失败原因。IaaS 配额、网络和凭证问题通常会在这里体现。
KubeadmControlPlane 未达到 Ready使用新集群 kubeconfig 执行 kubectl get nodes,以及 kubectl describe kubeadmcontrolplane -n cpaas-system第一个控制平面节点上的 etcd 健康状况,以及其余节点的加入进度。
kube-system 中的 Pod 一直 Pending 或拉取镜像失败kubectl --kubeconfig <global-kubeconfig> describe pod -n kube-system <pod>镜像拉取错误通常意味着节点可达的 registry 地址无法从新集群子网访问。
安装器进度 API 显示阶段停滞/var/cpaas/data/installer.log最近的阶段行和最近的错误消息。重试中的错误会在短时间间隔内重复;持续性错误不会推进。
ClusterModule/global 未进入健康阶段kubectl --kubeconfig <global-kubeconfig> describe clustermodule globalStatus.conditions 会说明是哪一个模块阻止了集群完成。

这里未列出的其他问题通常指向环境特定原因。请收集安装器日志、进度 API 响应以及相关的 kubectl describe 输出,然后上报。

可选灾难恢复部署

当你为灾难恢复部署主/备用 global 集群时,请使用本节内容。在为每个 global 集群应用 provider 专用 manifest 之前,先完成这些附加项。

开始之前,请完成 双向 DR 网络要求。在两个集群 VIP 都具有所需负载均衡监听器,并且集群间网络规则允许双向所需流量之前,不要启动任一安装。正常运行时使用的方向是备用到主集群,但在故障切换后方向会反转。

主集群和备用集群必须使用相同的 encryption provider 配置。对于 裸金属,主集群和备用集群还必须使用相同的 Kubernetes ServiceAccount signing key,这样主集群上创建的固定 baremetal-system-agent token 才能在故障切换后被备用 API server 接受。对于 DCS 和 裸金属,provider 专用 cluster 资源会引用一个包含 encryption-provider.conf 的 Secret;对于 HCS,普通的非 DR 部署不会将 /etc/kubernetes/encryption-provider.conf 添加到 KubeadmControlPlane.spec.kubeadmConfigSpec.files。VMware vSphere 则保留 release manifest 中的 /etc/kubernetes/encryption-provider.conf 文件条目。

准备共享 DR 变量

在主安装环境和备用安装环境上设置相同的加密密钥值。

export ENCRYPTION_PROVIDER_CONF="/root/yamls/encryption-provider.conf"
export ENCRYPTION_PROVIDER_SECRET_B64="<base64-shared-etcd-encryption-key>"
export PRIMARY_CLUSTER_VIP="<primary-ha-vip>"
export STANDBY_CLUSTER_VIP="<standby-ha-vip>"
export BAREMETAL_ENCRYPTION_PROVIDER_SECRET="global-encryption-provider-config"
export ETCD_SYNC_VERSION="<global-etcd-sync-version>"
export ETCD_SYNC_MODULEINFO="/root/yamls/global-etcd-sync-moduleinfo.json"
export SERVICE_ACCOUNT_ISSUER="https://kubernetes.default.svc.cluster.local"

在两个安装环境上创建 encryption provider 配置文件。

mkdir -p "$(dirname "${ENCRYPTION_PROVIDER_CONF}")"
cat > "${ENCRYPTION_PROVIDER_CONF}" <<EOF_CONF
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
  - secrets
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: ${ENCRYPTION_PROVIDER_SECRET_B64}
EOF_CONF

准备共享 ServiceAccount signing key

对于 裸金属 DR,只生成一次 ServiceAccount signing key,并在主集群和备用集群的 KubeadmControlPlane manifest 中使用相同的文件。

mkdir -p /root/global-dr-sa
openssl genrsa -out /root/global-dr-sa/sa.key 2048
openssl rsa -in /root/global-dr-sa/sa.key -pubout -out /root/global-dr-sa/sa.pub
chmod 0600 /root/global-dr-sa/sa.key
chmod 0644 /root/global-dr-sa/sa.pub

kubectl -n cpaas-system create secret generic global-sa-signing-key \
  --from-file=sa.key=/root/global-dr-sa/sa.key \
  --from-file=sa.pub=/root/global-dr-sa/sa.pub \
  --dry-run=client -o yaml | kubectl apply -f -

将以下条目添加到主集群和备用集群的 KubeadmControlPlane.spec.kubeadmConfigSpec 中。文件内容以及 issuer/audience 值在两侧必须完全一致。

files:
  - path: /etc/kubernetes/pki/sa.key
    owner: root:root
    permissions: "0600"
    contentFrom:
      secret:
        name: global-sa-signing-key
        key: sa.key
  - path: /etc/kubernetes/pki/sa.pub
    owner: root:root
    permissions: "0644"
    contentFrom:
      secret:
        name: global-sa-signing-key
        key: sa.pub
clusterConfiguration:
  apiServer:
    extraArgs:
      service-account-key-file: /etc/kubernetes/pki/sa.pub
      service-account-signing-key-file: /etc/kubernetes/pki/sa.key
      service-account-issuer: https://kubernetes.default.svc.cluster.local
      api-audiences: https://kubernetes.default.svc.cluster.local
  controllerManager:
    extraArgs:
      service-account-private-key-file: /etc/kubernetes/pki/sa.key

集群安装完成后,请在主集群和备用集群各自的一个控制平面节点上验证这些文件和 kubeadm 静态 Pod 参数。

sha256sum /etc/kubernetes/pki/sa.key /etc/kubernetes/pki/sa.pub
grep -E 'service-account-issuer|api-audiences|service-account-key-file|service-account-signing-key-file' \
  /etc/kubernetes/manifests/kube-apiserver.yaml
grep -E 'service-account-private-key-file' \
  /etc/kubernetes/manifests/kube-controller-manager.yaml

将 DR 证书 SAN 添加到 KubeadmControlPlane

在第 4 步生成的 manifest 中,将主集群和备用集群的控制平面 VIP、平台访问地址,以及 etcd.kube-system 一并包含到 KubeadmControlPlane.spec.kubeadmConfigSpec.clusterConfiguration.etcd.local.serverCertSANs 中。主集群和备用集群的安装环境必须使用相同的 SAN 列表。

serverCertSANs:
  - "${PRIMARY_CLUSTER_VIP}"
  - "${STANDBY_CLUSTER_VIP}"
  - "${PLATFORM_HOST}"
  - "etcd.kube-system"

添加 provider 专用 DR 字段

Huawei DCS
VMware vSphere
Huawei Cloud Stack
裸金属

minialauda 中创建 encryption provider Secret。

kubectl create secret generic encryption-provider-config \
  --from-file=encryption-provider.conf="${ENCRYPTION_PROVIDER_CONF}" \
  -n cpaas-system \
  --dry-run=client -o yaml | kubectl apply -f -

将该 Secret 引用添加到 DCSCluster.spec 中。

encryptionProviderConfigRef:
  name: encryption-provider-config

DCS 使用 DCSCluster.spec.encryptionProviderConfigRef 交付灾难恢复 encryption provider 配置。对于 DCS DR 路径,不要将 /etc/kubernetes/encryption-provider.conf 添加到 KubeadmControlPlane.spec.kubeadmConfigSpec.files

在两个安装环境上都创建第 7 步中的 DCS dcs-import-extra-resources ConfigMap。将 PROVIDER_SECRET_NAME 设置为与 DCSCluster.spec.credentialSecretRef.name 相同的 Secret 名称。

安装主集群和备用集群

对主 global 集群和备用 global 集群都执行第 1 步到第 9 步。

对于 裸金属 DR,请使用两个独立的 bootstrap KIND 主机:一个用于主集群安装,一个用于备用集群安装。不要为两侧复用同一个 bootstrap KIND 集群。bootstrap 环境包含安装器状态、AppRelease 对象、registry Secret、MachineRegistrationSeedImage 以及 handoff 状态;共享这些内容可能会污染两个 global 安装,并可能使 handoff 或清理操作影响错误的一侧。

对两侧使用 provider 专用安装器配置差异:

提供商主集群安装备用集群安装
Huawei DCSconsole.hostcluster.features.ha.vip 设置为主 HA VIP。创建第 7 步中的 DCS dcs-import-extra-resources ConfigMap,并保持 PROVIDER_SECRET_NAMEDCSCluster.spec.credentialSecretRef.name 一致。console.hostcluster.features.ha.vip 设置为备用 HA VIP。创建第 7 步中的 DCS dcs-import-extra-resources ConfigMap,并保持 PROVIDER_SECRET_NAMEDCSCluster.spec.credentialSecretRef.name 一致。
VMware vSphereVSphereCluster.spec.controlPlaneEndpoint.host 设置为主 manifest 使用的主 HA VIP。创建第 7 步中的 VMware vSphere dcs-import-extra-resources ConfigMap,并保持 global-vsphere-credentialsVSphereCluster.spec.identityRef.name 一致。VSphereCluster.spec.controlPlaneEndpoint.host 设置为备用 manifest 使用的备用 HA VIP。创建第 7 步中的 VMware vSphere dcs-import-extra-resources ConfigMap,并保持 global-vsphere-credentialsVSphereCluster.spec.identityRef.name 一致。
Huawei Cloud Stack保持 console.host: [];主 VIP 由 HCS ELB 管理。创建第 7 步中的 HCS dcs-import-extra-resources ConfigMap,并保持 PROVIDER_SECRET_NAMEHCSCluster.spec.identityRef.name 一致。保持 console.host: [];备用 VIP 由 HCS ELB 管理。创建第 7 步中的 HCS dcs-import-extra-resources ConfigMap,并保持 PROVIDER_SECRET_NAMEHCSCluster.spec.identityRef.name 一致。
裸金属console.hostcluster.features.ha.vipBaremetalCluster.spec.controlPlaneLoadBalancer.hosthandoffHook.controlPlaneVIP 设置为主控制平面 VIP。创建第 7 步中的 裸金属 dcs-import-extra-resources ConfigMap。console.hostcluster.features.ha.vipBaremetalCluster.spec.controlPlaneLoadBalancer.hosthandoffHook.controlPlaneVIP 设置为备用控制平面 VIP。创建第 7 步中的 裸金属 dcs-import-extra-resources ConfigMap。

对于主集群,请确保平台域解析到主 HA VIP。在第 8 步中,将 hostIP 设置为主 KIND 节点 IP。对于 DCS,将 console.hostcluster.features.ha.vip 设置为主 HA VIP。对于 VMware vSphere,将主 manifest 中的控制平面端点设置为主 HA VIP。对于 HCS,由于 VIP 由 HCS ELB 管理,保持 console.host: []。对于 裸金属,将 manifest VIP 和 installer VIP 字段都设置为主控制平面 VIP。

在主集群安装成功后,按照 DR 流程要求将平台域切换到备用 HA VIP。然后安装备用集群。必须在备用集群安装前完成这个 DNS 切换,因为若干平台资源是使用平台域渲染的,而在备用安装器运行期间它们必须解析到备用入口。在备用 KIND 主机上的第 8 步中,将 hostIP 设置为备用 KIND 节点 IP。对于 DCS,将 console.hostcluster.features.ha.vip 设置为备用 HA VIP。对于 VMware vSphere,将备用 manifest 中的控制平面端点设置为备用 HA VIP。对于 HCS,保持 console.host: []。对于 裸金属,将 manifest VIP 和 installer VIP 字段都设置为备用控制平面 VIP,并在两侧都将 REGISTRY_DOMAIN 保持为 ${PLATFORM_HOST}:11443。从备用 KIND 主机上的 cpaas-installer Pod 获取 INSTALLER_IP;不要复用主 KIND 主机上的值。

在两个集群都安装完成后,在主控制平面节点上获取主 k8sadmin token。 etcd Synchronizer 仅安装在备用集群上,并且其 active_cluster_* 值指向主集群。请将该值以原始 base64 Secret 形式保留给 active_cluster_token

export PRIMARY_CLUSTER_TOKEN_B64="$(sudo kubectl get secret -n cpaas-system k8sadmin -o jsonpath='{.data.token}')"

在备用控制平面节点上获取备用 k8sadmin token。使用此解码后的 bearer token 调用备用集群的 ModuleInfo API。

export STANDBY_CLUSTER_BEARER_TOKEN="$(sudo kubectl get secret -n cpaas-system k8sadmin -o jsonpath='{.data.token}' | base64 -d)"

如果你是从其他主机创建 global-etcd-sync ModuleInfo payload,请安全地将备用控制平面节点上的解码值传输过去并在那边导出。

export STANDBY_CLUSTER_BEARER_TOKEN="<decoded-standby-token>"

为备用集群创建 global-etcd-sync ModuleInfo payload。active_cluster_vipactive_cluster_token 的值必须指向主集群。

cat > "${ETCD_SYNC_MODULEINFO}" <<EOF
{
  "kind": "ModuleInfo",
  "apiVersion": "cluster.alauda.io/v1alpha1",
  "metadata": {
    "name": "global-etcd-sync",
    "labels": {
      "cpaas.io/cluster-name": "global",
      "cpaas.io/module-name": "etcd-sync",
      "cpaas.io/module-type": "plugin"
    }
  },
  "spec": {
    "version": "${ETCD_SYNC_VERSION}",
    "config": {
      "monitor_check_interval": 1,
      "detail": false,
      "active_cluster_vip": "${PRIMARY_CLUSTER_VIP}",
      "active_cluster_token": "${PRIMARY_CLUSTER_TOKEN_B64}"
    }
  }
}
EOF

通过提交 global-etcd-sync ModuleInfo payload,在备用集群上安装 etcd Synchronizer

curl -sk -X POST "https://${STANDBY_CLUSTER_VIP}/apis/cluster.alauda.io/v1alpha1/moduleinfoes" \
  -H "Authorization: Bearer ${STANDBY_CLUSTER_BEARER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d @"${ETCD_SYNC_MODULEINFO}"

重启必须重新加载 DR 和端点配置的 Pod。在主控制平面节点和备用控制平面节点上运行相同命令。

sudo kubectl delete po -n cpaas-system -l 'service_name in (alertmanager,vmselect,vminsert)'
sudo kubectl delete po -n cpaas-system -l service_name=cpaas-elasticsearch
sudo kubectl delete po -n cpaas-system -l service_name=cluster-transformer

关于安装后的 DR 生命周期,请参见 global 集群灾难恢复

验证

安装器报告完成后,请验证 global 集群是否健康。

kubectl --kubeconfig <global-kubeconfig> get nodes
kubectl --kubeconfig <global-kubeconfig> get clusters.platform.tkestack.io global \
  -o jsonpath='{.status.phase}'
kubectl --kubeconfig <global-kubeconfig> get pods -n cpaas-system
kubectl --kubeconfig <global-kubeconfig> get clustermodule global

当满足以下所有条件时,说明安装成功:

  • 安装器进度 API 报告 status: Successtype: Complete
  • 所有 global 集群节点都处于 Ready
  • cpaas-system 中的关键 Pod 处于 RunningCompleted
  • ClusterModule/global 报告基础模块健康。

下一步