Como usar o Docker Buildx Bake para criar pipelines de construção de imagens complexas

Publicados: 2022-08-10

Gráfico mostrando o logotipo do Docker

O grupo de comandos docker buildx usa o BuildKit para expor recursos avançados de criação de imagens. As compilações preparadas são um recurso de alto nível que pode ser usado para definir pipelines de compilação automatizados. Eles permitem que você produza várias imagens a partir de uma única operação de compilação.

Os fluxos de trabalho preparados são úteis quando você deseja publicar diferentes variantes de suas imagens ou criar vários projetos vinculados em paralelo. Neste artigo, abordaremos os principais recursos do docker buildx bake e como você pode usá-los para simplificar compilações complexas.

Começando

O comando docker buildx bake executa vários "destinos" de compilação, cada um produzindo uma imagem de contêiner. Os alvos são executados em paralelo sempre que possível para maximizar o desempenho. Os destinos também podem fazer referência direta aos predecessores para criar pipelines sequenciais.

Os destinos de compilação podem ser definidos usando vários mecanismos diferentes, incluindo arquivos existentes do Docker Compose. O Buildx construirá automaticamente todas as imagens identificadas no arquivo.

Recursos mais avançados são expostos quando você lista destinos de compilação em arquivos JSON ou HCL. Essas variáveis ​​de suporte, funções e interpolação de valor para personalizar suas compilações.

O comando buildx bake procura os seguintes arquivos em ordem:

  • docker-compose.yml
  • docker-compose.yaml
  • docker-bake.json
  • docker-bake.override.json
  • docker-bake.hcl
  • docker-bake.override.hcl

Você pode especificar um arquivo diferente com o sinalizador de comando -f .

Construir alvos

Os destinos de compilação encapsulam toda a configuração relacionada à sua compilação. Eles incluem detalhes como

  • o caminho para o Dockerfile para construir
  • construir caminhos de contexto, definindo o conteúdo disponível em seu Dockerfile
  • tags e rótulos para anexar às imagens de saída
  • as plataformas para produzir imagens.

Uma lista completa de campos de configuração suportados está disponível na documentação. Anteriormente, você pode ter fornecido essas configurações como sinalizadores de linha de comando para docker buildx build (ou até mesmo docker build ), forçando você a lembrar os valores corretos a cada vez. Com buildx bake , você pode usar os mesmos valores de maneira confiável, definindo-os em seu arquivo assado com controle de versão.

Aqui está um exemplo simples de um comando docker-bake.hcl que define um único destino de compilação:

 target "default" { dockerfile = "app/Dockerfile" contexts = { app = "app/src" shared = "shared-components/src" } tags = ["my-app:latest", "docker.io/my-org/my-app:latest"] }

A execução docker buildx bake com este arquivo bake carregará o app/Dockerfile Dockerfile do seu diretório de trabalho. Ele terá acesso aos diretórios app/src e shared-components/src como contextos de construção. A imagem produzida receberá duas tags.

O destino default é criado automaticamente quando você executa o docker buildx bake . Você também pode definir destinos nomeados que podem ser criados sob demanda:

 target "app" { // ... }
 $ docker buildx bake app

Usando vários destinos

Você pode construir outra imagem simultaneamente definindo-a como um novo alvo dentro do seu arquivo bake:

 group "default" { targets = ["app", "api"] } target "app" { dockerfile = "app/Dockerfile" contexts = { app = "app/src" shared = "shared-components/src" } tags = ["my-app:latest", "docker.io/my-org/my-app:latest"] } target "api" { dockerfile = "api/Dockerfile" contexts = { src = "api/src" } tags = ["my-api:latest", "docker.io/my-org/my-api:latest"] }

Essas imagens podem ser criadas simultaneamente porque estão aninhadas em um grupo. As imagens da api e app serão compiladas em paralelo sempre que você executar o comando docker buildx bake , pois o grupo default é selecionado automaticamente. Você pode usar grupos nomeados de maneira semelhante ao exemplo de destinos nomeados acima.

Criar herança de destino

Os destinos de compilação podem herdar uns dos outros para reutilizar a configuração. Um cenário em que isso pode ser útil diz respeito a imagens que precisam ser personalizadas para diferentes ambientes. Você pode querer adicionar arquivos de configuração extras às variantes de imagem destinadas ao uso em desenvolvimento. Aqui está um docker-bake.hcl que demonstra esse modelo:

 group "default" { targets = ["backend", "backend-dev"] } target "backend" { dockerfile = "backend/Dockerfile" contexts = { src = "api/src" config = "api/config" } tags = ["backend:latest"] } target "backend-dev" { inherits = ["backend"] contexts = { config = "api/config-dev" } tags = ["backend:dev"] }

O destino backend-dev herda todas as propriedades do destino backend -end, mas substitui o contexto de config e aplica uma tag diferente.

Você pode visualizar a estrutura do arquivo mesclado executando o comando bake com o sinalizador --print :

 $ docker buildx bake --print ... "backend-dev": { "context": ".", "contexts": { "config": "api/config-dev", "src": "api/src" }, "dockerfile": "backend/Dockerfile", "tags": [ "backend:dev" ] } ...

Usando um alvo anterior como uma imagem de base

Às vezes, você pode querer que um destino de compilação use a imagem criada por um destino anterior como sua própria base. Essa é uma alternativa para compilações de vários estágios que podem ser usadas quando seus Dockerfiles dependem uns dos outros, mas não podem ser mesclados, talvez porque existam em projetos diferentes.

 group "default" { targets = ["org-base-image", "api"] } target "org-base-image" { dockerfile = "docker-base/Dockerfile" tags = ["org-base-image:latest"] } target "api" { dockerfile = "api/Dockerfile" contexts = { base = "target:org-base-image" } tags = ["api:latest"] }

O exemplo primeiro cria o destino org-base-image . Isso pode conter alguns utilitários comuns às cargas de trabalho em contêiner da sua organização. O destino da api é então compilado com a saída do destino org-base-image acessível como o build-context base . O API Dockerfile agora pode fazer referência ao conteúdo dentro da imagem base:

 COPY --from=base /utilities/example /usr/bin/example-utility

Este é um padrão poderoso que permite criar links de dependência entre imagens enquanto mantém Dockerfiles separados.

Substituindo propriedades de destinos no tempo de compilação

O comando docker buildx bake permite que você substitua as propriedades de seus destinos ao executar sua compilação:

 $ docker buildx bake --set api.dockerfile="api/Dockerfile-dev"

Este exemplo altera o Dockerfile do destino da api . O curinga * é suportado ao identificar o destino a ser alterado. * por si só seleciona todos os alvos enquanto api* modificará todos os alvos que começam com api .

Configurando Variáveis

Os arquivos HCL podem definir variáveis ​​que você pode fazer referência em seus destinos de compilação. use um bloco variable para configurá-los:

 variable "TAG" { default = "latest" } group "default" { targets = ["app"] } target "app" { dockerfile = "src/Dockerfile" tags = ["my-app:${TAG}"] }

A execução docker buildx bake com essa configuração marcará o destino do app como my-app:latest . Você pode alterar o valor da variável TAG definindo uma variável de ambiente antes de executar o comando:

 $ TAG=v1 docker buildx bake

Você pode usar todos os recursos de interpolação e comparação de variáveis ​​da linguagem HCL para tornar seus destinos de compilação reutilizáveis. As funções também estão disponíveis para analisar e transformar seus valores.

Resumo

As compilações Baked Buildx permitem encapsular a configuração de compilação da imagem como “destinos” definidos em um arquivo. Quando você executa buildx bake , as imagens de todos os destinos referenciados são criadas em paralelo.

Os alvos podem herdar e depender uns dos outros. Você também pode usar variáveis ​​e funções para criar pipelines de compilação altamente complexos e configuráveis.

O comando docker buildx bake é uma operação de alto nível que não é necessária em todos os fluxos de trabalho. Você não precisa usá-lo ao criar imagens simples sem dependências entre projetos. O uso do docker compose build é uma alternativa melhor para a maioria dos casos de uso que mantém a configuração do build no arquivo docker-compose.yml . Mudar para compilações preparadas deve ser considerado quando você estiver compilando muitas imagens simultaneamente usando diferentes variáveis, plataformas, contextos de compilação e substituições de configuração.