documentation.suse.com / Documentação do SUSE Edge / Guias de procedimentos / Usando clusterclass para implantar clusters downstream

29 Usando clusterclass para implantar clusters downstream

29.1 Introdução

O provisionamento de clusters Kubernetes é uma tarefa complexa que demanda profunda experiência na configuração de componentes de cluster. À medida que as configurações se tornam cada vez mais complexas, ou as demandas de diversos provedores geram inúmeras definições de recursos específicas do provedor, a criação de clusters pode ser um processo assustador. Felizmente, a Kubernetes Cluster API (CAPI) oferece uma abordagem declarativa e mais refinada que é aprimorada pelo ClusterClass. Esse recurso apresenta um modelo orientado por gabarito que permite definir uma classe de cluster reutilizável que encapsula a complexidade e promove a consistência.

29.2 O que é ClusterClass?

O projeto CAPI lançou o recurso ClusterClass como uma mudança de paradigma no gerenciamento do ciclo de vida de clusters Kubernetes por meio da adoção de uma metodologia baseada em gabarito para criação de instâncias de cluster. Em vez de definir recursos separadamente para cada cluster, os usuários definem um ClusterClass, que serve como um diagrama de referência abrangente e reutilizável. Essa representação abstrata encapsula o estado e a configuração desejados de um cluster Kubernetes, o que permite a criação rápida e consistente de vários clusters que seguem as especificações definidas. Essa abstração reduz a sobrecarga de configuração, resultando em manifestos de implantação mais gerenciáveis. Isso significa que os componentes principais de um cluster de carga de trabalho são definidos no nível da classe, permitindo que os usuários recorram a esses gabaritos como variantes de cluster Kubernetes que podem ser reutilizadas uma ou várias vezes para provisionamento de clusters. A implementação do ClusterClass oferece diversas vantagens importantes que abordam os desafios inerentes ao gerenciamento tradicional da CAPI em escala:

  • Redução significativa na complexidade e detalhamento do YAML

  • Processos otimizados de manutenção e atualização

  • Consistência e padronização aprimoradas nas implantações

  • Escalabilidade e recursos de automação aprimorados

  • Gerenciamento declarativo e controle de versão robusto

clusterclass

29.3 Exemplo de arquivo de provisionamento da CAPI atual

A implantação de um cluster Kubernetes por meio do provedor Cluster API (CAPI) e RKE2 requer a definição de vários recursos personalizados. Esses recursos definem o estado desejado do cluster e sua infraestrutura subjacente, o que permite à CAPI orquestrar o provisionamento e o ciclo de vida de gerenciamento. O trecho do código a seguir ilustra os tipos de recursos que devem ser configurados:

  • Cluster: esse recurso encapsula as configurações de alto nível, incluindo a topologia de rede que controla a comunicação entre os nós e a descoberta de serviços. Ele também estabelece vínculos essenciais com a especificação do plano de controle e o recurso do provedor de infraestrutura designado e, desse modo, informa a CAPI sobre a arquitetura desejada do cluster e a infraestrutura subjacente na qual ele deverá ser provisionado.

  • Metal3Cluster: esse recurso define os atributos no nível da infraestrutura exclusivos do Metal3, por exemplo, o endpoint externo pelo qual o servidor da API Kubernetes estará acessível.

  • RKE2ControlPlane: esse recurso define as características e o comportamento dos nós do plano de controle do cluster. Nessa especificação, os parâmetros, como o número desejado de réplicas do plano de controle (essencial para garantir alta disponibilidade e tolerância a falhas), a versão da distribuição Kubernetes específica (alinhada à versão do RKE2 selecionada) e a estratégia de distribuição das atualizações para os componentes do plano de controle são configurados. Além disso, esse recurso determina a interface de rede de contêiner (CNI, Container Network Interface) que será usada dentro do cluster e facilita a injeção das configurações específicas do agente, em geral aproveitando o Ignition para provisionamento contínuo e automatizado dos agentes do RKE2 nos nós do plano de controle.

  • Metal3MachineTemplate: esse recurso funciona como um diagrama de referência para criação das instâncias de computação individuais que formam os nós do worker do cluster Kubernetes definindo a imagem que será usada.

  • Metal3DataTemplate: como complemento ao Metal3MachineTemplate, o recurso Metal3DataTemplate permite especificar metadados adicionais para instâncias de máquina recém-provisionadas.

---
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
  name: emea-spa-cluster-3
  namespace: emea-spa
spec:
  clusterNetwork:
    pods:
      cidrBlocks:
        - 192.168.0.0/18
    services:
      cidrBlocks:
        - 10.96.0.0/12
  controlPlaneRef:
    apiVersion: controlplane.cluster.x-k8s.io/v1beta1
    kind: RKE2ControlPlane
    name: emea-spa-cluster-3
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
    kind: Metal3Cluster
    name: emea-spa-cluster-3
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3Cluster
metadata:
  name: emea-spa-cluster-3
  namespace: emea-spa
spec:
  controlPlaneEndpoint:
    host: 192.168.122.203
    port: 6443
  noCloudProvider: true
---
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: RKE2ControlPlane
metadata:
  name: emea-spa-cluster-3
  namespace: emea-spa
spec:
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
    kind: Metal3MachineTemplate
    name: emea-spa-cluster-3
  replicas: 1
  version: v1.32.4+rke2r1
  rolloutStrategy:
    type: "RollingUpdate"
    rollingUpdate:
      maxSurge: 1
  registrationMethod: "control-plane-endpoint"
  registrationAddress: 192.168.122.203
  serverConfig:
    cni: cilium
    cniMultusEnable: true
    tlsSan:
      - 192.168.122.203
      - https://192.168.122.203.sslip.io
  agentConfig:
    format: ignition
    additionalUserData:
      config: |
        variant: fcos
        version: 1.4.0
        storage:
          files:
            - path: /var/lib/rancher/rke2/server/manifests/endpoint-copier-operator.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: helm.cattle.io/v1
                  kind: HelmChart
                  metadata:
                    name: endpoint-copier-operator
                    namespace: kube-system
                  spec:
                    chart: oci://registry.suse.com/edge/charts/endpoint-copier-operator
                    targetNamespace: endpoint-copier-operator
                    version: 303.0.0+up0.2.1
                    createNamespace: true
            - path: /var/lib/rancher/rke2/server/manifests/metallb.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: helm.cattle.io/v1
                  kind: HelmChart
                  metadata:
                    name: metallb
                    namespace: kube-system
                  spec:
                    chart: oci://registry.suse.com/edge/charts/metallb
                    targetNamespace: metallb-system
                    version: 303.0.0+up0.14.9
                    createNamespace: true

            - path: /var/lib/rancher/rke2/server/manifests/metallb-cr.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: metallb.io/v1beta1
                  kind: IPAddressPool
                  metadata:
                    name: kubernetes-vip-ip-pool
                    namespace: metallb-system
                  spec:
                    addresses:
                      - 192.168.122.203/32
                    serviceAllocation:
                      priority: 100
                      namespaces:
                        - default
                      serviceSelectors:
                        - matchExpressions:
                          - {key: "serviceType", operator: In, values: [kubernetes-vip]}
                  ---
                  apiVersion: metallb.io/v1beta1
                  kind: L2Advertisement
                  metadata:
                    name: ip-pool-l2-adv
                    namespace: metallb-system
                  spec:
                    ipAddressPools:
                      - kubernetes-vip-ip-pool
            - path: /var/lib/rancher/rke2/server/manifests/endpoint-svc.yaml
              overwrite: true
              contents:
                inline: |
                  apiVersion: v1
                  kind: Service
                  metadata:
                    name: kubernetes-vip
                    namespace: default
                    labels:
                      serviceType: kubernetes-vip
                  spec:
                    ports:
                    - name: rke2-api
                      port: 9345
                      protocol: TCP
                      targetPort: 9345
                    - name: k8s-api
                      port: 6443
                      protocol: TCP
                      targetPort: 6443
                    type: LoadBalancer
        systemd:
          units:
            - name: rke2-preinstall.service
              enabled: true
              contents: |
                [Unit]
                Description=rke2-preinstall
                Wants=network-online.target
                Before=rke2-install.service
                ConditionPathExists=!/run/cluster-api/bootstrap-success.complete
                [Service]
                Type=oneshot
                User=root
                ExecStartPre=/bin/sh -c "mount -L config-2 /mnt"
                ExecStart=/bin/sh -c "sed -i \"s/BAREMETALHOST_UUID/$(jq -r .uuid /mnt/openstack/latest/meta_data.json)/\" /etc/rancher/rke2/config.yaml"
                ExecStart=/bin/sh -c "echo \"node-name: $(jq -r .name /mnt/openstack/latest/meta_data.json)\" >> /etc/rancher/rke2/config.yaml"
                ExecStartPost=/bin/sh -c "umount /mnt"
                [Install]
                WantedBy=multi-user.target
    kubelet:
      extraArgs:
        - provider-id=metal3://BAREMETALHOST_UUID
    nodeName: "localhost.localdomain"
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3MachineTemplate
metadata:
  name: emea-spa-cluster-3
  namespace: emea-spa
spec:
  nodeReuse: True
  template:
    spec:
      automatedCleaningMode: metadata
      dataTemplate:
        name: emea-spa-cluster-3
      hostSelector:
        matchLabels:
          cluster-role: control-plane
          deploy-region: emea-spa
          node: group-3
      image:
        checksum: http://fileserver.local:8080/eibimage-downstream-cluster.raw.sha256
        checksumType: sha256
        format: raw
        url: http://fileserver.local:8080/eibimage-downstream-cluster.raw
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3DataTemplate
metadata:
  name: emea-spa-cluster-3
  namespace: emea-spa
spec:
  clusterName: emea-spa-cluster-3
  metaData:
    objectNames:
      - key: name
        object: machine
      - key: local-hostname
        object: machine
      - key: local_hostname
        object: machine

29.4 Transformando o arquivo de provisionamento da CAPI em ClusterClass

29.4.1 Definição do ClusterClass

O código a seguir define o recurso ClusterClass, um gabarito declarativo para implantação consistente de um tipo específico de cluster Kubernetes. Essa especificação inclui as configurações comuns de infraestrutura e de plano de controle, o que permite o provisionamento eficiente e o gerenciamento do ciclo de vida uniforme de toda a frota de clusters. Há algumas variáveis no exemplo abaixo do clusterclass que serão substituídas pelos valores reais durante o processo de criação de instância do cluster. As seguintes variáveis são usadas no exemplo:

  • controlPlaneMachineTemplate: esse é o nome para definir a referência de gabarito da máquina do ControlPlane que será usada

  • controlPlaneEndpointHost: esse é o nome de host ou endereço IP do endpoint do plano de controle

  • tlsSan: esse é o nome alternativo da entidade TLS para o endpoint do plano de controle

O arquivo de definição de clusterclass é definido com base nos três recursos a seguir:

  • ClusterClass: esse recurso encapsula a definição da classe do cluster inteira, incluindo os gabaritos de plano de controle e de infraestrutura. Além disso, ele inclui a lista das variáveis que serão substituídas durante o processo de criação de instâncias.

  • RKE2ControlPlaneTemplate: esse recurso define o gabarito do plano de controle, especificando a configuração desejada para os nós do plano de controle. Ele inclui os parâmetros, como número de réplicas, versão do Kubernetes e CNI, que serão usados. Alguns parâmetros também serão substituídos pelos valores corretos durante o processo de criação de instâncias.

  • Metal3ClusterTemplate: esse recurso define o gabarito de infraestrutura, especificando a configuração desejada da infraestrutura subjacente. Ele inclui parâmetros, como o endpoint do plano de controle e o sinalizador noCloudProvider. Alguns parâmetros também serão substituídos pelos valores corretos durante o processo de criação de instâncias.

apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: RKE2ControlPlaneTemplate
metadata:
  name: example-controlplane-type2
  namespace: emea-spa
spec:
  template:
    spec:
      infrastructureRef:
        apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
        kind: Metal3MachineTemplate
        name: example-controlplane    # This will be replaced by the patch applied in each cluster instances
        namespace: emea-spa
      replicas: 1
      version: v1.32.4+rke2r1
      rolloutStrategy:
        type: "RollingUpdate"
        rollingUpdate:
          maxSurge: 1
      registrationMethod: "control-plane-endpoint"
      registrationAddress: "default"  # This will be replaced by the patch applied in each cluster instances
      serverConfig:
        cni: cilium
        cniMultusEnable: true
        tlsSan:
          - "default"  # This will be replaced by the patch applied in each cluster instances
      agentConfig:
        format: ignition
        additionalUserData:
          config: |
            default
        kubelet:
          extraArgs:
            - provider-id=metal3://BAREMETALHOST_UUID
        nodeName: "localhost.localdomain"
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3ClusterTemplate
metadata:
  name: example-cluster-template-type2
  namespace: emea-spa
spec:
  template:
    spec:
      controlPlaneEndpoint:
        host: "default"  # This will be replaced by the patch applied in each cluster instances
        port: 6443
      noCloudProvider: true
---
apiVersion: cluster.x-k8s.io/v1beta1
kind: ClusterClass
metadata:
  name: example-clusterclass-type2
  namespace: emea-spa
spec:
  variables:
    - name: controlPlaneMachineTemplate
      required: true
      schema:
        openAPIV3Schema:
          type: string
    - name: controlPlaneEndpointHost
      required: true
      schema:
        openAPIV3Schema:
          type: string
    - name: tlsSan
      required: true
      schema:
        openAPIV3Schema:
          type: array
          items:
            type: string
  infrastructure:
    ref:
      kind: Metal3ClusterTemplate
      apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
      name: example-cluster-template-type2
  controlPlane:
    ref:
      kind: RKE2ControlPlaneTemplate
      apiVersion: controlplane.cluster.x-k8s.io/v1beta1
      name: example-controlplane-type2
  patches:
    - name: setControlPlaneMachineTemplate
      definitions:
        - selector:
            apiVersion: controlplane.cluster.x-k8s.io/v1beta1
            kind: RKE2ControlPlaneTemplate
            matchResources:
              controlPlane: true
          jsonPatches:
            - op: replace
              path: "/spec/template/spec/infrastructureRef/name"
              valueFrom:
                variable: controlPlaneMachineTemplate
    - name: setControlPlaneEndpoint
      definitions:
        - selector:
            apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
            kind: Metal3ClusterTemplate
            matchResources:
              infrastructureCluster: true  # Added to select InfraCluster
          jsonPatches:
            - op: replace
              path: "/spec/template/spec/controlPlaneEndpoint/host"
              valueFrom:
                variable: controlPlaneEndpointHost
    - name: setRegistrationAddress
      definitions:
        - selector:
            apiVersion: controlplane.cluster.x-k8s.io/v1beta1
            kind: RKE2ControlPlaneTemplate
            matchResources:
              controlPlane: true  # Added to select ControlPlane
          jsonPatches:
            - op: replace
              path: "/spec/template/spec/registrationAddress"
              valueFrom:
                variable: controlPlaneEndpointHost
    - name: setTlsSan
      definitions:
        - selector:
            apiVersion: controlplane.cluster.x-k8s.io/v1beta1
            kind: RKE2ControlPlaneTemplate
            matchResources:
              controlPlane: true  # Added to select ControlPlane
          jsonPatches:
            - op: replace
              path: "/spec/template/spec/serverConfig/tlsSan"
              valueFrom:
                variable: tlsSan
    - name: updateAdditionalUserData
      definitions:
        - selector:
            apiVersion: controlplane.cluster.x-k8s.io/v1beta1
            kind: RKE2ControlPlaneTemplate
            matchResources:
              controlPlane: true
          jsonPatches:
            - op: replace
              path: "/spec/template/spec/agentConfig/additionalUserData"
              valueFrom:
                template: |
                  config: |
                    variant: fcos
                    version: 1.4.0
                    storage:
                      files:
                        - path: /var/lib/rancher/rke2/server/manifests/endpoint-copier-operator.yaml
                          overwrite: true
                          contents:
                            inline: |
                              apiVersion: helm.cattle.io/v1
                              kind: HelmChart
                              metadata:
                                name: endpoint-copier-operator
                                namespace: kube-system
                              spec:
                                chart: oci://registry.suse.com/edge/charts/endpoint-copier-operator
                                targetNamespace: endpoint-copier-operator
                                version: 303.0.0+up0.2.1
                                createNamespace: true
                        - path: /var/lib/rancher/rke2/server/manifests/metallb.yaml
                          overwrite: true
                          contents:
                            inline: |
                              apiVersion: helm.cattle.io/v1
                              kind: HelmChart
                              metadata:
                                name: metallb
                                namespace: kube-system
                              spec:
                                chart: oci://registry.suse.com/edge/charts/metallb
                                targetNamespace: metallb-system
                                version: 303.0.0+up0.14.9
                                createNamespace: true
                        - path: /var/lib/rancher/rke2/server/manifests/metallb-cr.yaml
                          overwrite: true
                          contents:
                            inline: |
                              apiVersion: metallb.io/v1beta1
                              kind: IPAddressPool
                              metadata:
                                name: kubernetes-vip-ip-pool
                                namespace: metallb-system
                              spec:
                                addresses:
                                  - {{ .controlPlaneEndpointHost }}/32
                                serviceAllocation:
                                  priority: 100
                                  namespaces:
                                    - default
                                  serviceSelectors:
                                    - matchExpressions:
                                      - {key: "serviceType", operator: In, values: [kubernetes-vip]}
                              ---
                              apiVersion: metallb.io/v1beta1
                              kind: L2Advertisement
                              metadata:
                                name: ip-pool-l2-adv
                                namespace: metallb-system
                              spec:
                                ipAddressPools:
                                  - kubernetes-vip-ip-pool
                        - path: /var/lib/rancher/rke2/server/manifests/endpoint-svc.yaml
                          overwrite: true
                          contents:
                            inline: |
                              apiVersion: v1
                              kind: Service
                              metadata:
                                name: kubernetes-vip
                                namespace: default
                                labels:
                                  serviceType: kubernetes-vip
                              spec:
                                ports:
                                - name: rke2-api
                                  port: 9345
                                  protocol: TCP
                                  targetPort: 9345
                                - name: k8s-api
                                  port: 6443
                                  protocol: TCP
                                  targetPort: 6443
                                type: LoadBalancer
                    systemd:
                      units:
                        - name: rke2-preinstall.service
                          enabled: true
                          contents: |
                            [Unit]
                            Description=rke2-preinstall
                            Wants=network-online.target
                            Before=rke2-install.service
                            ConditionPathExists=!/run/cluster-api/bootstrap-success.complete
                            [Service]
                            Type=oneshot
                            User=root
                            ExecStartPre=/bin/sh -c "mount -L config-2 /mnt"
                            ExecStart=/bin/sh -c "sed -i \"s/BAREMETALHOST_UUID/$(jq -r .uuid /mnt/openstack/latest/meta_data.json)/\" /etc/rancher/rke2/config.yaml"
                            ExecStart=/bin/sh -c "echo \"node-name: $(jq -r .name /mnt/openstack/latest/meta_data.json)\" >> /etc/rancher/rke2/config.yaml"
                            ExecStartPost=/bin/sh -c "umount /mnt"
                            [Install]
                            WantedBy=multi-user.target

29.4.2 Definição da instância do cluster

No contexto do ClusterClass, uma instância de cluster se refere à criação de instância em execução específica de um cluster que foi criado com base no ClusterClass definido. Isso representa a implantação concreta com suas configurações, recursos e estado operacional exclusivos, derivados diretamente do diagrama de referência especificado no ClusterClass. Isso inclui o conjunto específico de máquinas, as configurações de rede e os componentes associados do Kubernetes que estão ativamente em execução. Saber o que é uma instância de cluster é essencial para gerenciar o ciclo de vida, fazer upgrades, executar operações de ajuste de escala e monitorar um determinado cluster implantado que foi provisionado usando a estrutura do ClusterClass.

Para definir uma instância de cluster, precisamos definir os seguintes recursos:

  • Cluster

  • Metal3MachineTemplate

  • Metal3DataTemplate

As variáveis definidas no gabarito (arquivo de definição de clusterclass) serão substituídas pelos valores finais para esta criação de instância do cluster:

apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
  name: emea-spa-cluster-3
  namespace: emea-spa
spec:
  topology:
    class: example-clusterclass-type2  # Correct way to reference ClusterClass
    version: v1.32.4+rke2r1
    controlPlane:
      replicas: 1
    variables:                         # Variables to be replaced for this cluster instance
      - name: controlPlaneMachineTemplate
        value: emea-spa-cluster-3-machinetemplate
      - name: controlPlaneEndpointHost
        value: 192.168.122.203
      - name: tlsSan
        value:
          - 192.168.122.203
          - https://192.168.122.203.sslip.io
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3MachineTemplate
metadata:
  name: emea-spa-cluster-3-machinetemplate
  namespace: emea-spa
spec:
  nodeReuse: True
  template:
    spec:
      automatedCleaningMode: metadata
      dataTemplate:
        name: emea-spa-cluster-3
      hostSelector:
        matchLabels:
          cluster-role: control-plane
          deploy-region: emea-spa
          cluster-type: type2
      image:
        checksum: http://fileserver.local:8080/eibimage-downstream-cluster.raw.sha256
        checksumType: sha256
        format: raw
        url: http://fileserver.local:8080/eibimage-downstream-cluster.raw
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3DataTemplate
metadata:
  name: emea-spa-cluster-3
  namespace: emea-spa
spec:
  clusterName: emea-spa-cluster-3
  metaData:
    objectNames:
      - key: name
        object: machine
      - key: local-hostname
        object: machine

Essa abordagem permite um processo mais ágil, implantando um cluster com apenas três recursos assim que você define o clusterclass.

Documentation survey