View a markdown version of this page

Criar uma variante personalizada da AMI Bottlerocket para o Amazon EKS - Amazon EKS

Ajudar a melhorar esta página

Para contribuir com este guia de usuário, escolha o link Editar esta página no GitHub, disponível no painel direito de cada página.

Criar uma variante personalizada da AMI Bottlerocket para o Amazon EKS

Ao executar workloads de GPU no Amazon Elastic Kubernetes Service (Amazon EKS), você escolhe uma variante do Bottlerocket. A variante deve corresponder à sua versão do Kubernetes e ao tipo de acelerador. O Bottlerocket oferece nativamente variantes validadas para configurações comuns. No entanto, sua organização pode precisar de uma variante diferente por qualquer um dos seguintes motivos:

  • Uma ramificação mais recente de drivers da NVIDIA

  • Uma versão fixa de driver para conformidade regulatória

  • Pacotes adicionais para monitoramento

  • Uma linha de base reforçada exigida por sua equipe de segurança

Como o Bottlerocket no site do GitHub é totalmente de código aberto, você pode criar uma variante personalizada que atenda a essas necessidades. Este tópico mostra como clonar uma variante existente e trocar o driver NVIDIA da ramificação R580 para a R595 (versão 595.71.05). Você então cria a imagem e a registra como uma AMI privada.

Importante

O tipo de instância G7 do EC2 requer a versão 595 ou posterior do driver NVIDIA. Atualmente, as AMIs Bottlerocket NVIDIA para EKS incluem a versão 580 do driver NVIDIA, que não é compatível com instâncias G7.

Consulte o repositório do Bottlerocket no site do GitHub para obter instruções sobre como criar uma variante com a versão 595 do driver NVIDIA. Este tópico explica todo o processo, começando na Etapa 1.

Como o sistema de compilação funciona

Quando você executa cargo make -e BUILDSYS_VARIANT=aws-k8s-1.36-nvidia, ocorrem três coisas:

  • Busca dependências. O Twoliter (o orquestrador de compilação do Bottlerocket) lê Twoliter.toml e extrai três artefatos da Open Container Initiative (OCI) de public.ecr.aws/bottlerocket:

    • bottlerocket-sdk: uma imagem de contêiner com a cadeia de ferramentas de compilação cruzada completa (GCC, Rust, Go, macros RPM).

    • bottlerocket-kernel-kit: RPMs pré-compilados para kernels, módulos de kernel (incluindo pacotes kmod da NVIDIA) e firmware.

    • bottlerocket-core-kit: RPMs pré-compilados para o espaço do usuário: kubelet, containerd, plug-in de dispositivo e kit de ferramentas de contêineres da NVIDIA, plug-ins de configurações e serviços do sistema.

      O Twoliter.toml fixa as versões e o Twoliter.lock bloqueia seus resumos. Para alterar qualquer um deles, execute ./tools/twoliter/twoliter update para resolver novamente.

  • Cria a variante. O Twoliter inicializa uma compilação do Docker dentro do contêiner do SDK. Ele compila a crate settings-defaults da sua variante, resolve a árvore de dependências RPM dos kits e monta tudo em uma imagem de disco.

  • Saída. O Twoliter grava o arquivo final .img.lz4 em build/images/. A compilação produz uma saída determinística: as mesmas fixações Twoliter.toml e o Cargo.toml da variante sempre geram a mesma imagem, independentemente do host.

Layout do repositório

Os seguintes diretórios são relevantes para o trabalho de variantes:

bottlerocket/ ├── Cargo.toml # workspace: lists every variant ├── Twoliter.toml # pins SDK + kit versions ├── Twoliter.lock # locked digests for the above ├── Licenses.toml # you create this (NVIDIA license acknowledgement) ├── Infra.toml # you create this (AMI publish regions) │ ├── variants/ │ ├── aws-k8s-1.36-nvidia/ # example variant you'll copy │ │ ├── Cargo.toml # package list + kernel params │ │ └── amispec.toml # symlink → ../shared/amispec-split.toml │ └── shared/ # shared AMI spec templates │ ├── sources/ │ ├── Cargo.toml # workspace: lists every settings-defaults crate │ ├── shared-defaults/ # the actual defaults (symlink targets) │ └── settings-defaults/ │ └── aws-k8s-1.36-nvidia/ │ ├── Cargo.toml │ └── defaults.d/ # 30+ symlinks into shared-defaults/ │ └── packages/ ├── settings-defaults/ │ └── settings-defaults.spec # RPM: declares which variants exist └── settings-plugins/ └── settings-plugins.spec # RPM: maps variants to settings plugins

Analise as seguintes observações sobre a estrutura do repositório:

  • Uma variante consiste principalmente em metadados. Os kits externos fornecem o kernel, os drivers e o espaço do usuário.

  • Os arquivos settings-defaults são links simbólicos, não cópias. Use cp -R (não cp -r no macOS) para preservá-los.

  • Adicionar uma variante requer edições em cinco lugares: dois arquivos Cargo.toml do espaço de trabalho, dois arquivos .spec e README.md.

Pré-requisitos

Para concluir este passo a passo, você precisa de:

  • Uma conta da AWS com permissões para inicializar instâncias do EC2 e registrar AMIs

  • Uma instância do EC2 (ou um host Linux x86_64 equivalente) com pelo menos 8 núcleos, 16 GiB de memória e 150 GB de disco

  • Ubuntu 24.04 LTS (ou Fedora; o macOS não é compatível como host de compilação)

  • Docker 20.10 ou posterior

  • Rust (cadeia de ferramentas estável, instalada via rustup)

  • cargo-make (versão mais recente)

  • Familiaridade com Git, o Cargo do Rust e conceitos de empacotamento RPM

nota

Ao concluir este passo a passo, encerre a instância do EC2 e cancele o registro de todas as AMIs de que você não precisa mais para evitar cobranças contínuas. Para obter instruções de limpeza, consulte Liberar.

Etapa 1: preparar o host de compilação

Inicialize uma instância do EC2: por exemplo, uma c7i.8xlarge (32 vCPU, 64 GiB de memória). Use um volume raiz gp3 de 150 GB e anexe a política gerenciada AmazonSSMManagedInstanceCore para acesso do SSM.

Conecte-se à instância usando o Gerenciador de Sessões do AWS Systems Manager (SSM):

aws ssm start-session --target <instance-id> cd ~

Instale os pacotes necessários do sistema operacional:

apt-get update apt-get install -y build-essential openssl libssl-dev pkg-config lz4 \ git ca-certificates curl gnupg
nota

O BUILDING.md oficial faz referência ao liblz4-tool. Nas versões recentes do Ubuntu, o pacote é denominado lz4.

Instale o Docker usando os seguintes comandos:

install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \ https://download.docker.com/linux/ubuntu noble stable" \ > /etc/apt/sources.list.d/docker.list apt-get update apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin systemctl enable --now docker

Instale o Rust e o cargo-make usando os seguintes comandos:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y . "$HOME/.cargo/env" cargo install cargo-make

Etapa 2: clonar o repositório

Clone o repositório do Bottlerocket no site do GitHub e navegue até o diretório:

cd ~/bottlerocket

Para criar uma compilação reproduzível, confira uma versão marcada (por exemplo, git checkout v1.62.1). Para usar os pacotes mais recentes, permaneça na ramificação develop.

Etapa 3: verificar as versões dos kits

Abra Twoliter.toml e confirme as versões dos kits. Para compatibilidade com o R595, você precisa da versão 6.2.2 ou posterior do bottlerocket-kernel-kit:

[[kit]] name = "bottlerocket-kernel-kit" version = "6.2.2" vendor = "bottlerocket"

Se a versão for mais antiga, atualize-a e gere o bloqueio novamente:

./tools/twoliter/twoliter update

Etapa 4: contornar o problema de caminho do cargo-make

O Twoliter define CARGO_HOME como ~/bottlerocket/.cargo, o que impede que o processo interno do Cargo encontre o cargo-make instalado globalmente. Criar um symlink:

mkdir -p ~/bottlerocket/.cargo/bin ln -sf /root/.cargo/bin/cargo-make ~/bottlerocket/.cargo/bin/cargo-make

Sem essa etapa, a compilação falhará com error: no such command: make.

Etapa 5: encontrar ramificações de driver disponíveis

Os pacotes kmod da NVIDIA são disponibilizados dentro do bottlerocket-kernel-kit. Para obter informações sobre os pacotes de drivers disponíveis, consulte o diretório de pacotes do kernel-kit ou as notas de versão no site do GitHub.

Para o kernel 6.18 (usado por variantes aws-k8s-1.36):

kmod-6.18-nvidia-r580 ← driver 580.159.03 (current default) kmod-6.18-nvidia-r595 ← driver 595.71.05

Para o kernel 6.12 (usado por aws-k8s-1.33, 1.34, 1.35):

kmod-6.12-nvidia-r580 kmod-6.12-nvidia-r595
nota

Cada pacote kmod disponibiliza subpacotes (-tesla, -open-gpu, -grid, -fabricmanager, -imex). As variantes oficiais NVIDIA do Bottlerocket fazem referência ao -tesla, que inclui todos os subpacotes necessários por meio de dependências RPM. Durante a inicialização, o Bottlerocket seleciona automaticamente o tipo de driver apropriado com base no tipo de instância.

Etapa 6: criar a nova variante

Copie a variante existente. Use cp -R para preservar os links simbólicos:

cp -R variants/aws-k8s-1.36-nvidia variants/aws-k8s-1.36-nvidia-595 cp -R sources/settings-defaults/aws-k8s-1.36-nvidia \ sources/settings-defaults/aws-k8s-1.36-nvidia-595

Editar o variants/aws-k8s-1.36-nvidia-595/Cargo.toml:

- name = "aws-k8s-1_36-nvidia" + name = "aws-k8s-1_36-nvidia-595" - "kmod-6.18-nvidia-r580-tesla", + "kmod-6.18-nvidia-r595-tesla",

Editar o sources/settings-defaults/aws-k8s-1.36-nvidia-595/Cargo.toml:

- name = "settings-defaults-aws-k8s-1_36-nvidia" + name = "settings-defaults-aws-k8s-1_36-nvidia-595"

Etapa 7: registrar a variante

Registre a nova variante em cinco arquivos:

1. Cargo.toml : adicione o membro do espaço de trabalho:

"variants/aws-k8s-1.36-nvidia", + "variants/aws-k8s-1.36-nvidia-595", "variants/aws-k8s-1.36-nvidia-fips",

2. sources/Cargo.toml : adicione o membro settings-defaults:

"settings-defaults/aws-k8s-1.36-nvidia", + "settings-defaults/aws-k8s-1.36-nvidia-595",

3. packages/settings-defaults/settings-defaults.spec : adicione um bloco %package, entradas nos dois loops de compilação e uma seção %files:

%package aws-k8s-1.36-nvidia-595 Summary: Settings defaults for the aws-k8s 1.36 nvidia-595 variant Requires: %{_cross_os}variant(aws-k8s-1.36-nvidia-595) Provides: %{_cross_os}settings-defaults(any) Provides: %{_cross_os}settings-defaults(aws-k8s-1.36-nvidia-595) Conflicts: %{_cross_os}settings-defaults(any) %description aws-k8s-1.36-nvidia-595 %{summary}.

Adicione aos dois loops for defaults in:

aws-k8s-1.36-nvidia \ + aws-k8s-1.36-nvidia-595 \ metal-dev \

Adicione a seção %files:

%files aws-k8s-1.36-nvidia-595 %{_cross_defaultsdir}/aws-k8s-1.36-nvidia-595.toml %{_cross_tmpfilesdir}/storewolf-defaults-aws-k8s-1.36-nvidia-595.conf

4. packages/settings-plugins/settings-plugins.spec : adicione uma linha Provides: abaixo de %package aws-k8s-nvidia:

Provides: %{_cross_os}settings-plugin(aws-k8s-1.36-nvidia) +Provides: %{_cross_os}settings-plugin(aws-k8s-1.36-nvidia-595) Conflicts: %{_cross_os}settings-plugin(any)

Etapa 8: atualizar o arquivo de bloqueio

Adicionar um membro do espaço de trabalho invalida o sources/Cargo.lock. Atualize-o:

cd ~/bottlerocket/sources cargo update --workspace
Importante

Não use o cargo generate-lockfile. Ele reescreve todo o arquivo de bloqueio e incrementa as versões das dependências transitivas, o que causa erros de versão duplicada no cargo-deny.

Etapa 9: criar o arquivo de licença da NVIDIA

A NVIDIA restringe a redistribuição das fontes de drivers. Você deve adicionar uma confirmação explícita da licença antes de compilar:

cat > ~/bottlerocket/Licenses.toml <<'EOF' [nvidia] spdx-id = "LicensesRef-NVIDIA-Customer-Use" licenses = [ { path = "LICENSE", license-url = "https://www.nvidia.com/en-us/drivers/nvidia-license/" } ] EOF

Etapa 10: compilar e publicar a AMI

Crie um Infra.toml com suas regiões de destino:

cat > ~/bottlerocket/Infra.toml <<'EOF' [aws] regions = ["us-west-2", "us-east-1", "us-east-2"] EOF

Compilar a imagem:

cd ~/bottlerocket cargo make \ -e BUILDSYS_VARIANT=aws-k8s-1.36-nvidia-595 \ -e BUILDSYS_UPSTREAM_SOURCE_FALLBACK=true \ -e BUILDSYS_UPSTREAM_LICENSE_FETCH=true \ -e BUILDSYS_JOBS=32

A primeira compilação extrai as imagens do SDK e do kit (aproximadamente 2 GB no total). As compilações subsequentes levam de 3 a 5 minutos em um host de 32 núcleos.

Publicar a AMI:

cargo make \ -e BUILDSYS_VARIANT=aws-k8s-1.36-nvidia-595 \ -e PUBLISH_REGIONS=us-west-2,us-east-1,us-east-2 \ ami

A compilação grava os IDs das AMIs em build/images/x86_64-aws-k8s-1.36-nvidia-595/latest/*-amis.json. Use-os em seus grupos de nós gerenciados pelo EKS, no EC2NodeClass do Karpenter ou em modelos de inicialização.

Outras combinações que você pode compilar

Este passo a passo troca a ramificação do driver NVIDIA, mas você pode usar a mesma abordagem para qualquer pacote disponível nos kits upstream. Os seguintes exemplos mostram o que você pode montar sem bifurcar um kit:

O que você quer O que alterar no Cargo.toml da variante

Outra ramificação de driver NVIDIA

kmod-6.18-nvidia-r580-teslakmod-6.18-nvidia-r595-tesla

Outra versão do kernel

kernel-6.18kernel-6.12 (ajuste o kmod de acordo)

Remover o NVIDIA por completo

Exclua as três linhas nvidia-* de included-packages

Adicionar suporte ao EFA

Adicionar kmod-6.18-efa a included-packages

Alternar a versão do runtime do container

containerd-2.2containerd-2.1

Para obter informações sobre os pacotes disponíveis, consulte o kernel-kit e o core-kit no site do GitHub.

Importante

O sistema de arquivos raiz do Bottlerocket é imutável. Você não pode instalar pacotes no runtime. Cada pacote nos kits é compilado de forma cruzada especificamente para o Bottlerocket. Os RPMs upstream padrão não funcionam. Se você precisar de um software que ainda não esteja em um kit, considere os contêineres bootstrap ou os contêineres host no site do GitHub como uma alternativa de runtime.

Liberar

Se você não precisar mais do host de compilação, encerre a instância do EC2 para evitar cobranças contínuas. As AMIs persistem de forma independente em sua conta; cancele o registro delas no console do EC2 ou na CLI se você não precisar mais delas.

Resumo

Este tópico mostrou como criar uma variante personalizada do Bottlerocket com outra ramificação do driver NVIDIA. O processo envolve copiar uma variante existente, alterar uma referência de pacote, registrar a nova variante no espaço de trabalho e nas especificações RPM e executar a compilação. A mesma abordagem se aplica a qualquer customização: trocar versões do kernel, adicionar pacotes ou criar variantes para novas versões do Kubernetes.