Provisionar e usar SSDs locais mistos para armazenamento em blocos brutos e temporário

Neste documento, mostramos como provisionar e particionar SSDs locais no Google Kubernetes Engine (GKE) para dar suporte a cargas de trabalho que exigem um sistema de arquivos de armazenamento temporário padrão e um armazenamento em blocos brutos não formatado no mesmo nó.

Use essa configuração para aplicativos com estado e bancos de dados altamente otimizados. Essas cargas de trabalho geralmente exigem acesso direto ao disco para aumentar o desempenho, mas também precisam de armazenamento de arquivos temporário padrão para sidecars, registros ou caches de contêiner. Ao usar a capacidade mista de SSD local, é possível reduzir a sobrecarga de gerenciamento de clusters e maximizar a utilização de hardware, porque não é necessário dedicar nós separados ou discos completos exclusivamente à infraestrutura de blocos brutos.

Quando você cria um cluster ou pool de nós com capacidade mista de SSD local, o GKE particiona cada SSD local fisicamente anexado da seguinte maneira:

  • Armazenamento temporário: a capacidade temporária solicitada é dividida igualmente entre os SSDs locais e combinada para fornecer o armazenamento de arquivos temporário padrão do nó. Quando a capacidade temporária é particionada em vários SSDs locais, o armazenamento é combinado em uma matriz RAID-0. É possível acessar o armazenamento temporário usando volumes emptyDir padrão.
  • Armazenamento em blocos brutos: o restante da capacidade física em cada disco é apresentado ao nó como dispositivos de transferência por blocos brutos distintos e não formatados.

Este documento é destinado a administradores e operadores de plataforma e DevOps que querem otimizar a utilização de hardware e o desempenho de armazenamento no GKE para cargas de trabalho especializadas.

Considerações

Além das limitações do SSD local do Compute Engine, confira as seguintes considerações específicas do GKE antes de configurar os modos mistos de SSD local:

  • Compatibilidade com o Autopilot: os clusters do Autopilot do GKE não são compatíveis com armazenamento temporário e de blocos brutos mistos. Para saber como usar SSDs locais para armazenamento temporário padrão no Autopilot, consulte SSDs locais em clusters do Autopilot.
  • ComputeClasses personalizadas: as ComputeClasses personalizadas não oferecem suporte à configuração mista de SSD local.
  • Sistema operacional: o modo misto de SSD local é compatível apenas com imagens de nó do Linux (Container-Optimized OS e Ubuntu). Os pools de nós do Windows Server não são compatíveis.
  • Eventos de manutenção: não recomendamos o uso do SSD local como armazenamento em blocos brutos para VMs Z3 ou Z4D otimizadas para armazenamento. Os dados nessas VMs podem não sobreviver a eventos de manutenção. Para mais informações, consulte Provisionar e usar o armazenamento em blocos brutos com suporte de SSD local.
  • E/S compartilhada: como a matriz RAID-0 temporária e as partições de bloco bruto de destino dependem dos mesmos SSDs físicos, operações intensivas em uma partição lógica podem afetar a capacidade da outra. Para informações sobre os limites máximos de capacidade, consulte Desempenho do SSD local.
  • Preços: ao usar modos mistos para particionar a capacidade do SSD local, você paga pela capacidade física total do SSD local anexada ao nó, independentemente de quanta capacidade é alocada para o armazenamento temporário em comparação com o armazenamento em blocos brutos. Para mais informações, consulte Preços de SSD local.
  • Configuração manual: para usar o armazenamento em blocos brutos com suporte de SSD local, é preciso configurar manualmente os dispositivos, porque o GKE não formata nem monta as partições de blocos brutos. Você também é responsável por gerenciar a capacidade dos nós e lidar com possíveis interrupções de cargas de trabalho colocalizadas. O uso de um objeto PersistentVolume local fornece programação de pod integrada. Se as cargas de trabalho não exigirem que os dados persistam durante o ciclo de vida do pod ou se não tiverem necessidades de desempenho especializadas, use a configuração de SSD local totalmente temporária. A configuração totalmente temporária é adequada para a maioria dos casos de uso.
  • Troca de memória do nó: é possível combinar a capacidade mista do SSD local com a troca de memória do nó usando o perfil do disco de inicialização ou o perfil do SSD local temporário. O perfil de SSD local dedicado não é compatível com capacidade mista de SSD local. Para mais informações, consulte Troca de memória de nó com capacidade mista de SSD local.

Antes de começar

Antes de começar, verifique se você realizou as tarefas a seguir:

  • Ative a API Google Kubernetes Engine.
  • Ativar a API Google Kubernetes Engine
  • Para usar a Google Cloud CLI nesta tarefa, instale e inicialize a CLI gcloud. Se você instalou a CLI gcloud anteriormente, instale a versão mais recente executando o comando gcloud components update. Talvez as versões anteriores da CLI gcloud não sejam compatíveis com a execução dos comandos neste documento.

Para usar esse recurso, os nós do GKE precisam executar a versão 1.37.0-gke.3570000 ou posterior.

Funções exigidas

Para receber as permissões necessárias para criar clusters e pools de nós com capacidade mista de SSD local, peça ao administrador para conceder a você o papel do IAM de Administrador do Kubernetes Engine (roles/container.admin) no projeto. Para mais informações sobre a concessão de papéis, consulte Gerenciar o acesso a projetos, pastas e organizações.

Também é possível conseguir as permissões necessárias usando papéis personalizados ou outros papéis predefinidos.

Criar um cluster ou pool de nós com armazenamento misto de SSD local

É possível alocar capacidade temporária e reservar partições de bloco bruto usando a propriedade capacity da flag --ephemeral-storage-local-ssd.

Crie o cluster ou pool de nós especificando o subcampo capacity com a flag --ephemeral-storage-local-ssd.

Se o tipo de máquina permitir um número configurável de SSDs locais, você também precisará especificar o subcampo count. Se o tipo de máquina tiver um número fixo de SSDs locais, por exemplo, tipos -lssd, será possível omitir o subcampo count porque o GKE calcula automaticamente a contagem de discos com base no formato da VM.

Criar um cluster com armazenamento misto de SSD local

Para criar um novo cluster, use o comando gcloud container clusters create. Essas configurações se aplicam apenas ao pool de nós padrão. Se os pools de nós subsequentes precisarem de armazenamento misto de SSD local, especifique a flag --ephemeral-storage-local-ssd ao criar o pool de nós. O número máximo de discos que podem ser anexados varia de acordo com o tipo de máquina e a região.

Se a versão do cluster for anterior a 1.37.0-gke.3570000, adicione uma das seguintes sinalizações aos comandos de criação de cluster abaixo:

  • A flag --cluster-version=<var>VERSION</var> com <var>VERSION</var> definida como 1.37.0-gke.3570000 ou mais recente, ou
  • A sinalização --release-channel=rapid

Para tipos de máquina com uma contagem de SSD local configurável, execute o seguinte:

gcloud container clusters create CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --ephemeral-storage-local-ssd count=NUMBER_OF_DISKS,capacity=CAPACITY

Para tipos de máquina com uma contagem fixa de SSDs locais, execute o seguinte:

gcloud container clusters create CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --ephemeral-storage-local-ssd capacity=CAPACITY

Substitua:

  • CLUSTER_NAME: o nome do cluster que você quer criar.
  • MACHINE_TYPE: o tipo de máquina que será usado. Para uma lista de tipos de máquina compatíveis, consulte Suporte a séries de máquinas. Não é possível usar SSDs locais com o tipo de máquina e2-medium padrão, porque os tipos de máquina com núcleo compartilhado não são compatíveis com eles.
  • NUMBER_OF_DISKS: para tipos de máquina com uma contagem de SSDs locais configurável, o número de discos SSD locais a serem provisionados em cada nó.
  • CAPACITY: a capacidade total do SSD local a ser formatada para armazenamento temporário. Esse valor precisa ser maior que 0 e estritamente menor que a capacidade física total do SSD local (contagem de discos × tamanho por disco), por exemplo, 200GB. Observe o seguinte:

    • O valor não pode ser alterado após a criação do cluster.
    • O GKE reserva parte dessa capacidade para uso do sistema, então o armazenamento temporário alocável é menor que CAPACITY. Para mais informações, consulte Reserva de armazenamento temporário local.

Criar um pool de nós com armazenamento misto de SSD local

Para adicionar um pool de nós a um cluster atual, use o comando gcloud container node-pools create.

Se a versão do pool de nós for anterior a 1.37.0-gke.3570000, faça o seguinte:

  • Adicione a flag --node-version=<var>VERSION</var> aos seguintes comandos de criação de pool de nós, com <var>VERSION</var> definido como 1.37.0-gke.3570000 ou mais recente.
  • Verifique se o plano de controle do cluster está na versão 1.37.0-gke.3570000 ou mais recente.

Para tipos de máquina com uma contagem de SSD local configurável, execute o seguinte:

gcloud container node-pools create POOL_NAME \
    --cluster=CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --ephemeral-storage-local-ssd count=NUMBER_OF_DISKS,capacity=CAPACITY

Para tipos de máquina com uma contagem fixa de SSDs locais, execute o seguinte:

gcloud container node-pools create POOL_NAME \
    --cluster=CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --ephemeral-storage-local-ssd capacity=CAPACITY

Substitua:

  • POOL_NAME: o nome do novo pool de nós que você quer criar.
  • CLUSTER_NAME: o nome do cluster.
  • MACHINE_TYPE: o tipo de máquina que será usado. Para uma lista de tipos de máquina compatíveis, consulte Suporte a séries de máquinas. Não é possível usar SSDs locais com o tipo de máquina e2-medium padrão, porque os tipos de máquina com núcleo compartilhado não são compatíveis com eles.
  • NUMBER_OF_DISKS: para tipos de máquina com uma contagem de SSDs locais configurável, o número de discos SSD locais a serem provisionados em cada nó.
  • CAPACITY: a capacidade total do SSD local a ser formatada para armazenamento temporário. Esse valor precisa ser maior que 0 e estritamente menor que a capacidade física total do SSD local (contagem de discos × tamanho por disco), por exemplo, 200GB. Observe o seguinte:

    • Não é possível mudar o valor depois que o pool de nós é criado.
    • O GKE reserva parte dessa capacidade para uso do sistema, de modo que o armazenamento temporário alocável é menor que CAPACITY. Para mais informações, consulte Reserva de armazenamento temporário local.

Verificar os rótulos dos nós

Após o provisionamento, para verificar se os nós têm os rótulos corretos para o armazenamento em blocos temporários e brutos, execute o seguinte comando:

kubectl describe node NODE_NAME

A saída precisa conter os dois rótulos de nó a seguir:

  • cloud.google.com/gke-ephemeral-storage-local-ssd: "true"
  • cloud.google.com/gke-local-nvme-ssd-partition: "true"

Acessar a capacidade temporária

Acesse o armazenamento temporário reservado por meio de volumes emptyDir exatamente como faria com qualquer outro volume temporário do GKE.

Acessar a capacidade de blocos brutos

Para acessar a capacidade de blocos brutos, crie um objeto StorageClass, provisione um objeto PersistentVolume local e reivindique-o usando um objeto PersistentVolumeClaim.

Criar um StorageClass

Como você está provisionando os objetos PersistentVolume sem o provisionador estático da comunidade, recomendamos criar um objeto StorageClass com o campo volumeBindingMode: WaitForFirstConsumer. Isso atrasa a vinculação até a programação do pod, garantindo que o Kubernetes escolha um SSD local de um nó apropriado que possa executar o pod.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: "local-storage"
provisioner: "kubernetes.io/no-provisioner"
volumeBindingMode: "WaitForFirstConsumer"

Criar o PersistentVolume

Os objetos PersistentVolume locais têm limitações importantes em relação a upgrades de nós, escalonamento e escalonamento automático de clusters. Antes de criar os volumes, consulte as Limitações dos PersistentVolumes locais para entender como os eventos de ciclo de vida afetam seus dados.

Para criar o objeto PersistentVolume, siga as etapas abaixo para encontrar o caminho do link simbólico para a partição do SSD local, determinar a capacidade restante exata e configurar o manifesto.

Encontrar a capacidade da partição

Execute o comando a seguir no nó de destino para encontrar a capacidade exata de blocos brutos restante para a partição.

kubectl debug node/NODE_NAME -it --image=ubuntu -- \
    sh -c 'ls -l /host/dev/disk/by-id/ | grep partition; lsblk -o NAME,SIZE,TYPE'

Substitua NODE_NAME pelo nome do nó em que o SSD local está anexado.

A saída mostra o mapeamento entre os nomes de dispositivos e os links simbólicos de partição para que você possa verificar qual partição corresponde a qual dispositivo. Ele também lista os dispositivos de transferência por blocos anexados ao nó e os tamanhos deles.

Por exemplo, se você anexar dois SSDs locais ao nó e alocar 200 GB para o armazenamento temporário (capacity=200GB), a saída será semelhante a esta:

google-local-ssd-partition0 -> /dev/nvme0n1p2
google-local-ssd-partition1 -> /dev/nvme0n2p2
NAME          SIZE TYPE
...
nvme0n1       375G disk
|-nvme0n1p1   100G part
| `-md0     199.9G raid0
`-nvme0n1p2   275G part
nvme0n2       375G disk
|-nvme0n2p1   100G part
| `-md0     199.9G raid0
`-nvme0n2p2   275G part

Observe o mapeamento entre o link simbólico google-local-ssd-partition e o nome do dispositivo subjacente, bem como o tamanho dessa partição. Use o tamanho como PARTITION_SIZE e o caminho do link simbólico como LOCAL_SSD_SYMLINK_PATH no manifesto do PersistentVolume.

Por exemplo, na saída anterior, o link simbólico /dev/disk/by-id/google-local-ssd-partition0 aponta para a partição nvme0n1p2, que tem um tamanho de 275G.

O comando kubectl debug deixa um pod temporário em execução no namespace padrão. Para evitar que ele consuma recursos, exclua o pod executando o seguinte comando:

kubectl delete pod DEBUG_POD_NAME

Substitua DEBUG_POD_NAME pelo nome do pod criado pelo comando kubectl debug, que é impresso quando você executa o comando.

Configurar o manifesto do PersistentVolume

Configure o manifesto do volume com o tamanho da partição que você encontrou. O campo nodeAffinity é obrigatório para volumes locais. Isso ajuda a garantir que o Kubernetes programe os pods que reivindicam esse volume para o nó específico em que o SSD local está fisicamente anexado. O exemplo a seguir mostra um manifesto para uma partição de SSD local de bloco bruto:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: "example-local-pv"
spec:
  capacity:
    storage: PARTITION_SIZE
  accessModes:
  - "ReadWriteOnce"
  volumeMode: "Block"
  persistentVolumeReclaimPolicy: "Retain"
  storageClassName: "local-storage"
  local:
    path: "LOCAL_SSD_SYMLINK_PATH"
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: "kubernetes.io/hostname"
          operator: "In"
          values:
          - "NODE_NAME"

Substitua:

  • PARTITION_SIZE: a capacidade bruta real do bloco que sobrou e que você encontrou na primeira etapa. Use o sufixo Gi (por exemplo, 275Gi) para que o valor corresponda exatamente à capacidade da partição.
  • NODE_NAME: o nome do nó em que o SSD local está anexado.
  • LOCAL_SSD_SYMLINK_PATH: o caminho do link simbólico para a partição do SSD local não formatada que você encontrou na primeira etapa. Para cada SSD local anexado ao pool de nós, o SO host cria um link simbólico para acessar a capacidade restante do bloco bruto. Os caminhos seguem um padrão indexado por zero. Por exemplo, se você anexar três SSDs locais, os caminhos de bloco bruto para as partições serão os seguintes:
    • /dev/disk/by-id/google-local-ssd-partition0
    • /dev/disk/by-id/google-local-ssd-partition1
    • /dev/disk/by-id/google-local-ssd-partition2

Criar o PersistentVolumeClaim

Crie um objeto PersistentVolumeClaim para reivindicar o volume. A especificação correspondente tem esta aparência:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: "example-local-pvc"
spec:
  accessModes:
  - "ReadWriteOnce"
  volumeMode: "Block"
  storageClassName: "local-storage"
  resources:
    requests:
      storage: PARTITION_SIZE

Usar o volume em um pod

É possível usar o objeto PersistentVolume em um pod referenciando o objeto PersistentVolumeClaim em uma especificação volumeDevices. Veja a seguir um exemplo de manifesto de pod que usa a declaração example-local-pvc:

apiVersion: v1
kind: Pod
metadata:
  name: "example-pod"
spec:
  containers:
  - name: "app"
    image: "ubuntu:22.04"
    command: ["/bin/sh", "-c"]
    args: ["tail -f /dev/null"]
    volumeDevices:
    - name: "raw"
      devicePath: "/dev/xvda"
  volumes:
  - name: "raw"
    persistentVolumeClaim:
      claimName: "example-local-pvc"

Como você está usando o provisionador kubernetes.io/no-provisioner, o GKE não limpa automaticamente os volumes locais. Se você excluir o objeto PersistentVolume, será necessário apagar manualmente os dados do disco subjacente antes que ele possa ser reutilizado com segurança.

Solução de problemas

Para instruções sobre solução de problemas, consulte Como resolver problemas de armazenamento no GKE.

A seguir