documentation.suse.com / Documentação do SUSE Edge / Documentação do produto / Configurando o cluster de gerenciamento

40 Configurando o cluster de gerenciamento

40.1 Introdução

O cluster de gerenciamento é a parte do SUSE Edge for Telco usada para gerenciar o provisionamento e o ciclo de vida das pilhas de runtime. Do ponto de vista técnico, esse cluster contém os seguintes componentes:

  • SUSE Linux Micro como sistema operacional. Dependendo do caso de uso, é possível personalizar algumas configurações, como rede, armazenamento, usuários e argumentos do kernel.

  • RKE2 como cluster Kubernetes. Dependendo do caso de uso, é possível configurá-lo para usar plug-ins de CNI específicos, como Multus, Cilium, Calico etc.

  • Rancher como plataforma de gerenciamento para gerenciar o ciclo de vida dos clusters.

  • Metal3 como componente para gerenciar o ciclo de vida dos nós bare metal.

  • CAPI como componente para gerenciar o ciclo de vida dos clusters Kubernetes (downstream). O provedor CAPI RKE2 é usado para gerenciar o ciclo de vida dos clusters RKE2.

Com todos os componentes mencionados acima, o cluster de gerenciamento pode gerenciar o ciclo de vida dos clusters downstream, aplicando uma abordagem declarativa para gerenciar a infraestrutura e os aplicativos.

Nota
Nota

Para obter mais informações sobre o SUSE Linux Micro, consulte: SUSE Linux Micro (Capítulo 9, SUSE Linux Micro)

Para obter mais informações sobre o RKE2, consulte: RKE2 (Capítulo 16, RKE2)

Para obter mais informações sobre o Rancher, consulte: Rancher (Capítulo 5, Rancher)

Para obter mais informações sobre o Metal3, consulte: Metal3 (Capítulo 10, Metal3)

40.2 Etapas para configurar o cluster de gerenciamento

As seguintes etapas são necessárias para configurar o cluster de gerenciamento (de nó único):

clustergrcmt1 produto atip

Veja a seguir as etapas principais para configurar o cluster de gerenciamento com uma abordagem declarativa:

  1. Preparação da imagem para ambientes conectados (Seção 40.3, “Preparação da imagem para ambientes conectados”): a primeira etapa é preparar o manifesto e os arquivos com todas as configurações necessárias aos ambientes conectados.

    • Estrutura de diretórios para ambientes conectados (Seção 40.3.1, “Estrutura de diretórios”): esta etapa cria uma estrutura de diretórios que o Edge Image Builder usará para armazenar os arquivos de configuração e a própria imagem.

    • Arquivo de definição do cluster de gerenciamento (Seção 40.3.2, “Arquivo de definição do cluster de gerenciamento”): o mgmt-cluster.yaml é o principal arquivo de definição do cluster de gerenciamento. Ele inclui as seguintes informações sobre a imagem que será criada:

      • Informações da imagem: as informações relacionadas à imagem que será criada usando a imagem base.

      • Sistema operacional: a configuração do sistema operacional que será usada na imagem.

      • Kubernetes: repositórios e gráficos Helm, versão do kubernetes, configuração de rede e os nós que serão usados no cluster.

    • Pasta custom (Seção 40.3.3, “Pasta custom”): a pasta custom contém os arquivos de configuração e os scripts que o Edge Image Builder usará para implantar um cluster totalmente funcional.

      • Arquivos: contêm os arquivos de configuração que serão usados pelo cluster de gerenciamento.

      • Scripts: contêm os scripts que serão usados pelo cluster de gerenciamento.

    • Pasta kubernetes (Seção 40.3.4, “Pasta kubernetes”): a pasta kubernetes contém os arquivos de configuração que serão usados pelo cluster de gerenciamento.

      • Manifestos: contêm os manifestos que serão usados pelo cluster de gerenciamento.

      • Helm: contém os arquivos de valores do Helm que serão usados pelo cluster de gerenciamento.

      • Config: contém os arquivos de configuração que serão usados pelo cluster de gerenciamento.

    • Pasta network (Seção 40.3.5, “Pasta de rede”): a pasta network contém os arquivos de configuração de rede que serão usados pelos nós do cluster de gerenciamento.

  2. Preparação da imagem para ambientes air-gapped (Seção 40.4, “Preparação da imagem para ambientes air-gapped”): a etapa mostra as diferenças para preparar os manifestos e os arquivos que serão usados em um cenário air-gapped.

    • Modificações no arquivo de definição (Seção 40.4.1, “Modificações no arquivo de definição”): o arquivo mgmt-cluster.yaml deve ser modificado para incluir a seção embeddedArtifactRegistry com o campo images definido para que todas as imagens do contêiner sejam incluídas na imagem de saída do EIB.

    • Modificações na pasta custom (Seção 40.4.2, “Modificações na pasta custom”): a pasta custom deve ser modificada para incluir os recursos necessários para executar o cluster de gerenciamento em um ambiente air-gapped.

      • Script de registro: o script custom/scripts/99-register.sh deve ser removido quando você usa um ambiente air-gapped.

    • Modificações na pasta de valores do Helm (Seção 40.4.3, “Modificações na pasta de valores do Helm”): a pasta helm/values deve ser modificada para incluir a configuração necessária para executar o cluster de gerenciamento em um ambiente air-gapped.

  3. Criação da imagem (Seção 40.5, “Criação de imagem”): esta etapa abrange a criação da imagem com a ferramenta Edge Image Builder (para os cenários tanto conectados quanto air-gapped). Consulte os pré-requisitos (Capítulo 11, Edge Image Builder) para executar a ferramenta Edge Image Builder no seu sistema.

  4. Provisionamento do cluster de gerenciamento (Seção 40.6, “Provisionar o cluster de gerenciamento”): esta etapa aborda o provisionamento do cluster de gerenciamento usando a imagem criada na etapa anterior (para os cenários tanto conectados quanto air-gapped). Para executá-la, é possível usar um laptop, um servidor, uma VM ou qualquer outro sistema AMD64/Intel 64 com uma porta USB.

Nota
Nota

Para obter mais informações sobre o Edge Image Builder, consulte o respectivo guia (Capítulo 11, Edge Image Builder) e o Guia de Início Rápido (Capítulo 3, Clusters independentes com o Edge Image Builder).

40.3 Preparação da imagem para ambientes conectados

O Edge Image Builder é usado para criar a imagem do cluster de gerenciamento. Neste documento, explicamos a configuração mínima necessária para configurar o cluster de gerenciamento.

O Edge Image Builder é executado dentro de um contêiner, portanto, um tempo de execução do contêiner é necessário, como Podman ou Rancher Desktop. Neste guia, consideramos que o podman esteja disponível.

Também como pré-requisito para implantar um cluster de gerenciamento altamente disponível, você precisa reservar três IPs na sua rede:

  • apiVIP para o endereço VIP da API (usado para acessar o servidor da API Kubernetes).

  • ingressVIP para o endereço VIP de entrada (consumido pela IU do Rancher, por exemplo).

  • metal3VIP para o endereço VIP do Metal3.

40.3.1 Estrutura de diretórios

Ao executar o EIB, um diretório é montado do host, portanto, a primeira etapa é criar uma estrutura de diretórios para o EIB usar para armazenar os arquivos de configuração e a própria imagem. Esse diretório tem a seguinte estrutura:

eib
├── mgmt-cluster.yaml
├── network
│ └── mgmt-cluster-node1.yaml
├── kubernetes
│ ├── manifests
│ │ ├── rke2-ingress-config.yaml
│ │ ├── neuvector-namespace.yaml
│ │ ├── ingress-l2-adv.yaml
│ │ └── ingress-ippool.yaml
│ ├── helm
│ │ └── values
│ │     ├── rancher.yaml
│ │     ├── neuvector.yaml
│ │     ├── metal3.yaml
│ │     └── certmanager.yaml
│ └── config
│     └── server.yaml
├── custom
│ ├── scripts
│ │ ├── 99-register.sh
│ │ ├── 99-mgmt-setup.sh
│ │ └── 99-alias.sh
│ └── files
│     ├── rancher.sh
│     ├── mgmt-stack-setup.service
│     ├── metal3.sh
│     └── basic-setup.sh
└── base-images
Nota
Nota

É necessário fazer download da imagem SL-Micro.x86_64-6.1-Base-SelfInstall-GM.install.iso do SUSE Customer Center ou da página de downloads da SUSE e salvá-la na pasta base-images.

Confira o checksum SHA256 da imagem para garantir que ela não tenha sido adulterada. O checksum está no mesmo local em que a imagem foi baixada.

Há um exemplo da estrutura de diretórios disponível no repositório SUSE Edge do GitHub na pasta "telco-examples".

40.3.2 Arquivo de definição do cluster de gerenciamento

O mgmt-cluster.yaml é o principal arquivo de definição do cluster de gerenciamento. Ele contém as seguintes informações:

apiVersion: 1.2
image:
  imageType: iso
  arch: x86_64
  baseImage: SL-Micro.x86_64-6.1-Base-SelfInstall-GM.install.iso
  outputImageName: eib-mgmt-cluster-image.iso
operatingSystem:
  isoConfiguration:
    installDevice: /dev/sda
  users:
  - username: root
    encryptedPassword: $ROOT_PASSWORD
  packages:
    packageList:
    - git
    - jq
    sccRegistrationCode: $SCC_REGISTRATION_CODE
kubernetes:
  version: v1.32.4+rke2r1
  helm:
    charts:
      - name: cert-manager
        repositoryName: jetstack
        version: 1.15.3
        targetNamespace: cert-manager
        valuesFile: certmanager.yaml
        createNamespace: true
        installationNamespace: kube-system
      - name: longhorn-crd
        version: 106.2.0+up1.8.1
        repositoryName: rancher-charts
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
      - name: longhorn
        version: 106.2.0+up1.8.1
        repositoryName: rancher-charts
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
      - name: metal3
        version: 303.0.7+up0.11.5
        repositoryName: suse-edge-charts
        targetNamespace: metal3-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: metal3.yaml
      - name: rancher-turtles
        version: 303.0.4+up0.20.0
        repositoryName: suse-edge-charts
        targetNamespace: rancher-turtles-system
        createNamespace: true
        installationNamespace: kube-system
      - name: neuvector-crd
        version: 106.0.1+up2.8.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector.yaml
      - name: neuvector
        version: 106.0.1+up2.8.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector.yaml
      - name: rancher
        version: 2.11.2
        repositoryName: rancher-prime
        targetNamespace: cattle-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: rancher.yaml
    repositories:
      - name: jetstack
        url: https://charts.jetstack.io
      - name: rancher-charts
        url: https://charts.rancher.io/
      - name: suse-edge-charts
        url: oci://registry.suse.com/edge/charts
      - name: rancher-prime
        url: https://charts.rancher.com/server-charts/prime
  network:
    apiHost: $API_HOST
    apiVIP: $API_VIP
  nodes:
    - hostname: mgmt-cluster-node1
      initializer: true
      type: server
#   - hostname: mgmt-cluster-node2
#     type: server
#   - hostname: mgmt-cluster-node3
#     type: server

Para explicar os campos e os valores no arquivo de definição mgmt-cluster.yaml, dividimos esse arquivo nas seções a seguir.

  • Seção da imagem (arquivo de definição):

image:
  imageType: iso
  arch: x86_64
  baseImage: SL-Micro.x86_64-6.1-Base-SelfInstall-GM.install.iso
  outputImageName: eib-mgmt-cluster-image.iso

em que baseImage é a imagem original que você baixou do SUSE Customer Center ou da página de downloads da SUSE. outputImageName é o nome da nova imagem que será usada para provisionar o cluster de gerenciamento.

  • Seção do sistema operacional (arquivo de definição):

operatingSystem:
  isoConfiguration:
    installDevice: /dev/sda
  users:
  - username: root
    encryptedPassword: $ROOT_PASSWORD
  packages:
    packageList:
    - jq
    sccRegistrationCode: $SCC_REGISTRATION_CODE

em que installDevice é o dispositivo usado para instalar o sistema operacional, username e encryptedPassword são as credenciais usadas para acessar o sistema, packageList é a lista dos pacotes que devem ser instalados (jq é obrigatório internamente durante o processo de instalação) e sccRegistrationCode é o código de registro usado para obter os pacotes e as dependências no momento da criação e pode ser recuperado do SUSE Customer Center. É possível gerar a senha criptografada usando o comando openssl da seguinte maneira:

openssl passwd -6 MyPassword!123

A saída é similar a esta:

$6$UrXB1sAGs46DOiSq$HSwi9GFJLCorm0J53nF2Sq8YEoyINhHcObHzX2R8h13mswUIsMwzx4eUzn/rRx0QPV4JIb0eWCoNrxGiKH4R31
  • Seção do Kubernetes (arquivo de definição):

kubernetes:
  version: v1.32.4+rke2r1
  helm:
    charts:
      - name: cert-manager
        repositoryName: jetstack
        version: 1.15.3
        targetNamespace: cert-manager
        valuesFile: certmanager.yaml
        createNamespace: true
        installationNamespace: kube-system
      - name: longhorn-crd
        version: 106.2.0+up1.8.1
        repositoryName: rancher-charts
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
      - name: longhorn
        version: 106.2.0+up1.8.1
        repositoryName: rancher-charts
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
      - name: metal3
        version: 303.0.7+up0.11.5
        repositoryName: suse-edge-charts
        targetNamespace: metal3-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: metal3.yaml
      - name: rancher-turtles
        version: 303.0.4+up0.20.0
        repositoryName: suse-edge-charts
        targetNamespace: rancher-turtles-system
        createNamespace: true
        installationNamespace: kube-system
      - name: neuvector-crd
        version: 106.0.1+up2.8.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector.yaml
      - name: neuvector
        version: 106.0.1+up2.8.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector.yaml
      - name: rancher
        version: 2.11.2
        repositoryName: rancher-prime
        targetNamespace: cattle-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: rancher.yaml
    repositories:
      - name: jetstack
        url: https://charts.jetstack.io
      - name: rancher-charts
        url: https://charts.rancher.io/
      - name: suse-edge-charts
        url: oci://registry.suse.com/edge/charts
      - name: rancher-prime
        url: https://charts.rancher.com/server-charts/prime
    network:
      apiHost: $API_HOST
      apiVIP: $API_VIP
    nodes:
    - hostname: mgmt-cluster-node1
      initializer: true
      type: server
#   - hostname: mgmt-cluster-node2
#     type: server
#   - hostname: mgmt-cluster-node3
#     type: server

A seção helm contém a lista de gráficos Helm para instalação, os repositórios que serão usados e a configuração da versão de todos eles.

A seção network contém a configuração da rede, como o apiHost e o apiVIP que o componente RKE2 usará. O apiVIP deve ser um endereço IP não usado na rede e que não faça parte do pool DHCP (se DHCP for usado). Além disso, quando usamos o apiVIP em um cluster de vários nós, ele é usado para acessar o servidor da API Kubernetes. O apiHost é a resolução de nome para o apiVIP que o componente RKE2 usará.

A seção nodes contém a lista dos nós usados no cluster. Neste exemplo, usamos um cluster de nó único, mas é possível estendê-lo para um cluster de vários nós adicionando nós à lista (removendo o marcador de comentário das linhas).

Nota
Nota
  • Os nomes dos nós devem ser exclusivos no cluster.

  • Se preferir, use o campo initializer para especificar o host de inicialização; do contrário, ele será o primeiro nó da lista.

  • Os nomes dos nós devem ser iguais aos nomes de host definidos na pasta de rede (Seção 40.3.5, “Pasta de rede”) quando a configuração de rede é obrigatória.

40.3.3 Pasta custom

A pasta custom contém as seguintes subpastas:

...
├── custom
│ ├── scripts
│ │ ├── 99-register.sh
│ │ ├── 99-mgmt-setup.sh
│ │ └── 99-alias.sh
│ └── files
│     ├── rancher.sh
│     ├── mgmt-stack-setup.service
│     ├── metal3.sh
│     └── basic-setup.sh
...
  • A pasta custom/files contém os arquivos de configuração usados pelo cluster de gerenciamento.

  • A pasta custom/scripts contém os scripts usados pelo cluster de gerenciamento.

A pasta custom/files contém os seguintes arquivos:

  • basic-setup.sh: inclui os parâmetros de configuração para Metal3, Rancher e MetalLB. Modifique esse arquivo apenas para alterar os namespaces usados.

    #!/bin/bash
    # Pre-requisites. Cluster already running
    export KUBECTL="/var/lib/rancher/rke2/bin/kubectl"
    export KUBECONFIG="/etc/rancher/rke2/rke2.yaml"
    
    ##################
    # METAL3 DETAILS #
    ##################
    export METAL3_CHART_TARGETNAMESPACE="metal3-system"
    
    ###########
    # METALLB #
    ###########
    export METALLBNAMESPACE="metallb-system"
    
    ###########
    # RANCHER #
    ###########
    export RANCHER_CHART_TARGETNAMESPACE="cattle-system"
    export RANCHER_FINALPASSWORD="adminadminadmin"
    
    die(){
      echo ${1} 1>&2
      exit ${2}
    }
  • metal3.sh: inclui a configuração para o componente Metal3 usado (sem necessidade de modificação). Em versões futuras, esse script será usado no lugar do Rancher Turtles para facilitar o uso.

    #!/bin/bash
    set -euo pipefail
    
    BASEDIR="$(dirname "$0")"
    source ${BASEDIR}/basic-setup.sh
    
    METAL3LOCKNAMESPACE="default"
    METAL3LOCKCMNAME="metal3-lock"
    
    trap 'catch $? $LINENO' EXIT
    
    catch() {
      if [ "$1" != "0" ]; then
        echo "Error $1 occurred on $2"
        ${KUBECTL} delete configmap ${METAL3LOCKCMNAME} -n ${METAL3LOCKNAMESPACE}
      fi
    }
    
    # Get or create the lock to run all those steps just in a single node
    # As the first node is created WAY before the others, this should be enough
    # TODO: Investigate if leases is better
    if [ $(${KUBECTL} get cm -n ${METAL3LOCKNAMESPACE} ${METAL3LOCKCMNAME} -o name | wc -l) -lt 1 ]; then
      ${KUBECTL} create configmap ${METAL3LOCKCMNAME} -n ${METAL3LOCKNAMESPACE} --from-literal foo=bar
    else
      exit 0
    fi
    
    # Wait for metal3
    while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_CHART_TARGETNAMESPACE} $(${KUBECTL} get pods -n ${METAL3_CHART_TARGETNAMESPACE} -l app.kubernetes.io/name=metal3-ironic -o name) --timeout=10s; do sleep 2 ; done
    
    # Get the ironic IP
    IRONICIP=$(${KUBECTL} get cm -n ${METAL3_CHART_TARGETNAMESPACE} ironic-bmo -o jsonpath='{.data.IRONIC_IP}')
    
    # If LoadBalancer, use metallb, else it is NodePort
    if [ $(${KUBECTL} get svc -n ${METAL3_CHART_TARGETNAMESPACE} metal3-metal3-ironic -o jsonpath='{.spec.type}') == "LoadBalancer" ]; then
      # Wait for metallb
      while ! ${KUBECTL} wait --for condition=ready -n ${METALLBNAMESPACE} $(${KUBECTL} get pods -n ${METALLBNAMESPACE} -l app.kubernetes.io/component=controller -o name) --timeout=10s; do sleep 2 ; done
    
      # Do not create the ippool if already created
      ${KUBECTL} get ipaddresspool -n ${METALLBNAMESPACE} ironic-ip-pool -o name || cat <<-EOF | ${KUBECTL} apply -f -
      apiVersion: metallb.io/v1beta1
      kind: IPAddressPool
      metadata:
        name: ironic-ip-pool
        namespace: ${METALLBNAMESPACE}
      spec:
        addresses:
        - ${IRONICIP}/32
        serviceAllocation:
          priority: 100
          serviceSelectors:
          - matchExpressions:
            - {key: app.kubernetes.io/name, operator: In, values: [metal3-ironic]}
    	EOF
    
      # Same for L2 Advs
      ${KUBECTL} get L2Advertisement -n ${METALLBNAMESPACE} ironic-ip-pool-l2-adv -o name || cat <<-EOF | ${KUBECTL} apply -f -
      apiVersion: metallb.io/v1beta1
      kind: L2Advertisement
      metadata:
        name: ironic-ip-pool-l2-adv
        namespace: ${METALLBNAMESPACE}
      spec:
        ipAddressPools:
        - ironic-ip-pool
    	EOF
    fi
    
    # If rancher is deployed
    if [ $(${KUBECTL} get pods -n ${RANCHER_CHART_TARGETNAMESPACE} -l app=rancher -o name | wc -l) -ge 1 ]; then
      cat <<-EOF | ${KUBECTL} apply -f -
    	apiVersion: management.cattle.io/v3
    	kind: Feature
    	metadata:
    	  name: embedded-cluster-api
    	spec:
    	  value: false
    	EOF
    
      # Disable Rancher webhooks for CAPI
      ${KUBECTL} delete --ignore-not-found=true mutatingwebhookconfiguration.admissionregistration.k8s.io mutating-webhook-configuration
      ${KUBECTL} delete --ignore-not-found=true validatingwebhookconfigurations.admissionregistration.k8s.io validating-webhook-configuration
      ${KUBECTL} wait --for=delete namespace/cattle-provisioning-capi-system --timeout=300s
    fi
    
    # Clean up the lock cm
    
    ${KUBECTL} delete configmap ${METAL3LOCKCMNAME} -n ${METAL3LOCKNAMESPACE}
    • rancher.sh: inclui a configuração para o componente Rancher usado (sem necessidade de modificação).

      #!/bin/bash
      set -euo pipefail
      
      BASEDIR="$(dirname "$0")"
      source ${BASEDIR}/basic-setup.sh
      
      RANCHERLOCKNAMESPACE="default"
      RANCHERLOCKCMNAME="rancher-lock"
      
      if [ -z "${RANCHER_FINALPASSWORD}" ]; then
        # If there is no final password, then finish the setup right away
        exit 0
      fi
      
      trap 'catch $? $LINENO' EXIT
      
      catch() {
        if [ "$1" != "0" ]; then
          echo "Error $1 occurred on $2"
          ${KUBECTL} delete configmap ${RANCHERLOCKCMNAME} -n ${RANCHERLOCKNAMESPACE}
        fi
      }
      
      # Get or create the lock to run all those steps just in a single node
      # As the first node is created WAY before the others, this should be enough
      # TODO: Investigate if leases is better
      if [ $(${KUBECTL} get cm -n ${RANCHERLOCKNAMESPACE} ${RANCHERLOCKCMNAME} -o name | wc -l) -lt 1 ]; then
        ${KUBECTL} create configmap ${RANCHERLOCKCMNAME} -n ${RANCHERLOCKNAMESPACE} --from-literal foo=bar
      else
        exit 0
      fi
      
      # Wait for rancher to be deployed
      while ! ${KUBECTL} wait --for condition=ready -n ${RANCHER_CHART_TARGETNAMESPACE} $(${KUBECTL} get pods -n ${RANCHER_CHART_TARGETNAMESPACE} -l app=rancher -o name) --timeout=10s; do sleep 2 ; done
      until ${KUBECTL} get ingress -n ${RANCHER_CHART_TARGETNAMESPACE} rancher > /dev/null 2>&1; do sleep 10; done
      
      RANCHERBOOTSTRAPPASSWORD=$(${KUBECTL} get secret -n ${RANCHER_CHART_TARGETNAMESPACE} bootstrap-secret -o jsonpath='{.data.bootstrapPassword}' | base64 -d)
      RANCHERHOSTNAME=$(${KUBECTL} get ingress -n ${RANCHER_CHART_TARGETNAMESPACE} rancher -o jsonpath='{.spec.rules[0].host}')
      
      # Skip the whole process if things have been set already
      if [ -z $(${KUBECTL} get settings.management.cattle.io first-login -ojsonpath='{.value}') ]; then
        # Add the protocol
        RANCHERHOSTNAME="https://${RANCHERHOSTNAME}"
        TOKEN=""
        while [ -z "${TOKEN}" ]; do
          # Get token
          sleep 2
          TOKEN=$(curl -sk -X POST ${RANCHERHOSTNAME}/v3-public/localProviders/local?action=login -H 'content-type: application/json' -d "{\"username\":\"admin\",\"password\":\"${RANCHERBOOTSTRAPPASSWORD}\"}" | jq -r .token)
        done
      
        # Set password
        curl -sk ${RANCHERHOSTNAME}/v3/users?action=changepassword -H 'content-type: application/json' -H "Authorization: Bearer $TOKEN" -d "{\"currentPassword\":\"${RANCHERBOOTSTRAPPASSWORD}\",\"newPassword\":\"${RANCHER_FINALPASSWORD}\"}"
      
        # Create a temporary API token (ttl=60 minutes)
        APITOKEN=$(curl -sk ${RANCHERHOSTNAME}/v3/token -H 'content-type: application/json' -H "Authorization: Bearer ${TOKEN}" -d '{"type":"token","description":"automation","ttl":3600000}' | jq -r .token)
      
        curl -sk ${RANCHERHOSTNAME}/v3/settings/server-url -H 'content-type: application/json' -H "Authorization: Bearer ${APITOKEN}" -X PUT -d "{\"name\":\"server-url\",\"value\":\"${RANCHERHOSTNAME}\"}"
        curl -sk ${RANCHERHOSTNAME}/v3/settings/telemetry-opt -X PUT -H 'content-type: application/json' -H 'accept: application/json' -H "Authorization: Bearer ${APITOKEN}" -d '{"value":"out"}'
      fi
      
      # Clean up the lock cm
      ${KUBECTL} delete configmap ${RANCHERLOCKCMNAME} -n ${RANCHERLOCKNAMESPACE}
    • mgmt-stack-setup.service: contém a configuração para criar o serviço systemd para executar os scripts durante a primeira inicialização (nenhuma modificação é necessária).

      [Unit]
      Description=Setup Management stack components
      Wants=network-online.target
      # It requires rke2 or k3s running, but it will not fail if those services are not present
      After=network.target network-online.target rke2-server.service k3s.service
      # At least, the basic-setup.sh one needs to be present
      ConditionPathExists=/opt/mgmt/bin/basic-setup.sh
      
      [Service]
      User=root
      Type=forking
      # Metal3 can take A LOT to download the IPA image
      TimeoutStartSec=1800
      
      ExecStartPre=/bin/sh -c "echo 'Setting up Management components...'"
      # Scripts are executed in StartPre because Start can only run a single one
      ExecStartPre=/opt/mgmt/bin/rancher.sh
      ExecStartPre=/opt/mgmt/bin/metal3.sh
      ExecStart=/bin/sh -c "echo 'Finished setting up Management components'"
      RemainAfterExit=yes
      KillMode=process
      # Disable & delete everything
      ExecStartPost=rm -f /opt/mgmt/bin/rancher.sh
      ExecStartPost=rm -f /opt/mgmt/bin/metal3.sh
      ExecStartPost=rm -f /opt/mgmt/bin/basic-setup.sh
      ExecStartPost=/bin/sh -c "systemctl disable mgmt-stack-setup.service"
      ExecStartPost=rm -f /etc/systemd/system/mgmt-stack-setup.service
      
      [Install]
      WantedBy=multi-user.target

A pasta custom/scripts contém os seguintes arquivos:

  • Script 99-alias.sh: contém o álias que o cluster de gerenciamento usa para carregar o arquivo kubeconfig na primeira inicialização (sem necessidade de modificação).

    #!/bin/bash
    echo "alias k=kubectl" >> /etc/profile.local
    echo "alias kubectl=/var/lib/rancher/rke2/bin/kubectl" >> /etc/profile.local
    echo "export KUBECONFIG=/etc/rancher/rke2/rke2.yaml" >> /etc/profile.local
  • Script 99-mgmt-setup.sh: contém a configuração para copiar os scripts durante a primeira inicialização (sem necessidade de modificação).

    #!/bin/bash
    
    # Copy the scripts from combustion to the final location
    mkdir -p /opt/mgmt/bin/
    for script in basic-setup.sh rancher.sh metal3.sh; do
    	cp ${script} /opt/mgmt/bin/
    done
    
    # Copy the systemd unit file and enable it at boot
    cp mgmt-stack-setup.service /etc/systemd/system/mgmt-stack-setup.service
    systemctl enable mgmt-stack-setup.service
  • Script 99-register.sh: contém a configuração para registrar o sistema usando o código de registro do SCC. O ${SCC_ACCOUNT_EMAIL} e o ${SCC_REGISTRATION_CODE} devem ser devidamente definidos para registrar o sistema com a sua conta.

    #!/bin/bash
    set -euo pipefail
    
    # Registration https://www.suse.com/support/kb/doc/?id=000018564
    if ! which SUSEConnect > /dev/null 2>&1; then
    	zypper --non-interactive install suseconnect-ng
    fi
    SUSEConnect --email "${SCC_ACCOUNT_EMAIL}" --url "https://scc.suse.com" --regcode "${SCC_REGISTRATION_CODE}"

40.3.4 Pasta kubernetes

A pasta kubernetes contém as seguintes subpastas:

...
├── kubernetes
│ ├── manifests
│ │ ├── rke2-ingress-config.yaml
│ │ ├── neuvector-namespace.yaml
│ │ ├── ingress-l2-adv.yaml
│ │ └── ingress-ippool.yaml
│ ├── helm
│ │ └── values
│ │     ├── rancher.yaml
│ │     ├── neuvector.yaml
│ │     ├── metal3.yaml
│ │     └── certmanager.yaml
│ └── config
│     └── server.yaml
...

A pasta kubernetes/config contém os seguintes arquivos:

  • server.yaml: por padrão, o plug-in de CNI instalado é o Cilium, portanto, você não precisa criar a pasta nem o arquivo. Caso seja necessário personalizar o plug-in de CNI, use o arquivo server.yaml na pasta kubernetes/config, que contém as seguintes informações:

    cni:
    - multus
    - cilium
Nota
Nota

Esse é um arquivo opcional para definir personalizações do Kubernetes, como os plug-ins de CNI usados ou várias opções que você pode conferir na documentação oficial.

A pasta kubernetes/manifests contém os seguintes arquivos:

  • rke2-ingress-config.yaml: contém a configuração para criar o serviço Ingress para o cluster de gerenciamento (sem necessidade de modificação).

    apiVersion: helm.cattle.io/v1
    kind: HelmChartConfig
    metadata:
      name: rke2-ingress-nginx
      namespace: kube-system
    spec:
      valuesContent: |-
        controller:
          config:
            use-forwarded-headers: "true"
            enable-real-ip: "true"
          publishService:
            enabled: true
          service:
            enabled: true
            type: LoadBalancer
            externalTrafficPolicy: Local
  • neuvector-namespace.yaml: contém a configuração para criar o namespace NeuVector (sem necessidade de modificação).

    apiVersion: v1
    kind: Namespace
    metadata:
      labels:
        pod-security.kubernetes.io/enforce: privileged
      name: neuvector
  • ingress-l2-adv.yaml: contém a configuração para criar o L2Advertisement para o componente MetalLB (sem necessidade de modificação).

    apiVersion: metallb.io/v1beta1
    kind: L2Advertisement
    metadata:
      name: ingress-l2-adv
      namespace: metallb-system
    spec:
      ipAddressPools:
        - ingress-ippool
  • ingress-ippool.yaml: contém a configuração para criar o IPAddressPool para o componente rke2-ingress-nginx. O ${INGRESS_VIP} deve ser definido apropriadamente para especificar o endereço IP reservado que o componente rke2-ingress-nginx usará.

    apiVersion: metallb.io/v1beta1
    kind: IPAddressPool
    metadata:
      name: ingress-ippool
      namespace: metallb-system
    spec:
      addresses:
        - ${INGRESS_VIP}/32
      serviceAllocation:
        priority: 100
        serviceSelectors:
          - matchExpressions:
              - {key: app.kubernetes.io/name, operator: In, values: [rke2-ingress-nginx]}

A pasta kubernetes/helm/values contém os seguintes arquivos:

  • rancher.yaml: contém a configuração para criar o componente Rancher. É necessário definir apropriadamente o ${INGRESS_VIP} para especificar o endereço IP que o componente Rancher consumirá. O URL para acessar o componente Rancher será https://rancher-${INGRESS_VIP}.sslip.io.

    hostname: rancher-${INGRESS_VIP}.sslip.io
    bootstrapPassword: "foobar"
    replicas: 1
    global.cattle.psp.enabled: "false"
  • neuvector.yaml: contém a configuração para criar o componente NeuVector (sem necessidade de modificação).

    controller:
      replicas: 1
      ranchersso:
        enabled: true
    manager:
      enabled: false
    cve:
      scanner:
        enabled: false
        replicas: 1
    k3s:
      enabled: true
    crdwebhook:
      enabled: false
  • metal3.yaml: contém a configuração para criar o componente Metal3. É necessário definir apropriadamente o ${METAL3_VIP} para especificar o endereço IP que o componente Metal3 consumirá.

    global:
      ironicIP: ${METAL3_VIP}
      enable_vmedia_tls: false
      additionalTrustedCAs: false
    metal3-ironic:
      global:
        predictableNicNames: "true"
      persistence:
        ironic:
          size: "5Gi"

    Para implantar clusters downstream arm64 usando esse cluster de gerenciamento x86_64, você precisa adicionar a seguinte deployArchitecture: arm64 à seção global do arquivo metal3.yaml:

    global:
      ironicIP: ${METAL3_VIP}
      enable_vmedia_tls: false
      additionalTrustedCAs: false
      deployArchitecture: arm64
    metal3-ironic:
      global:
        predictableNicNames: "true"
      persistence:
        ironic:
          size: "5Gi"
Nota
Nota

Na versão atual, existe uma limitação referente ao uso da deployArchitecture: arm64. Especificamente, se você permitir a implantação de clusters downstream arm64 usando essa diretiva, o cluster de gerenciamento apenas poderá implantar essa arquitetura no futuro. Para implantar clusters nas duas arquiteturas (x86_64 e arm64), provisione dois clusters de gerenciamento separados. Essa limitação será removida em uma versão futura.

Nota
Nota

O servidor de mídia é um recurso opcional incluído no Metal3 (que está desabilitado por padrão). Para usar o recurso Metal3, configure-o no manifesto anterior. Para usar o servidor de mídia Metal3, especifique a seguinte variável:

  • adicione enable_metal3_media_server a true para habilitar o recurso de servidor de mídia na seção global.

  • inclua a seguinte configuração sobre o servidor de mídia, em que ${MEDIA_VOLUME_PATH} é o caminho para o volume da mídia (por exemplo, /home/metal3/bmh-image-cache).

    metal3-media:
      mediaVolume:
        hostPath: ${MEDIA_VOLUME_PATH}

É possível usar um servidor de mídia externo para armazenar as imagens e, caso você queira usá-lo com TLS, precisará modificar as seguintes configurações:

  • defina additionalTrustedCAs como true no arquivo metal3.yaml anterior para permitir as CAs confiáveis adicionais do servidor de mídia externo.

  • inclua a seguinte configuração de segredo na pasta kubernetes/manifests/metal3-cacert-secret.yaml para armazenar o certificado CA do servidor de mídia externo.

    apiVersion: v1
    kind: Namespace
    metadata:
      name: metal3-system
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: tls-ca-additional
      namespace: metal3-system
    type: Opaque
    data:
      ca-additional.crt: {{ additional_ca_cert | b64encode }}

O additional_ca_cert é o certificado CA codificado em base64 do servidor de mídia externo. É possível usar o seguinte comando para codificar o certificado e gerar o segredo manualmente:

kubectl -n meta3-system create secret generic tls-ca-additional --from-file=ca-additional.crt=./ca-additional.crt
  • certmanager.yaml: contém a configuração para criar o componente Cert-Manager (sem necessidade de modificação).

    installCRDs: "true"

40.3.5 Pasta de rede

A pasta network contém o mesmo número de arquivos e nós no cluster de gerenciamento. Em nosso caso, temos apenas um nó, portanto, temos somente um arquivo chamado mgmt-cluster-node1.yaml. O nome do arquivo deve ser igual ao nome de host especificado no arquivo de definição mgmt-cluster.yaml incluído na seção network/node descrita acima.

Se você precisa personalizar a configuração de rede, por exemplo, para usar um endereço IP estático específico (cenário sem DHCP), use o arquivo mgmt-cluster-node1.yaml na pasta network, que contém as seguintes informações:

  • ${MGMT_GATEWAY}: o endereço IP do gateway.

  • ${MGMT_DNS}: o endereço IP do servidor DNS.

  • ${MGMT_MAC}: o endereço MAC da interface de rede.

  • ${MGMT_NODE_IP}: o endereço IP do cluster de gerenciamento.

routes:
  config:
  - destination: 0.0.0.0/0
    metric: 100
    next-hop-address: ${MGMT_GATEWAY}
    next-hop-interface: eth0
    table-id: 254
dns-resolver:
  config:
    server:
    - ${MGMT_DNS}
    - 8.8.8.8
interfaces:
- name: eth0
  type: ethernet
  state: up
  mac-address: ${MGMT_MAC}
  ipv4:
    address:
    - ip: ${MGMT_NODE_IP}
      prefix-length: 24
    dhcp: false
    enabled: true
  ipv6:
    enabled: false

Para usar DHCP para obter o endereço IP, você pode definir a seguinte configuração (o endereço MAC deve ser devidamente definido por meio da variável ${MGMT_MAC}):

## This is an example of a dhcp network configuration for a management cluster
interfaces:
- name: eth0
  type: ethernet
  state: up
  mac-address: ${MGMT_MAC}
  ipv4:
    dhcp: true
    enabled: true
  ipv6:
    enabled: false
Nota
Nota
  • Dependendo do número de nós no cluster de gerenciamento, você poderá criar mais arquivos, como mgmt-cluster-node2.yaml, mgmt-cluster-node3.yaml etc., para configurar o restante dos nós.

  • A seção routes é usada para definir a tabela de roteamento para o cluster de gerenciamento.

40.4 Preparação da imagem para ambientes air-gapped

Esta seção descreve como preparar a imagem para ambientes air-gapped mostrando apenas as diferenças das seções anteriores. As seguintes alterações na seção anterior (Preparação da imagem para ambientes conectados (Seção 40.3, “Preparação da imagem para ambientes conectados”)) são necessárias para preparar a imagem para os ambientes air-gapped:

  • É necessário modificar o arquivo mgmt-cluster.yaml para incluir a seção embeddedArtifactRegistry com o campo images definido para que todas as imagens do contêiner sejam incluídas na imagem de saída do EIB.

  • É necessário modificar o arquivo mgmt-cluster.yaml para incluir o gráfico Helm rancher-turtles-airgap-resources.

  • É necessário remover o script custom/scripts/99-register.sh ao usar um ambiente air-gapped.

40.4.1 Modificações no arquivo de definição

É necessário modificar o arquivo mgmt-cluster.yaml para incluir a seção embeddedArtifactRegistry. Nessa seção, o campo images deve conter a lista de todas as imagens do contêiner que serão incluídas na imagem de saída.

Nota
Nota

Veja a seguir um exemplo do arquivo mgmt-cluster.yaml com a seção embeddedArtifactRegistry incluída. Garanta que as imagens listadas contenham as versões dos componentes necessárias.

É necessário também adicionar o gráfico Helm rancher-turtles-airgap-resources para criar os recursos conforme descrito na documentação do Rancher Turtles sobre ambientes air-gapped. Isso também requer um arquivo de valores turtles.yaml para que o gráfico rancher-turtles especifique a configuração necessária.

apiVersion: 1.2
image:
  imageType: iso
  arch: x86_64
  baseImage: SL-Micro.x86_64-6.1-Base-SelfInstall-GM.install.iso
  outputImageName: eib-mgmt-cluster-image.iso
operatingSystem:
  isoConfiguration:
    installDevice: /dev/sda
  users:
  - username: root
    encryptedPassword: $ROOT_PASSWORD
  packages:
    packageList:
    - jq
    sccRegistrationCode: $SCC_REGISTRATION_CODE
kubernetes:
  version: v1.32.4+rke2r1
  helm:
    charts:
      - name: cert-manager
        repositoryName: jetstack
        version: 1.15.3
        targetNamespace: cert-manager
        valuesFile: certmanager.yaml
        createNamespace: true
        installationNamespace: kube-system
      - name: longhorn-crd
        version: 106.2.0+up1.8.1
        repositoryName: rancher-charts
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
      - name: longhorn
        version: 106.2.0+up1.8.1
        repositoryName: rancher-charts
        targetNamespace: longhorn-system
        createNamespace: true
        installationNamespace: kube-system
      - name: metal3
        version: 303.0.7+up0.11.5
        repositoryName: suse-edge-charts
        targetNamespace: metal3-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: metal3.yaml
      - name: rancher-turtles
        version: 303.0.4+up0.20.0
        repositoryName: suse-edge-charts
        targetNamespace: rancher-turtles-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: turtles.yaml
      - name: rancher-turtles-airgap-resources
        version: 303.0.4+up0.20.0
        repositoryName: suse-edge-charts
        targetNamespace: rancher-turtles-system
        createNamespace: true
        installationNamespace: kube-system
      - name: neuvector-crd
        version: 106.0.1+up2.8.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector.yaml
      - name: neuvector
        version: 106.0.1+up2.8.6
        repositoryName: rancher-charts
        targetNamespace: neuvector
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: neuvector.yaml
      - name: rancher
        version: 2.11.2
        repositoryName: rancher-prime
        targetNamespace: cattle-system
        createNamespace: true
        installationNamespace: kube-system
        valuesFile: rancher.yaml
    repositories:
      - name: jetstack
        url: https://charts.jetstack.io
      - name: rancher-charts
        url: https://charts.rancher.io/
      - name: suse-edge-charts
        url: oci://registry.suse.com/edge/charts
      - name: rancher-prime
        url: https://charts.rancher.com/server-charts/prime
    network:
      apiHost: $API_HOST
      apiVIP: $API_VIP
    nodes:
    - hostname: mgmt-cluster-node1
      initializer: true
      type: server
#   - hostname: mgmt-cluster-node2
#     type: server
#   - hostname: mgmt-cluster-node3
#     type: server
#       type: server
embeddedArtifactRegistry:
  images:
    - name: registry.suse.com/rancher/hardened-cluster-autoscaler:v1.9.0-build20241203
    - name: registry.suse.com/rancher/hardened-cni-plugins:v1.6.2-build20250306
    - name: registry.suse.com/rancher/hardened-coredns:v1.12.1-build20250401
    - name: registry.suse.com/rancher/hardened-k8s-metrics-server:v0.7.2-build20250110
    - name: registry.suse.com/rancher/hardened-multus-cni:v4.2.0-build20250326
    - name: registry.suse.com/rancher/klipper-helm:v0.9.5-build20250306
    - name: registry.suse.com/rancher/mirrored-cilium-cilium:v1.17.3
    - name: registry.suse.com/rancher/mirrored-cilium-operator-generic:v1.17.3
    - name: registry.suse.com/rancher/mirrored-longhornio-csi-attacher:v4.8.1
    - name: registry.suse.com/rancher/mirrored-longhornio-csi-node-driver-registrar:v2.13.0
    - name: registry.suse.com/rancher/mirrored-longhornio-csi-provisioner:v5.2.0
    - name: registry.suse.com/rancher/mirrored-longhornio-csi-resizer:v1.13.2
    - name: registry.suse.com/rancher/mirrored-longhornio-csi-snapshotter:v8.2.0
    - name: registry.suse.com/rancher/mirrored-longhornio-livenessprobe:v2.15.0
    - name: registry.suse.com/rancher/mirrored-longhornio-longhorn-engine:v1.8.1
    - name: registry.suse.com/rancher/mirrored-longhornio-longhorn-instance-manager:v1.8.1
    - name: registry.suse.com/rancher/mirrored-longhornio-longhorn-manager:v1.8.1
    - name: registry.suse.com/rancher/mirrored-longhornio-longhorn-share-manager:v1.8.1
    - name: registry.suse.com/rancher/mirrored-longhornio-longhorn-ui:v1.8.1
    - name: registry.suse.com/rancher/mirrored-sig-storage-snapshot-controller:v8.2.0
    - name: registry.suse.com/rancher/neuvector-compliance-config:1.0.5
    - name: registry.suse.com/rancher/neuvector-controller:5.4.4
    - name: registry.suse.com/rancher/neuvector-enforcer:5.4.4
    - name: registry.suse.com/rancher/nginx-ingress-controller:v1.12.1-hardened3
    - name: registry.rancher.com/rancher/cluster-api-addon-provider-fleet:v0.10.0
    - name: registry.rancher.com/rancher/cluster-api-operator:v0.17.0
    - name: registry.rancher.com/rancher/fleet-agent:v0.12.3
    - name: registry.rancher.com/rancher/fleet:v0.12.3
    - name: registry.rancher.com/rancher/hardened-node-feature-discovery:v0.15.7-build20250425
    - name: registry.rancher.com/rancher/rancher-webhook:v0.7.2
    - name: registry.rancher.com/rancher/rancher/turtles:v0.20.0
    - name: registry.rancher.com/rancher/rancher:v2.11.2
    - name: registry.rancher.com/rancher/shell:v0.4.1
    - name: registry.rancher.com/rancher/system-upgrade-controller:v0.15.2
    - name: registry.suse.com/rancher/cluster-api-controller:v1.9.5
    - name: registry.suse.com/rancher/cluster-api-provider-metal3:v1.9.3
    - name: registry.suse.com/rancher/cluster-api-provider-rke2-bootstrap:v0.16.1
    - name: registry.suse.com/rancher/cluster-api-provider-rke2-controlplane:v0.16.1
    - name: registry.suse.com/rancher/hardened-sriov-network-operator:v1.5.0-build20250425
    - name: registry.suse.com/rancher/ip-address-manager:v1.9.4
    - name: registry.rancher.com/rancher/kubectl:v1.32.2

40.4.2 Modificações na pasta custom

  • É necessário remover o script custom/scripts/99-register.sh ao usar um ambiente air-gapped. Conforme você pode observar na estrutura de diretórios, o script 99-register.sh não está incluído na pasta custom/scripts.

40.4.3 Modificações na pasta de valores do Helm

  • O turtles.yaml: contém a configuração necessária para especificar a operação air-gapped para o Rancher Turtles. Observe que isso depende da instalação do gráfico rancher-turtles-airgap-resources.

    cluster-api-operator:
      cluster-api:
        core:
          fetchConfig:
            selector: "{\"matchLabels\": {\"provider-components\": \"core\"}}"
        rke2:
          bootstrap:
            fetchConfig:
              selector: "{\"matchLabels\": {\"provider-components\": \"rke2-bootstrap\"}}"
          controlPlane:
            fetchConfig:
              selector: "{\"matchLabels\": {\"provider-components\": \"rke2-control-plane\"}}"
        metal3:
          infrastructure:
            fetchConfig:
              selector: "{\"matchLabels\": {\"provider-components\": \"metal3\"}}"

40.5 Criação de imagem

Depois que a estrutura de diretórios foi preparada de acordo com as seções anteriores (para os cenários tanto conectados quanto air-gapped), execute o comando abaixo para criar a imagem:

podman run --rm --privileged -it -v $PWD:/eib \
 registry.suse.com/edge/3.3/edge-image-builder:1.2.1 \
 build --definition-file mgmt-cluster.yaml

Isso cria o arquivo de imagem ISO de saída que, com base na definição da imagem descrita acima, no nosso caso é eib-mgmt-cluster-image.iso.

40.6 Provisionar o cluster de gerenciamento

A imagem anterior contém todos os componentes explicados acima e pode ser usada para provisionar o cluster de gerenciamento usando uma máquina virtual ou um servidor bare metal (com o recurso de mídia virtual).

Documentation survey