• Русский
  • Создание кластеров на Huawei DCS

    В этом документе приведены инструкции по созданию кластеров Kubernetes на платформе Huawei DCS. Создание кластера на основе YAML доступно через manifests. Если установлен Fleet Essentials и версия Alauda Container Platform DCS Infrastructure Provider равна 1.0.13 или выше, вы также можете создавать кластеры через web UI. Если рабочий процесс опирается на persistent disks, управляемые пулом, используйте DCS provider v1.0.16 или выше. В v1.0.16 объявление persistentDisk для DCSIpHostnamePool доступно только через YAML и не отображается в web UI.

    INFO

    Web UI предоставляет пошаговый сценарий с проверками, тогда как YAML обеспечивает большую гибкость автоматизации.

    Предварительные требования

    Перед созданием кластеров убедитесь, что выполнены все следующие предварительные требования:

    1. Ресурсы инфраструктуры

    Перед созданием кластера настройте следующие ресурсы инфраструктуры:

    • Cloud Credential - информация для доступа к платформе DCS
    • IP Pool - сетевые настройки для узлов кластера, дополнительных NIC и любых persistent disks с IP-slot, таких как /var/cpaas
    • Machine Template - характеристики VM для control plane и worker-узлов, без persistent disks, управляемых пулом

    Подробные инструкции по настройке см. в разделе Infrastructure Resources for Huawei DCS.

    2. Установка необходимых плагинов

    Установите следующие плагины в кластере global:

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

    Подробные инструкции по установке см. в Installation Guide.

    3. Подготовка шаблона виртуальной машины

    Для установки Kubernetes необходимо:

    • загрузить образ Alauda OS на платформу DCS
    • создать шаблон виртуальной машины на основе этого образа
    • убедиться, что шаблон включает все необходимые компоненты Kubernetes
    • использовать шаблоны DCS VM 4.2.1 или выше, если планируется использовать persistent disks, поскольку безопасное завершение работы и отключение диска зависят от guest tools
    • использовать замену один за одним для любого кластера, который будет опираться на persistent disks, управляемые пулом. Установите maxSurge: 0 для control plane и для пулов worker-узлов.

    Подробности о компонентах Kubernetes, включенных в каждый образ VM, см. в OS Support Matrix.

    4. Сетевое подключение

    Узлы кластера global должны иметь возможность обращаться к платформе DCS по двум различным адресатам:

    FromToPortPurpose
    Узел кластера globalDCS VRM virtual IPTCP/7443DCS REST API. Охватывает вызовы жизненного цикла кластера и первый шаг загрузки файлов (applyUpload).
    Узел кластера globalDCS physical host MGMT IP (every host that may receive a clone)DCS-returned port; typically TCP/8443; confirm with the DCS administratorFile-stream upload of the Ignition ISO. The provider streams the file to the URL returned by the applyUpload response.

    Загрузка файла выполняется в два этапа: provider вызывает applyUpload на VRM virtual IP (TCP/7443); платформа DCS отвечает URL, который указывает на MGMT IP и порт конкретного physical host; после этого provider передает файл потоком по этому URL. Оба адресата должны быть доступны end-to-end до начала создания кластера.

    Если узлы кластера global используют multi-NIC layout (например, один NIC в сети кластера ACP, а другой NIC — в сети управления клиента, где развернут DCS), убедитесь, что к обоим адресатам — VRM virtual IP и каждому DCS physical host MGMT IP — можно маршрутизировать трафик с соответствующего NIC.

    Требование: подключение к обоим адресатам обязательно для создания и управления кластером.

    5. Настройка LoadBalancer

    Перед созданием кластера настройте LoadBalancer для Kubernetes API Server. LoadBalancer распределяет трафик API server между узлами control plane, обеспечивая высокую доступность.

    DCS provider не создает этот load balancer. Разверните его самостоятельно до создания кластера и укажите его адрес в DCSCluster.spec.controlPlaneLoadBalancer. Для развертывания с одним control-plane, в котором перед API server нет load balancer, см. Single-Control-Plane (No External LB) Layout.

    6. Настройка публичного registry

    Настройте учетные данные публичного registry. Это включает:

    • настройку адреса repository registry
    • настройку корректных учетных данных для аутентификации

    Использование Web UI

    WARNING

    Fleet Essentials UI не поддерживает обновление кластеров ACP 4.3

    Сценарий Fleet Essentials UI не был адаптирован под механизм Cluster Version Operator (CVO), представленный в ACP 4.3. Не используйте Fleet Essentials UI для обновления кластеров DCS на ACP 4.3.

    Две поддерживаемые альтернативы:

    • YAML path — выполните описанную далее на этой странице процедуру обновления на основе YAML.
    • ACP Core cluster management UI — используйте встроенный в платформу ACP Core двухэтапный сценарий обновления; см. Request the upgrade for the global cluster или Request the upgrade for workload clusters.

    Это ограничение не влияет на создание кластеров и управление node-pool через Fleet Essentials UI.

    Требование к версии: этот сценарий требует Fleet Essentials и Alauda Container Platform DCS Infrastructure Provider 1.0.13 или выше. Если версия provider ниже 1.0.13, используйте YAML manifests. Если вы используете persistent disks, управляемые пулом, используйте DCS provider v1.0.16 или выше. В v1.0.16 настройте DCSIpHostnamePool.spec.pool[].persistentDisk через YAML, так как web UI не отображает это поле.

    Если новый кластер будет опираться на persistent disks, управляемые пулом, создайте или обновите базовый DCSIpHostnamePool с помощью YAML, а затем используйте 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 CredentialdropdownYesВыберите существующий Cloud Credential
    NametextYesУникальный идентификатор кластера (строчные буквы, цифры, дефисы)
    Display NametextNoПользовательское описание для удобной идентификации
    Distribution Versionreadonly-Версия ACP (совпадает с кластером global)
    Kubernetes Versionreadonly-Определяется Distribution Version
    Cluster API AddresstextYesФормат: https://<load-balancer-address>:6443

    Проверка предварительных условий:

    Перед созданием кластера убедитесь, что:

    • в платформе DCS существуют DCS VM Templates, а версия Alauda OS соответствует версии Kubernetes
    • настроен LoadBalancer для Kubernetes API Server

    Ограничение версии: можно создать только последнюю версию Kubernetes, поддерживаемую платформой.

    Шаг 2: Node Pool control plane

    Node pool control plane имеет фиксированное значение 3 replicas для обеспечения высокой доступности.

    ПолеТипОбязательноОписание
    Machine TemplatedropdownYesФильтрует шаблоны по Type: Control Plane и совместимой версии Kubernetes
    Replicasreadonly-Зафиксировано на значении 3
    SSH Authorized KeystextNoДобавьте несколько SSH public keys для доступа к узлам

    Проверка: связанный IP Pool должен иметь достаточное количество доступных IP-адресов (≥ 3).

    Шаг 3: Worker Node Pools

    Вы можете добавить несколько worker node pool. Для каждого pool предусмотрена следующая конфигурация:

    ПолеТипОбязательноОписание
    Pool NametextYesУникальный идентификатор этого node pool
    Machine TemplatedropdownYesФильтрует шаблоны по Type: Worker Node и совместимой версии Kubernetes
    ReplicasnumberYesПо умолчанию: 3
    Max SurgenumberNoПо умолчанию: 0, должно быть ≥ 0. Оставьте это значение равным 0, если node pool будет использовать persistent disks, управляемые пулом
    Max UnavailablenumberNoПо умолчанию: 1, должно быть ≥ 0. Когда maxSurge = 0, maxUnavailable должен быть > 0 и ≤ Replicas
    SSH Authorized KeystextNoДобавьте несколько SSH public keys

    Правила проверки:

    • имена pool должны быть уникальными в пределах кластера
    • IP Pool должен иметь достаточное количество доступных IP-адресов (≥ Replicas)
    • maxSurge и maxUnavailable должны удовлетворять ограничению: если maxSurge = 0, то maxUnavailable > 0
    • если кластер будет опираться на persistent disks, управляемые пулом, оставляйте maxSurge = 0, чтобы узлы заменялись по одному во время будущих обновлений

    Совет: добавьте к имени pool префикс в виде имени кластера и дефиса (например, mycluster-worker-1), чтобы избежать конфликтов имен между разными кластерами.

    Шаг 4: Сеть

    ПолеТипОбязательноОписание
    Pods CIDRCIDRYesДиапазон адресов сети Pod
    Services CIDRCIDRYesДиапазон адресов сети Service
    Join CIDRCIDRYesПараметр Join CIDR для Kube-OVN

    Проверка: Pods CIDR и Services CIDR не должны пересекаться.

    Шаг 5: Проверка

    Перед созданием кластера проверьте все параметры конфигурации:

    Основная информация:

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

    Node Pool control plane:

    • Machine Template с VM Template Name, OS Version, Kubernetes Version
    • CPU, Memory, Replicas, SSH Keys

    Worker Node Pools (вид списка):

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

    Если кластер будет опираться на persistent disks, управляемые пулом, оставьте Max Surge равным 0 для worker node pool.

    Сеть:

    • Pods CIDR, Services CIDR, Join CIDR

    Нажмите Create, чтобы запустить процесс создания кластера.


    Использование YAML

    Сценарий создания кластера

    При использовании YAML вы создаете ресурсы Cluster API в кластере global, чтобы подготовить инфраструктуру и инициализировать рабочий кластер Kubernetes.

    WARNING

    Важное требование к namespace

    Чтобы обеспечить корректную интеграцию в качестве business clusters, все ресурсы должны быть развернуты в namespace cpaas-system. Развертывание ресурсов в других namespace может привести к проблемам интеграции.

    WARNING

    Именование workload cluster

    cluster-name для workload не должен быть global. Это имя зарезервировано для кластера global, и его повторное использование приводит к конфликту ресурсов workload cluster с ресурсами кластера global в cpaas-system. Префикс global- зарезервирован для ресурсов, которыми владеет DR workflow кластера global; см. Common Prerequisites. Не используйте global- для ресурсов workload cluster, поскольку операции failover могут выбрать эти ресурсы так, как будто они принадлежат кластеру global.

    По соглашению, присваивайте ресурсам CAPI Cluster и ресурсу кластера provider (DCSCluster) точное имя <cluster-name>, а не-root ресурсам CAPI и provider (KubeadmControlPlane, KubeadmConfigTemplate, MachineDeployment, machine templates, IP/hostname pools и т. д.) — префикс <cluster-name>-; например, в приведенных ниже manifests используются <cluster-name>-kcp. Это рекомендация, а не правило, enforced controller, но она предотвращает конфликты в пределах одного namespace при размещении нескольких workload cluster в cpaas-system и делает владение ресурсами очевидным при выполнении операций.

    Сценарий настройки

    Выполняйте следующие шаги по порядку, чтобы подготовить функциональный кластер (control plane и worker-узлы):

    1. Настройте KubeadmControlPlane (спецификация control plane и kubeadm bootstrap).
    2. Настройте DCSCluster (привязка инфраструктуры и ссылка на load balancer).
    3. Создайте ресурс Cluster (верхнеуровневый объект CAPI, связывающий два предыдущих).
    4. Настройте worker-ресурсы: KubeadmConfigTemplate (worker bootstrap), worker DCSMachineTemplate, worker DCSIpHostnamePool и MachineDeployment. Только control plane не является полноценным рабочим кластером. См. Managing Nodes on Huawei DCS для четырех YAML-ресурсов worker.

    Примечание: инфраструктурные ресурсы (Secret, control-plane DCSIpHostnamePool, control-plane DCSMachineTemplate) следует настраивать отдельно. Инструкции см. в Infrastructure Resources for Huawei DCS.

    Если какой-либо диск должен сохраняться при rolling replacement, укажите его в соответствующей записи DCSIpHostnamePool.spec.pool[].persistentDisk. Это относится и к требуемому платформой диску /var/cpaas. Provider создает новые persistent volumes как независимые persistent normal volumes. Когда в среде DCS требуется явная настройка thin-provisioning, задайте persistentDisk[].isThin; если опустить это поле, provider не отправит isThin, и DCS будет использовать значение по умолчанию платформы.

    Если кластеру нужны дополнительные NIC, укажите их в DCSIpHostnamePool.spec.pool[].additionNic[] до создания соответствующих Machines. Provider применяет дополнительные NIC только при создании новой VM. Уже существующие VM не получают hot-added NIC после последующего изменения Pool.

    Разрешение значений-заполнителей

    В примерах manifests ниже используется синтаксис <placeholder> для значений, зависящих от среды. У нескольких из них есть канонический источник истины, который следует запрашивать, а не подставлять вручную:

    PlaceholderSource of truthHow to retrieve
    <control-plane-kubernetes-version> / <worker-kubernetes-version>ConfigMap cpaas.io/dcs-vm-template в namespace cpaas-system, по одному на каждую версию distribution.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)Значение метки cpaas.io/dcs-vm-template у ConfigMap (должно совпадать с именем VM template, зарегистрированным в платформе DCS).Тот же запрос kubectl get cm — прочитайте метку.
    <base64-encoded-secret> в encryption-provider.confГенерируется локально; рассматривайте его как настоящий secret кластера.head -c 32 /dev/urandom | base64 — храните безопасно и повторно используйте во всех control-plane replicas одного кластера.
    <ssh-authorized-keys>Задает оператор. Каждая запись представляет собой public key в формате OpenSSH, размещенный в одной строке (ssh-ed25519 AAAA… / ssh-rsa AAAA…). Поле требуется валидатором ignition и не должно быть пустым. Для test- или PoC-кластеров, которым не нужен интерактивный SSH, укажите любой синтаксически корректный public key (matching private key хранить не требуется); для production используйте signing key команды операторов.n/a — генерируется или предоставляется оператором.
    <auth-secret-name>Secret, созданный вами в Infrastructure → Cloud Credentials.kubectl -n cpaas-system get secret <name>
    <cluster-name>Выбирается оператором; должен соответствовать DNS-1123 и не должен быть global (это имя зарезервировано для кластера global). Повторно используется в Cluster, DCSCluster и метке cluster.x-k8s.io/cluster-name на каждом Machine. KubeadmControlPlane использует форму с префиксом <cluster-name>-kcp. Полное соглашение см. в Workload Cluster Naming.n/a
    <load-balancer-ip-or-domain-name>Задает оператор: IP / hostname, который клиенты используют для доступа к API server кластера. Для кластеров с одним control-plane и без внешнего LB это IP единственного master-узла (см. Single-control-plane layout).n/a
    <pods-cidr> / <services-cidr> / <kube-ovn-join-cidr>Задает оператор. Не должно пересекаться с host network, CIDR кластера global или CIDR любого другого CAPI-кластера, который вы планируете связать между собой. Если оставить эти значения пустыми, будут использованы значения kube-ovn по умолчанию, поставляемые с кластером global, что не рекомендуется для production: явные CIDR помогают избежать скрытых конфликтов, когда несколько workload cluster размещены в одном кластере global.n/a

    Заменители Magic Token

    Некоторые значения в примерах manifests выглядят как заполнители, но на самом деле являются буквальными токенами, подставляемыми DCS Provider во время присоединения машины к кластеру. Оставляйте их ровно в том виде, в каком они написаны:

    Literal tokenMeaningSubstituted by
    PROVIDER_IDProvider ID для каждой Machine (например, dcs://<dcsmachine-name>).DCS Provider — перезаписывается в сгенерированной конфигурации kubelet до запуска kubeadm init / kubeadm join.
    NODE_IPIP узла, выделенный из записи DCSIpHostnamePool, привязанной к этой Machine.DCS Provider — перезаписывается значением DCSIpHostnamePool.spec.pool[].ip.

    Ручная замена или заключение этих токенов в кавычки нарушает процесс join и приводит к тому, что узлы так и не регистрируются в control plane.

    Планирование сети и Load Balancer

    Перед созданием ресурсов control plane спланируйте сетевую архитектуру и разверните load balancer для обеспечения высокой доступности.

    Требования:

    • Сегментация сети: спланируйте диапазоны IP-адресов для узлов control plane
    • Дополнительные NIC: если узлам требуются storage-, management- или изолированные application-сети, спланируйте значения DCSIpHostnamePool.spec.pool[].additionNic[] для каждого IP slot, включая имена DVS и Port Group
    • Load balancer: разверните и настройте доступ к API server
    • Адрес API server: подготовьте стабильный VIP или адрес load balancer для Kubernetes API Server
    • Подключение: убедитесь в сетевой связности между всеми компонентами

    Настройка KubeadmControlPlane

    Ресурс KubeadmControlPlane определяет конфигурацию control plane, включая версию Kubernetes, спецификации узлов и параметры bootstrap.

    TIP

    Полная справка по конфигурации

    В приведенном ниже примере длинные конфигурационные файлы сокращены для удобства чтения. Для полной конфигурации (включая политики аудита по умолчанию, admission controls и содержимое файлов) см. Complete KubeadmControlPlane Configuration в Appendix.

    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.kubeadmConfigSpecobjectПараметры запуска bootstrap provider kubeadmYes
    .spec.machineTemplate.infrastructureRefobjectСсылка на DCSMachineTemplateYes
    .spec.replicasintКоличество replicas control plane. Должно удовлетворять 1 ≤ replicas ≤ IP Pool size. Установите 1 для development / PoC-развертываний с одним control-plane (см. Single-control-plane layout). В production обычно используется 3 для HA.Yes
    .spec.versionstringВерсия Kubernetes (должна совпадать с VM template — см. Resolving Placeholder Values)Yes

    Для версий компонентов (например, <dns-image-tag>, <etcd-image-tag>) см. OS Support Matrix.

    Настройка DCSCluster

    DCSCluster — это объявление инфраструктурного кластера, которое ссылается на load balancer и учетные данные платформы 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
      # Optional. Enable only when the target DCS compute cluster has DRS enabled.
      controlPlaneHA:
        enabled: true
      networkType: kube-ovn
      site: <site>

    Описание параметров:

    ПараметрТипОписаниеОбязательно
    .spec.controlPlaneLoadBalancerobjectСпособ публикации API server control planeYes
    .spec.controlPlaneLoadBalancer.typestringВ настоящее время поддерживается только "external"Yes
    .spec.controlPlaneLoadBalancer.hoststringIP или доменное имя load balancerYes
    .spec.credentialSecretRef.namestringИмя Secret для аутентификации в DCS. Secret определяет, выполняет ли DCS Provider аутентификацию как user interconnection интерфейса (по умолчанию) или как domain user — см. Credential User Types.Yes
    .spec.controlPlaneHA.enabledboolВключает управляемое provider правило взаимного исключения DCS DRS для VM control plane. Устанавливайте true только если целевой вычислительный кластер DCS имеет включенный DRS и достаточное количество hosts и capacity для размещения на разных host.No
    .spec.networkTypestringВ настоящее время поддерживается только "kube-ovn"Yes
    .spec.sitestringИдентификатор site платформы DCSYes

    controlPlaneHA является необязательным. При включении provider создает и поддерживает одно правило взаимного исключения DRS ruleType=2 для текущих VM control plane в этом workload cluster. Фактическое размещение и runtime migration выполняет DCS. Provider не запускает DRS и не применяет рекомендации DRS. Если правило поддерживается, но размещение не стабилизировалось, дождитесь механизма планирования DCS или запустите/apply DRS со стороны платформы DCS. Предварительные требования к инфраструктуре см. в разделе Cross-Host High Availability for Control Plane.

    Single-Control-Plane (No External LB) Layout

    Для development, PoC или любого развертывания, где у control plane только одна replica (KubeadmControlPlane.spec.replicas: 1), у вас нет настоящего load balancer перед API server. Тем не менее, двум полям все равно нужно задать значение:

    • .spec.controlPlaneLoadBalancer.host и .spec.controlPlaneEndpoint.host — задайте оба в качестве IP единственного master-узла (того же IP, который выделен master-узлу в DCSIpHostnamePool для control plane).
    • .spec.controlPlaneLoadBalancer.type — оставьте значение external (для этого поля не поддерживается другое значение).

    Конкретно:

    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. Для production используйте replicas: 3 с настоящим load balancer.

    Настройка Cluster

    Ресурс Cluster объявляет кластер и ссылается на ресурсы control plane и инфраструктуры.

    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[]stringCIDR для Pod. В схеме CAPI это поле необязательно, но рекомендуется задавать его явно, чтобы несколько кластеров CAPI могли сосуществовать без пересечений. Если не задано, kube-ovn использует значение по умолчанию, которое может конфликтовать с другим кластером в том же global.Рекомендуется
    .spec.clusterNetwork.services.cidrBlocks[]stringCIDR для Service. Та же рекомендация, что и для CIDR Pod — задавайте явно, чтобы избежать конфликтов между кластерами.Рекомендуется
    .spec.controlPlaneRefobjectСсылка на control planeYes
    .spec.infrastructureRefobjectСсылка на инфраструктурный кластерYes

    Аннотации Cluster:

    В примере выше показаны три аннотации, но полный ресурс Cluster содержит еще несколько. В таблице ниже перечислены аннотации, которые задают авторы operator (некоторые другие записываются ACP controllers, и заранее задавать их не следует):

    AnnotationRequiredValue sourcePurpose
    capi.cpaas.io/resource-group-versionYesLiteral infrastructure.cluster.x-k8s.io/v1beta1Указывает CAPI infrastructure binding, какой API group использовать.
    capi.cpaas.io/resource-kindYesLiteral DCSClusterУказывает CAPI infrastructure binding, к какому kind выполнять bind.
    cpaas.io/kubernetesYesТо же значение, что у KubeadmControlPlane.spec.version и MachineDeployment.spec.template.spec.version.Отображаемая метка, а также используется некоторыми инструментами обновления и инвентаризации. Источник истины — kubernetesVersion в ConfigMap cpaas.io/dcs-vm-template.
    cpaas.io/kube-ovn-join-cidrYesВыбранный оператором CIDR /16, не должен пересекаться с pod/service CIDR или с join CIDR любого другого кластера.Сетевая сеть межузлового туннеля Kube-OVN.
    cpaas.io/kube-ovn-versionYesВерсия kube-ovn, поставляемая с кластером global. Прочитайте ее из аннотации cpaas.io/kube-ovn-version у CAPI Cluster global (kubectl get cluster global -n cpaas-system -o jsonpath='{.metadata.annotations.cpaas\.io/kube-ovn-version}'). То же значение присутствует на каждом исправно работающем workload cluster в том же global, поэтому его можно прочитать и оттуда, если они существуют.Фиксирует версию kube-ovn, устанавливаемую в workload cluster.
    cpaas.io/registry-addressYesImage registry, который использует кластер global (обычно <registry-host>:11443). Прочитайте его из аннотации cpaas.io/registry-address у CAPI Cluster global (kubectl get cluster global -n cpaas-system -o jsonpath='{.metadata.annotations.cpaas\.io/registry-address}').Workload cluster получает platform images (CoreDNS, kube-proxy, kube-ovn) из этого registry.
    cpaas.io/nodes-modeYesLiteral self-managed для кластеров, которые развертывает DCS Provider.Помечает кластер как такой, жизненный цикл узлов которого управляется CAPI + данным provider.

    ACP controllers могут записывать дополнительные аннотации только для чтения (cpaas.io/cpu-cores-number, cpaas.io/memories, cpaas.io/nodes-number и т. п.) после запуска кластера — они вычисляются автоматически и не должны быть заранее заданы в применяемом YAML.

    Развертывание узлов

    Инструкции по развертыванию worker-узлов см. в разделе Managing Nodes on Huawei DCS.


    Проверка кластера

    После развертывания всех ресурсов кластера убедитесь, что кластер успешно создан и функционирует.

    Использование Console

    1. Перейдите в ClustersClusters
    2. Найдите недавно созданный кластер в списке кластеров
    3. Убедитесь, что состояние кластера отображается как Running
    4. Проверьте, что все узлы control plane и 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}'

    Проверка HA control plane

    Если вы включили DCSCluster.spec.controlPlaneHA.enabled, сначала проверьте condition DCSCluster:

    kubectl get dcscluster <cluster-name> -n cpaas-system \
      -o jsonpath='{range .status.conditions[?(@.type=="ControlPlaneHAReady")]}{.status}{" "}{.reason}{" "}{.message}{"\n"}{end}'

    Интерпретируйте condition следующим образом:

    Status and reasonMeaningNext step
    True ControlPlaneHAReadyПравило DRS, управляемое provider, существует, и provider обнаружил текущие VM control plane на разных DCS hosts.Действия не требуются.
    False ControlPlaneHAPendingProvider ожидает состояния, которое можно восстановить, например достаточного числа VM URN, достаточного числа members или размещения на стороне DCS.Прочитайте сообщение. Если в нем указано размещение, проверьте capacity DCS host, состояние DRS и не блокируется ли runtime migration.
    False ControlPlaneHAFailedProvider не смог выполнить запрос, проверку, создание, обновление, удаление или проверку правила DRS.Прочитайте сообщение, затем при необходимости проверьте DCS credential, настройки DRS, конфликты имен правил и логи controller.

    Проверьте наблюдаемое состояние правила и снимок membership:

    kubectl get dcscluster <cluster-name> -n cpaas-system \
      -o jsonpath='rule={.status.controlPlaneHA.ruleName}{" index="}{.status.controlPlaneHA.ruleIndex}{" cluster="}{.status.controlPlaneHA.clusterUrn}{"\n"}{range .status.controlPlaneHA.members[*]}{.machineName}{" "}{.vmUrn}{"\n"}{end}'

    Список members[] содержит имя CAPI Machine и DCS VM URN для каждой VM control plane в правиле. Текущий снимок состояния DCS не включает имя DCS host. Если вам нужно подтвердить точное размещение на host, запросите сведения о VM на платформе DCS или через DCS API и сравните значения hostName или hostUrn у VM.

    Ожидаемые результаты

    Успешно созданный кластер должен показывать:

    • состояние кластера: Running или Provisioned
    • все машины control plane: Running
    • все worker-узлы (если развернуты): Running
    • узлы Kubernetes: Ready
    • Cluster Module Status: Completed
    • для multi-NIC кластеров каждая созданная VM имеет ожидаемые дополнительные NIC в DCSMachine.status.additionalNic, а гостевая ОС показывает соответствующие интерфейсы ethN.

    Приложение

    Полная конфигурация KubeadmControlPlane

    Ниже приведена полная конфигурация KubeadmControlPlane, включая все политики аудита по умолчанию, admission controls и содержимое файлов.

    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 поставляет Secret с именем dcs-kubernetes-<kubernetes-major-minor>-files в namespace cpaas-system (например, dcs-kubernetes-1.33-files для Kubernetes 1.33). Он содержит каноническое содержимое psa-config.yaml, control-plane-kubelet-patch.json и audit-policy.yaml, и обновляется вместе с каждым релизом.

    Если этот Secret присутствует, вы можете заменить три встроенные записи files ссылками contentFrom.secret. Встроенная форма и форма со ссылкой на Secret функционально эквивалентны; использование Secret позволяет синхронизировать содержимое файлов с установленной версией плагина и избежать ручных обновлений при upgrade кластера.

    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>), либо полностью исключить встроенный файл и использовать версию, уже включенную в образ VM template DCS — оба варианта допустимы; второй проще, когда значение ключа по умолчанию в VM template подходит для вашей среды.

    Минимальная версия плагина: этот 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 — например, worker-узлы остаются в состоянии NotReady, потому что CNI не развернут — см. Troubleshoot a Workload Cluster Stuck in Provisioned.