安装 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;每个提供商都有各自对应的资源)必须精确命名为 global。cpaas-installer 会按字面名称查找它们,而 Huawei Cloud Stack 提供商仅在基础设施集群命名为 global 时才会分配全局 ELB 监听端口(registry 和 console 使用 11443,DR etcd 同步使用 2379,Web 访问使用 443)。使用其他名称会静默破坏 registry 拉取、DR etcd 同步和 Web 控制台。
- 其他所有 CAPI 资源(
KubeadmControlPlane、KubeadmConfigTemplate、MachineDeployment)以及其他所有提供商基础设施资源(机器模板、IP/主机名池、机器配置池,以及任何其他按提供商划分的资源)必须使用带有 global- 前缀的名称。DR(故障切换)机制使用该前缀来识别属于 global 集群的资源。没有 global- 前缀的 global 集群资源对 DR 不可见,并会导致备用集群的机器在故障切换时被删除——集群会正常部署和运行,但在第一次执行 DR 时会丢失节点。这是硬性要求,不是风格约定。
Cluster.spec.controlPlaneRef.name 以及任何其他交叉引用都必须与带前缀的名称完全一致。
兼容性和版本输入
在安装之前,请记录交付包支持的版本集合:
操作步骤
第 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。该值决定平台如何配置节点级组件;它不用于选择基础设施提供商。
设置 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
设置 provider 包路径和 chart 版本。
export VSPHERE_PROVIDER_PACK="/root/cluster-api-provider-vsphere.amd64.<version>.tgz"
export KUBEADM_PROVIDER_PACK="/root/cluster-api-provider-kubeadm.amd64.<version>.tgz"
export VSPHERE_PROVIDER_VERSION="<vsphere-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 "${VSPHERE_PROVIDER_PACK}"
/root/cpaas-install/installer/res/amd64/packtool pack push \
-r "${LOCAL_REGISTRY_ADDRESS}" -c "${KUBEADM_PROVIDER_PACK}"
创建并应用 Kubeadm provider 和 VMware vSphere provider 的 AppRelease 资源。
mkdir -p /root/yamls
export VSPHERE_PROVIDER_APPRELEASES="/root/yamls/vsphere-provider-appreleases.yaml"
cat > "${VSPHERE_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-vsphere
namespace: cpaas-system
spec:
destination:
cluster: ""
namespace: ""
source:
chartPullSecret: global-registry-auth
charts:
- name: ait/chart-cluster-api-provider-vsphere
releaseName: cluster-api-provider-vsphere
targetRevision: ${VSPHERE_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 "${VSPHERE_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 vsphereclusters.infrastructure.cluster.x-k8s.io --ignore-not-found 2>/dev/null | grep -q vsphereclusters.infrastructure.cluster.x-k8s.io; do
sleep 10
done
设置 provider 包路径和 chart 版本。
export HCS_PROVIDER_PACK="/root/cluster-api-provider-hcs.amd64.<version>.tgz"
export KUBEADM_PROVIDER_PACK="/root/cluster-api-provider-kubeadm.amd64.<version>.tgz"
export HCS_PROVIDER_VERSION="<hcs-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 "${HCS_PROVIDER_PACK}"
/root/cpaas-install/installer/res/amd64/packtool pack push \
-r "${LOCAL_REGISTRY_ADDRESS}" -c "${KUBEADM_PROVIDER_PACK}"
创建并应用 Kubeadm provider 和 HCS provider 的 AppRelease 资源。
mkdir -p /root/yamls
export HCS_PROVIDER_APPRELEASES="/root/yamls/hcs-provider-appreleases.yaml"
cat > "${HCS_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-hcs
namespace: cpaas-system
spec:
destination:
cluster: ""
namespace: ""
source:
chartPullSecret: global-registry-auth
charts:
- name: ait/chart-cluster-api-provider-hcs
releaseName: cluster-api-provider-hcs
targetRevision: ${HCS_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 "${HCS_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 hcsclusters.infrastructure.cluster.x-k8s.io --ignore-not-found 2>/dev/null | grep -q hcsclusters.infrastructure.cluster.x-k8s.io; do
sleep 10
done
设置 provider 包路径和 chart 版本。
export BAREMETAL_PROVIDER_PACK="/root/cluster-api-provider-baremetal.amd64.<version>.tgz"
export KUBEADM_PROVIDER_PACK="/root/cluster-api-provider-kubeadm.amd64.<version>.tgz"
export BAREMETAL_PROVIDER_VERSION="<baremetal-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 "${BAREMETAL_PROVIDER_PACK}"
/root/cpaas-install/installer/res/amd64/packtool pack push \
-r "${LOCAL_REGISTRY_ADDRESS}" -c "${KUBEADM_PROVIDER_PACK}"
创建并应用 Kubeadm provider 和 裸金属 provider 的 AppRelease 资源。
裸金属 bootstrap 端点
在 bootstrap 期间,global 集群尚未将控制权交给最终 VIP。请在 bootstrap KIND 主机上保留裸金属注册路径:global.platformUrl 指向 bootstrap 主机,elemental.server.url 指向 https://<kind-host-ip>:12443。在此阶段,不要在 global 机器使用的 MachineRegistration 上设置 baremetal.cluster.io/system-agent-server-url。handoff job 会在平台安装完成后,将 global 机器切换到 https://<CONTROL_PLANE_VIP>/kubernetes/global。
在安装 裸金属 provider 之前,先准备 global-alb2 使用的 bootstrap HTTPS 证书。elemental-operator 会挂载来自 cpaas-system/dex.tls 的 CA,而当 elemental.tls.agentTLSMode 为 strict 时,elemental-system-agent 会使用该 CA。Secret 必须包含 tls.crt、tls.key,以及你在 AppRelease 中配置的 CA bundle key,下面示例为 ca.crt。服务证书必须包含 ${HOST_IP} 作为 IP SAN,因为 bootstrap 端点是 https://${HOST_IP}:12443。
如果 bootstrap KIND 集群中可用 cert-manager,请使用 bootstrap 本地 CA 创建或刷新 dex.tls:
kubectl get crd certificates.cert-manager.io issuers.cert-manager.io
kubectl -n cpaas-system apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: baremetal-bootstrap-selfsigned
namespace: cpaas-system
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: baremetal-bootstrap-ca
namespace: cpaas-system
spec:
secretName: baremetal-bootstrap-ca
commonName: baremetal-bootstrap-ca
duration: 87600h
renewBefore: 720h
isCA: true
privateKey:
algorithm: RSA
size: 2048
usages:
- cert sign
- crl sign
issuerRef:
name: baremetal-bootstrap-selfsigned
kind: Issuer
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: baremetal-bootstrap-ca
namespace: cpaas-system
spec:
ca:
secretName: baremetal-bootstrap-ca
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: dex-tls-bootstrap
namespace: cpaas-system
spec:
secretName: dex.tls
commonName: ${HOST_IP}
duration: 87600h
renewBefore: 720h
privateKey:
algorithm: RSA
size: 2048
usages:
- digital signature
- key encipherment
- server auth
ipAddresses:
- "${HOST_IP}"
- "127.0.0.1"
dnsNames:
- global-alb2
- global-alb2.cpaas-system.svc
- global-alb2.cpaas-system.svc.cluster.local
issuerRef:
name: baremetal-bootstrap-ca
kind: Issuer
EOF
kubectl -n cpaas-system wait certificate/baremetal-bootstrap-ca \
--for=condition=Ready \
--timeout=120s
kubectl -n cpaas-system wait certificate/dex-tls-bootstrap \
--for=condition=Ready \
--timeout=120s
验证该 Secret 是否包含预期的 key,并且证书对 bootstrap 端点有效:
kubectl -n cpaas-system get secret dex.tls \
-o jsonpath='{.data.tls\.crt}{" "}{.data.tls\.key}{" "}{.data.ca\.crt}{"\n"}'
tmp_dir=$(mktemp -d)
trap 'rm -rf "${tmp_dir}"' EXIT
kubectl -n cpaas-system get secret dex.tls \
-o jsonpath='{.data.ca\.crt}' | base64 -d > "${tmp_dir}/ca.crt"
kubectl -n cpaas-system get secret dex.tls \
-o jsonpath='{.data.tls\.crt}' | base64 -d > "${tmp_dir}/tls.crt"
openssl verify -CAfile "${tmp_dir}/ca.crt" "${tmp_dir}/tls.crt"
openssl x509 -in "${tmp_dir}/tls.crt" -noout -text | grep "IP Address:${HOST_IP}"
echo | openssl s_client \
-connect "${HOST_IP}:12443" \
-servername "${HOST_IP}" \
-CAfile "${tmp_dir}/ca.crt" \
-verify_return_error 2>&1 | grep "Verify return code: 0 (ok)"
如果 bootstrap ALB 仍在提供旧证书,请重启它并再次验证:
kubectl -n cpaas-system rollout restart deploy/global-alb2
kubectl -n cpaas-system rollout status deploy/global-alb2
不要将这个 bootstrap dex.tls 放入 dcs-import-extra-resources。它只用于临时 bootstrap 端点。最终 global 集群的 dex.tls 由安装器平台证书流程创建或维护。对于 DR,请在第 8 步中使用 thirdParty 控制台证书指导,以便最终平台证书链覆盖平台域名、主 VIP 和备用 VIP。
mkdir -p /root/yamls
export BAREMETAL_PROVIDER_APPRELEASES="/root/yamls/baremetal-provider-appreleases.yaml"
cat > "${BAREMETAL_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-baremetal
namespace: cpaas-system
spec:
destination:
cluster: ""
namespace: ""
source:
chartPullSecret: global-registry-auth
charts:
- name: ait/chart-cluster-api-provider-baremetal
releaseName: cluster-api-provider-baremetal
targetRevision: ${BAREMETAL_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}
tls:
secretName: dex.tls
labelBaseDomain: cpaas.io
namespace: cpaas-system
platformUrl: https://${HOST_IP}
protectSecretFiles:
enabled: false
region: global
registry:
address: ${BOOTSTRAP_REGISTRY_ADDRESS}
imagePullSecrets:
- global-registry-auth
replicas: 1
scheme: https
handoffHook:
controlPlaneVIP: ${CONTROL_PLANE_VIP}
delivery:
enabled: true
mode: always
elemental:
server:
url: https://${HOST_IP}:12443
systemAgent:
authMode: shared
serviceAccountName: baremetal-system-agent
tls:
agentTLSMode: strict
caCertSecretName: dex.tls
caCertSecretKey: ca.crt
EOF
kubectl apply -f "${BAREMETAL_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 baremetalclusters.infrastructure.cluster.x-k8s.io --ignore-not-found 2>/dev/null | grep -q baremetalclusters.infrastructure.cluster.x-k8s.io; do
sleep 10
done
until kubectl get crd machineinventories.elemental.cattle.io --ignore-not-found 2>/dev/null | grep -q machineinventories.elemental.cattle.io; do
sleep 10
done
provider 启动后,验证 chart values 是否已被接受。若出现带有未知标志(如 --system-agent-auth-mode)的 CrashLoopBackOff,说明 AppRelease chart 与 elemental-operator 镜像不匹配;请先安装来自同一发布负载的 chart 和镜像,再继续。
kubectl -n cpaas-system get pods | grep -E 'cluster-api-provider-baremetal|elemental'
kubectl -n cpaas-system logs deploy/elemental-operator --tail=100
第 4 步 — 配置 provider 专用的 global manifest
为 global 集群创建一个 provider 专用 manifest。该 manifest 使用与 workload cluster 相同的 provider 资源,但还必须包含平台控制平面所需的 global 专用标签、注解、registry 值、与安装器兼容的 kubeadm 设置以及持久化数据路径。
请使用以下 provider 创建指南作为详细的资源参考:
将 通用前提条件 中的命名约定应用到你在下方编写的 manifest 中的每个资源。
将 KubeadmControlPlane.spec.kubeadmConfigSpec.format 设置为目标 provider 接受的值。provider controller 会强制执行此项:
在渲染 DCS global manifest 之前,先设置输出路径。
export GLOBAL_DCS_YAML="/root/yamls/new-global.yaml"
DCS global manifest 必须在 cpaas-system 命名空间中包含以下资源:
请使用 在 Huawei DCS 上创建集群 和 Huawei DCS 基础设施资源 中的 DCS 资源字段。对于 global 集群,请保留以下附加要求:
- 将
Cluster.metadata.name 和 DCSCluster.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}"
在渲染 VMware vSphere global manifest 之前,先设置输出路径。
export GLOBAL_VSPHERE_YAML="/root/yamls/new-global.yaml"
VMware vSphere global manifest 必须在 cpaas-system 命名空间中包含以下资源:
请使用 准备 VMware vSphere 集群参数 准备 vSphere 输入值。请使用 在 global 集群中创建 VMware vSphere 集群 和 VMware vSphere Provider 作为基础参考来准备 global 集群 manifest。create-cluster 指南是针对从 global 集群创建的 workload cluster 编写的,但在应用以下附加要求后,其中的大部分 vSphere YAML 都可以复用于 global 集群:
- 将
Cluster.metadata.name 和 VSphereCluster.metadata.name 设置为 global(基础设施集群与 CAPI Cluster 同名)。其他所有 CAPI 资源和 provider 资源都要加上 global- 前缀;下方 wiring 片段使用 KubeadmControlPlane.metadata.name: global-kcp。
- 添加
Cluster.metadata.labels.is-global: "true" 和 Cluster.metadata.labels.cluster-type: VSphere。
- 添加
Cluster.metadata.annotations["cpaas.io/registry-address"],值为 ${NODE_REGISTRY_ADDRESS}。
- 保留平台 controller 所需的 VMware vSphere 注解,包括 VMware vSphere create-cluster 指南中的网络和 CPI 注解。
- 将
VSphereMachineTemplate.spec.template.spec.folder 设置为 /<datacenter>/vm/global,这样操作者就可以在 vCenter 中识别 global 集群的 VM。在 DR 部署中,分别为主集群和备用集群使用不同的子目录,例如 /<datacenter>/vm/global/primary 和 /<datacenter>/vm/global/standby。
- 将
VSphereCluster.spec.identityRef.name 设置为 global-vsphere-credentials。这个固定的 Secret 名称仅适用于 VMware vSphere global 安装路径;非 global 的 VMware vSphere 集群仍遵循通用 create-cluster 指南。
- 将
KubeadmControlPlane.spec.kubeadmConfigSpec.format 设置为 cloud-init,或者留空,因为 VMware vSphere 的默认值就是 cloud-init。
- 保留 release manifest 中的 kubeadm 文件,包括 VMware vSphere 的
/etc/kubernetes/encryption-provider.conf 文件条目,以及 kubelet patch、审计策略和 installer RBAC 条目。VMware vSphere 通过 KubeadmControlPlane.spec.kubeadmConfigSpec.files 提供此文件;不要使用 DCS 的 DCSCluster.spec.encryptionProviderConfigRef 模式。
片段范围
下方 YAML 是一个差异片段,不是可以直接应用的完整 manifest。请将这些 global 专用变更合并到你根据 VMware vSphere create-cluster 指南准备的 manifest 中,然后再应用完整 manifest 文件。
下方片段展示了 global 专用的 Cluster API wiring。请使用上面的 VMware vSphere create-cluster 参考来填写 provider 资源字段。
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
name: global
namespace: cpaas-system
labels:
cluster-type: VSphere
is-global: "true"
addons.cluster.x-k8s.io/vsphere-cpi: "enabled"
annotations:
capi.cpaas.io/resource-group-version: infrastructure.cluster.x-k8s.io/v1beta1
capi.cpaas.io/resource-kind: VSphereCluster
cpaas.io/alb-address-type: ClusterAddress
cpaas.io/network-type: kube-ovn
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: VSphereCluster
name: global
---
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: KubeadmControlPlane
metadata:
name: global-kcp
namespace: cpaas-system
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: VSphereMachineTemplate
name: global-master-machine-template
kubeadmConfigSpec:
format: cloud-init
clusterConfiguration:
etcd:
local:
serverCertSANs:
- "${CONTROL_PLANE_VIP}"
- "${PLATFORM_HOST}"
在渲染 HCS global manifest 之前,先设置输出路径。
export GLOBAL_HCS_YAML="/root/yamls/new-global.yaml"
HCS global manifest 必须在 cpaas-system 命名空间中包含以下资源:
请使用 在 Huawei Cloud Stack 上创建集群 和 Huawei Cloud Stack 基础设施资源 中的 HCS 资源字段。对于 global 集群,请保留以下附加要求:
- 将
Cluster.metadata.name 和 HCSCluster.metadata.name 设置为 global(基础设施集群与 CAPI Cluster 同名)。其他所有 CAPI 资源和 provider 资源都要加上 global- 前缀;下方 wiring 片段使用 KubeadmControlPlane.metadata.name: global-kcp。
- 将
HCSCluster.spec.identityRef.name 设置为 ${PROVIDER_SECRET_NAME}。第 7 步会将该 Secret 导入到最终的 global 集群中。
- 添加
Cluster.metadata.labels.is-global: "true" 和 Cluster.metadata.labels.cluster-type: HCS。
- 添加
Cluster.metadata.annotations["cpaas.io/registry-address"],值为 ${NODE_REGISTRY_ADDRESS}。
- 将
KubeadmControlPlane.spec.kubeadmConfigSpec.format 设置为 cloud-init,或者留空,因为 HCS 的默认值就是 cloud-init。
- 保留 release manifest 中非加密的 kubeadm 文件、kubelet patch、审计策略以及 installer RBAC 条目。
- 对于普通的非 DR 部署,不要将
/etc/kubernetes/encryption-provider.conf 添加到 KubeadmControlPlane.spec.kubeadmConfigSpec.files。
- 将
/var/cpaas 保持为平台状态目录。当它必须在节点替换后继续保留时,请在 HCSMachineConfigPool.spec.configs[].persistentDisks[] 中声明;不要依赖 HCSMachineTemplate.spec.template.spec.dataVolumes[] 作为保留状态。
global 集群请使用高可用控制平面。单控制平面 HCS 集群仅适用于创建,不是推荐的 global 升级路径。
片段范围
下方 YAML 是一个差异片段,不是可以直接应用的完整 manifest。请将这些 global 专用变更合并到你根据 HCS create-cluster 参考准备的 manifest 中,然后再应用完整 manifest 文件。
下方片段展示了 global 专用的 Cluster API wiring。请使用上面的 HCS create-cluster 参考来填写 provider 资源字段。
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
name: global
namespace: cpaas-system
labels:
cluster-type: HCS
is-global: "true"
annotations:
capi.cpaas.io/resource-group-version: infrastructure.cluster.x-k8s.io/v1beta1
capi.cpaas.io/resource-kind: HCSCluster
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: HCSCluster
name: global
---
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: KubeadmControlPlane
metadata:
name: global-kcp
namespace: cpaas-system
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: HCSMachineTemplate
name: global-master-machine-template
kubeadmConfigSpec:
format: cloud-init
clusterConfiguration:
etcd:
local:
serverCertSANs:
- "${CONTROL_PLANE_VIP}"
- "${PLATFORM_HOST}"
在渲染 裸金属 global manifest 之前,先设置输出路径。
export GLOBAL_BAREMETAL_YAML="/root/yamls/new-global.yaml"
裸金属 global manifest 必须在 cpaas-system 命名空间中包含以下资源:
请使用 在裸金属上创建集群、在裸金属上管理节点 和 Bare Metal Provider 作为资源参考。对于 global 集群,请保留以下附加要求:
-
将 Cluster.metadata.name 和 BaremetalCluster.metadata.name 设置为 global。其他所有 CAPI、裸金属和 elemental 资源都要加上 global- 前缀。
-
添加 Cluster.metadata.labels.cluster-type: ProviderBaremetal。
-
添加 Cluster.metadata.annotations["cpaas.io/registry-address"],值为 ${NODE_REGISTRY_ADDRESS}。
-
添加 Cluster.metadata.annotations["cpaas.io/kube-ovn-join-cidr"]、Cluster.metadata.annotations["cpaas.io/sentry-deploy-type"]: Baremetal 以及 Cluster.metadata.annotations["cpaas.io/alb-address-type"]: ClusterAddress。
-
将 KubeadmControlPlane.spec.kubeadmConfigSpec.format 设置为 cloud-init,或者留空,因为裸金属使用的 provider 路径就是 cloud-init。
-
将 KubeadmControlPlane.spec.rolloutStrategy.rollingUpdate.maxSurge 设置为 0。裸金属池不能对物理主机进行超额分配。
-
当 release manifest 使用 kube-ovn 时,保留 KubeadmControlPlane 上的 controlplane.cluster.x-k8s.io/skip-kube-proxy: ""。
-
在 KubeadmControlPlane.spec.kubeadmConfigSpec.clusterConfiguration.etcd.local.serverCertSANs 中加入 ${CONTROL_PLANE_VIP} 和 ${PLATFORM_HOST}。
-
将 BaremetalCluster.spec.controlPlaneLoadBalancer.host 设置为 ${CONTROL_PLANE_VIP},port 设置为 6443,并使用在控制平面二层网络域中唯一的 vrid。
-
对于普通的非 DR 部署,可以省略 BaremetalCluster.spec.encryptionProviderConfigRef。对于 DR,请按 可选灾难恢复部署 中的说明进行设置;不要通过将其添加到 KubeadmControlPlane.spec.kubeadmConfigSpec.files 来交付 /etc/kubernetes/encryption-provider.conf。
-
不要在 bootstrap global 主机使用的 MachineRegistration 上设置 baremetal.cluster.io/system-agent-server-url。bootstrap ISO 必须通过 bootstrap 主机进行注册;handoff job 会在之后将 global 机器切换到 VIP。
-
如果某个 global VM 或物理主机在 live-ISO 启动期间没有 DHCP,请在等待 MachineInventory 注册前,从主机控制台手动配置 NIC。使用 在裸金属上创建集群 中描述的相同 NetworkManager 操作步骤,并将示例地址、网关、DNS 和连接名替换为该主机的实际值。
-
不要依赖操作系统 hostname 的副作用。裸金属 provider 会从 CAPI 和 inventory 对象中规范化 kubeadm 节点名称和 provider ID。
-
在 bootstrap KIND 环境中创建的 SeedImage 是 bootstrap 工件。handoff 之后,请在活动的 global 集群上创建任何新的 MachineRegistration 或 SeedImage。
-
当向已安装的 global 集群添加新机器时,必须在该 MachineRegistration 上显式设置 baremetal.cluster.io/system-agent-server-url 注解,指向当前活动的 global 控制平面 VIP。新的 global 机器不会经过 bootstrap handoff job,因此该注解决定了它们的 system-agent 通过 https://<CONTROL_PLANE_VIP>/kubernetes/global 监听 plan Secret。非 global workload cluster 机器应继续使用平台域路径。
apiVersion: elemental.cattle.io/v1beta1
kind: MachineRegistration
metadata:
name: global-<purpose>
namespace: cpaas-system
annotations:
baremetal.cluster.io/system-agent-server-url: https://<CONTROL_PLANE_VIP>
片段范围
下方 YAML 是一个差异片段,不是可以直接应用的完整 manifest。请将这些 global 专用变更合并到你根据裸金属 create-cluster 参考准备的 manifest 中,然后再应用完整 manifest 文件。
下方片段展示了 global 专用的 Cluster API wiring。请使用上面的 裸金属 create-cluster 参考来填写 inventory 名称、注册配置、镜像引用以及可选的 worker 资源。
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
name: global
namespace: cpaas-system
labels:
cluster-type: ProviderBaremetal
annotations:
capi.cpaas.io/resource-group-version: infrastructure.cluster.x-k8s.io/v1beta1
capi.cpaas.io/resource-kind: BaremetalCluster
cpaas.io/kube-ovn-join-cidr: "${KUBE_OVN_JOIN_CIDR}"
cpaas.io/registry-address: "${NODE_REGISTRY_ADDRESS}"
cpaas.io/sentry-deploy-type: Baremetal
cpaas.io/alb-address-type: ClusterAddress
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: BaremetalCluster
name: global
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: BaremetalCluster
metadata:
name: global
namespace: cpaas-system
spec:
controlPlaneLoadBalancer:
type: Internal
host: ${CONTROL_PLANE_VIP}
port: 6443
vrid: <unique-vrid>
# vipMode defaults to nic. Set it explicitly only when the environment
# requires another supported mode, such as arp or policy_route.
# vipMode: nic
# Required for DR. Omit this field for a normal non-DR deployment unless
# you need to provide a pre-existing encryption-provider.conf.
# encryptionProviderConfigRef:
# name: global-encryption-provider-config
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: MachineInventoryPool
metadata:
name: global-control-plane-pool
namespace: cpaas-system
spec:
clusterName: global
machineInventories:
- global-cp-1
- global-cp-2
- global-cp-3
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: BaremetalMachineTemplate
metadata:
name: global-control-plane-template
namespace: cpaas-system
spec:
template:
spec:
machineInventoryPoolRef:
name: global-control-plane-pool
allocationPolicy: Ordered
---
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: BaremetalMachineTemplate
name: global-control-plane-template
kubeadmConfigSpec:
format: cloud-init
clusterConfiguration:
etcd:
local:
serverCertSANs:
- "${CONTROL_PLANE_VIP}"
- "${PLATFORM_HOST}"
第 5 步 — 应用 global manifest
将 provider 专用 manifest 应用到 minialauda。
kubectl apply -f "${GLOBAL_DCS_YAML}"
kubectl apply -f "${GLOBAL_VSPHERE_YAML}"
kubectl apply -f "${GLOBAL_HCS_YAML}"
kubectl apply -f "${GLOBAL_BAREMETAL_YAML}"
在你期望 Cluster API 开始协调之前,请等待 bootstrap registrations 生成预期的 inventory。
kubectl -n cpaas-system get machineinventory.elemental.cattle.io
kubectl -n cpaas-system get machineinventorypool
kubectl -n cpaas-system get baremetalcluster,baremetalmachine
第 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: True 且 Cluster 报告 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 必须显式导入。
在触发安装器之前,创建并应用 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
在触发安装器之前,创建并应用 VMware vSphere 导入 ConfigMap。此 ConfigMap 对正常安装和灾难恢复 global 安装都必需。global-vsphere-credentials Secret 存储 vCenter 用户名和密码,并且必须与 VMware vSphere global manifest 中 VSphereCluster.spec.identityRef.name 引用的 Secret 名称保持一致。
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: "vsphereclusters.infrastructure.cluster.x-k8s.io"
names: ["global"]
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/vsphereclusters/cpaas-system/"
method: etcdctl
- resource: "vspheremachinetemplates.infrastructure.cluster.x-k8s.io"
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/vspheremachinetemplates/cpaas-system/"
method: etcdctl
- resource: "vspheremachines.infrastructure.cluster.x-k8s.io"
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/vspheremachines/cpaas-system/"
method: etcdctl
- resource: "vspherevms.infrastructure.cluster.x-k8s.io"
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/vspherevms/cpaas-system/"
method: etcdctl
- resource: "vspheremachineconfigpools.infrastructure.cluster.x-k8s.io"
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/vspheremachineconfigpools/cpaas-system/"
method: etcdctl
- resource: "secrets"
names: ["global-vsphere-credentials"]
method: kubectl
EOF
kubectl apply -f /root/yamls/dcs-import-extra-resources.yaml
在触发安装器之前,创建并应用 HCS 导入 ConfigMap。此 ConfigMap 对正常安装和灾难恢复 global 安装都必需。将 PROVIDER_SECRET_NAME 设置为与 HCSCluster.spec.identityRef.name 相同的 Secret 名称。
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
- resource: "hcsclusters.infrastructure.cluster.x-k8s.io"
names: ["global"]
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/hcsclusters/cpaas-system/"
method: etcdctl
- resource: "hcsmachinetemplates.infrastructure.cluster.x-k8s.io"
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/hcsmachinetemplates/cpaas-system/"
method: etcdctl
- resource: "hcsmachineconfigpools.infrastructure.cluster.x-k8s.io"
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/hcsmachineconfigpools/cpaas-system/"
method: etcdctl
- resource: "hcsmachines.infrastructure.cluster.x-k8s.io"
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/hcsmachines/cpaas-system/"
method: etcdctl
EOF
kubectl apply -f /root/yamls/dcs-import-extra-resources.yaml
在触发安装器之前,创建并应用 裸金属 导入 ConfigMap。之所以需要它,是因为安装器必须导入 bootstrap KIND 集群中创建的裸金属和 elemental 资源,而此时 global 集群尚不存在。
在 DCS API 之前导入
在调用 POST /cpaas-installer/api/config/dcs 之前,先创建 dcs-import-extra-resources。如果缺失,handoff job 可能会在空的目标列表上运行,因为新的 global 集群中还没有描述 bootstrap global 机器的 BaremetalMachine、MachineInventory、MachineRegistration 或 plan Secret 对象。
在 global Cluster API 资源完成协调后,再收集 plan Secret 名称和 kubeadm bootstrap data Secret 名称。这些名称在 CAPI 创建 Machines 之前不存在。对于 DR,还要包含 BaremetalCluster.spec.encryptionProviderConfigRef 引用的 Secret,以便最终的 global 集群包含相同的 encryption-provider 配置。不要导入任意平台凭证 Secret,也不要导入 MachineRegistration token Secret。
kubectl -n cpaas-system get machineinventory.elemental.cattle.io \
-o jsonpath='{range .items[*]}{.status.plan.secretRef.name}{"\n"}{end}'
kubectl -n cpaas-system get baremetalmachine \
-o jsonpath='{range .items[*]}{.status.planSecretRef.name}{"\n"}{end}'
kubectl -n cpaas-system get machine -l cluster.x-k8s.io/cluster-name=global \
-o jsonpath='{range .items[*]}{.spec.bootstrap.dataSecretName}{"\n"}{end}'
创建 ConfigMap。将占位符 inventory、plan Secret 和 bootstrap data Secret 名称替换为上面命令得到的值。
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: "customresourcedefinitions.apiextensions.k8s.io"
names:
- baremetalclusters.infrastructure.cluster.x-k8s.io
- baremetalmachines.infrastructure.cluster.x-k8s.io
- baremetalmachinetemplates.infrastructure.cluster.x-k8s.io
- machineinventorypools.infrastructure.cluster.x-k8s.io
- machineinventories.elemental.cattle.io
- machineregistrations.elemental.cattle.io
- seedimages.elemental.cattle.io
method: kubectl
- resource: "baremetalclusters.infrastructure.cluster.x-k8s.io"
names: ["global"]
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/baremetalclusters/cpaas-system/"
method: etcdctl
- resource: "baremetalmachinetemplates.infrastructure.cluster.x-k8s.io"
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/baremetalmachinetemplates/cpaas-system/"
method: etcdctl
- resource: "baremetalmachines.infrastructure.cluster.x-k8s.io"
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/baremetalmachines/cpaas-system/"
method: etcdctl
- resource: "machineinventorypools.infrastructure.cluster.x-k8s.io"
etcdKeyBase: "/registry/infrastructure.cluster.x-k8s.io/machineinventorypools/cpaas-system/"
method: etcdctl
- resource: "machineinventories.elemental.cattle.io"
names:
- "<global-machine-inventory-1>"
- "<global-machine-inventory-2>"
- "<global-machine-inventory-3>"
etcdKeyBase: "/registry/elemental.cattle.io/machineinventories/cpaas-system/"
method: etcdctl
- resource: "machineregistrations.elemental.cattle.io"
names: ["<global-machine-registration>"]
etcdKeyBase: "/registry/elemental.cattle.io/machineregistrations/cpaas-system/"
method: etcdctl
- resource: "secrets"
names:
- "<global-machine-plan-secret-1>"
- "<global-machine-plan-secret-2>"
- "<global-machine-plan-secret-3>"
method: kubectl
- resource: "secrets"
names:
- "<global-kubeadm-bootstrap-data-secret-1>"
- "<global-kubeadm-bootstrap-data-secret-2>"
- "<global-kubeadm-bootstrap-data-secret-3>"
method: kubectl
# Required for DR when BaremetalCluster.spec.encryptionProviderConfigRef is set.
# The name must match the Secret referenced by BaremetalCluster.
- resource: "secrets"
names:
- "<global-encryption-provider-config-secret>"
method: kubectl
EOF
kubectl apply -f /root/yamls/dcs-import-extra-resources.yaml
kubectl -n cpaas-system get cm dcs-import-extra-resources -o yaml
不要将 SeedImage 对象或 MachineRegistration token Secret 添加到此导入列表中。bootstrap SeedImage 会生成一个指向 bootstrap 环境的 ISO,而在 global 集群完成 handoff 后,它已经不再是正确的生命周期对象。seedimages.elemental.cattle.io CRD 之所以被导入,只是为了让新的 global 集群理解该 API 类型。
对于 DR,请在安装后验证最终的 global 集群中是否已包含导入的 encryption-provider Secret。
kubectl --kubeconfig <global-kubeconfig> -n cpaas-system \
get secret <global-encryption-provider-config-secret> \
-o jsonpath='{.data.encryption-provider\.conf}{"\n"}'
第 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_IP 是 minialauda 中内嵌安装器的 Pod IP。该端点仅在安装期间使用。
在当前 KIND 主机上创建 provider 专用的安装器配置 JSON 文件,然后将其提交给安装器端点。此安装路径中的所有 provider 都使用相同的端点路径,但请求体不同。
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.host 和 cluster.features.ha.vip 设置为本地 global HA VIP。不要在 console.host 中使用平台域;请在 console.globalHost 中使用平台访问地址。
VMware vSphere 使用与 DCS 相同的安装器端点路径,但其请求体不包含 cluster.features.ha。控制平面端点在 VSphereCluster.spec.controlPlaneEndpoint.host 中声明,而 cluster CIDR 在 VMware vSphere Cluster manifest 中声明。
mkdir -p /root/yamls
export INSTALLER_CONFIG_JSON="/root/yamls/installer-config-vsphere.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": [],
"globalHost": "${PLATFORM_HOST}",
"httpPort": 80,
"httpsPort": 443,
"cert": {
"selfSigned": {}
}
},
"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.host 保持为空列表,因为 VMware vSphere 控制平面端点已经在 global manifest 中设置。不要在 console.host 中使用平台域;请在 console.globalHost 中使用平台访问地址。
HCS 使用与 DCS 相同的安装器端点路径,但其请求体不包含 cluster.features.ha。控制平面 VIP 由 HCSCluster.spec.controlPlaneLoadBalancer 中声明的 HCS ELB 管理,因此 console.host 必须保持为空列表。
mkdir -p /root/yamls
export INSTALLER_CONFIG_JSON="/root/yamls/installer-config-hcs.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": [],
"globalHost": "${PLATFORM_HOST}",
"httpPort": 80,
"httpsPort": 443,
"cert": {
"selfSigned": {}
}
},
"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}"
裸金属安装器请求包含控制平面 VIP,因为 global 集群在 handoff 后使用 alive 暴露的 VIP。将 REGISTRY_DOMAIN 设置为最终 global 集群应使用的平台 registry 地址。对于 DR,在主集群和备用集群上都使用 ${PLATFORM_HOST}:11443,这样 registry 会随着平台域切换而切换。对于非 DR 部署,${CONTROL_PLANE_VIP}:11443 也有效。不要在此字段中使用 bootstrap registry 地址。
mkdir -p /root/yamls
export INSTALLER_CONFIG_JSON="/root/yamls/installer-config-baremetal.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.host 和 cluster.features.ha.vip 设置为本地裸金属 global 控制平面 VIP。使用 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 部署速度、镜像拉取时间以及所选插件数量。
你将观察到的阶段
安装期间的信号
请同时观察安装器进度 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
常见卡顿及排查位置
这里未列出的其他问题通常指向环境特定原因。请收集安装器日志、进度 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 字段
在 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 名称。
不需要 VSphereCluster encryption Secret 引用。对于 VMware vSphere,请在主集群和备用集群的安装环境中都保留 KubeadmControlPlane.spec.kubeadmConfigSpec.files 中的这个文件条目。渲染后的 /etc/kubernetes/encryption-provider.conf 内容在两侧必须完全一致,包括 provider 顺序、key 名称以及 base64 key 值。还需要在两个安装环境上都创建第 7 步中的 VMware vSphere dcs-import-extra-resources ConfigMap,以便安装器导入 vSphere 基础设施资源和 global-vsphere-credentials Secret。
- 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: ${ENCRYPTION_PROVIDER_SECRET_B64}
在主集群和备用集群的安装环境中保留相同的 DR serverCertSANs 列表。
不需要 HCSCluster encryption Secret 引用。对于 HCS,请在主集群和备用集群的安装环境中将这个文件条目追加到 KubeadmControlPlane.spec.kubeadmConfigSpec.files 中。渲染后的 /etc/kubernetes/encryption-provider.conf 内容在两侧必须完全一致,包括 provider 顺序、key 名称以及 base64 key 值。
- 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: ${ENCRYPTION_PROVIDER_SECRET_B64}
在主集群和备用集群的安装环境中保留相同的 DR serverCertSANs 列表。
在两个安装环境上都创建第 7 步中的 HCS dcs-import-extra-resources ConfigMap。将 PROVIDER_SECRET_NAME 设置为与 HCSCluster.spec.identityRef.name 相同的 Secret 名称。
在主集群和备用集群的安装环境中分别在 minialauda 中创建 encryption provider Secret。该 Secret 必须位于与 BaremetalCluster 相同的命名空间中,并且必须包含名为 encryption-provider.conf 的 key。
kubectl create secret generic "${BAREMETAL_ENCRYPTION_PROVIDER_SECRET}" \
--from-file=encryption-provider.conf="${ENCRYPTION_PROVIDER_CONF}" \
-n cpaas-system \
--dry-run=client -o yaml | kubectl apply -f -
从 BaremetalCluster.spec.encryptionProviderConfigRef 引用该 Secret。
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: BaremetalCluster
metadata:
name: global
namespace: cpaas-system
spec:
encryptionProviderConfigRef:
name: global-encryption-provider-config
裸金属 provider 会读取此 Secret,并将 /etc/kubernetes/encryption-provider.conf 注入到生成的控制平面 bootstrap 数据中。对于 裸金属 DR,不要再手动将该文件添加到 KubeadmControlPlane.spec.kubeadmConfigSpec.files 中;BaremetalCluster 引用才是唯一事实来源。
这个 Secret 还必须包含到第 7 步中的 裸金属 dcs-import-extra-resources ConfigMap 中。它不能只保留在 bootstrap KIND 集群里,因为 handoff 后的 global 集群会保留导入后的 BaremetalCluster 对象,并且后续 provider 协调也需要引用到该 Secret。
在主集群和备用集群的安装环境中保留相同的 DR serverCertSANs 列表。
还要保留来自 准备共享 ServiceAccount signing key 的共享 ServiceAccount signing key 配置。没有该 key,备用 API server 将无法验证故障切换前已有主机收到的 baremetal-system-agent token。
在两个安装环境上都创建第 7 步中的 裸金属 dcs-import-extra-resources ConfigMap。该 ConfigMap 必须导入 handoff 所需的裸金属和 elemental 资源,包括 BaremetalCluster.spec.encryptionProviderConfigRef 引用的 encryption-provider Secret,并且不能导入 SeedImage。
两侧的 裸金属 provider AppRelease 都必须启用共享 system-agent auth 和 handoff 交付:
handoffHook:
controlPlaneVIP: <current-side-control-plane-vip>
delivery:
enabled: true
mode: always
# directAPIServer: true # DR opt-in only. Points global-cluster machines at
# https://<control-plane-vip>:6443 directly instead of the platform ingress
# path. Defaults to false. See "Bare Metal DR Model" in Disaster Recovery.
elemental:
systemAgent:
authMode: shared
serviceAccountName: baremetal-system-agent
tls:
agentTLSMode: strict
caCertSecretName: dex.tls
caCertSecretKey: ca.crt
生成的 Role/cpaas-system/baremetal-system-agent 必须使用 resourceNames 限制 secrets 访问权限,而且 resourceNames 中只能包含 plan Secret 名称。不要授予命名空间范围的 Secret 访问权限,也不要包含 registry、bootstrap 或平台凭证 Secret。
安装主集群和备用集群
对主 global 集群和备用 global 集群都执行第 1 步到第 9 步。
对于 裸金属 DR,请使用两个独立的 bootstrap KIND 主机:一个用于主集群安装,一个用于备用集群安装。不要为两侧复用同一个 bootstrap KIND 集群。bootstrap 环境包含安装器状态、AppRelease 对象、registry Secret、MachineRegistration、SeedImage 以及 handoff 状态;共享这些内容可能会污染两个 global 安装,并可能使 handoff 或清理操作影响错误的一侧。
对两侧使用 provider 专用安装器配置差异:
对于主集群,请确保平台域解析到主 HA VIP。在第 8 步中,将 hostIP 设置为主 KIND 节点 IP。对于 DCS,将 console.host 和 cluster.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.host 和 cluster.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_vip 和 active_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: Success 且 type: Complete。
- 所有
global 集群节点都处于 Ready。
cpaas-system 中的关键 Pod 处于 Running 或 Completed。
ClusterModule/global 报告基础模块健康。
下一步
- 在新的
global 集群上安装其他 provider 插件:请参见 安装。
- 为 workload cluster 配置基础设施资源:请参见 基础设施资源。
- 创建你的第一个 workload cluster:请参见 创建集群。
- 规划灾难恢复:请参见 global 集群灾难恢复。