Como usar vários contextos de compilação do Docker para acelerar a montagem da imagem

0
38


O conceito de “contexto de compilação” do Docker é um de seus recursos mais restritivos e incompreendidos. O contexto de compilação define os arquivos e pastas locais que você pode fazer referência em seu Dockerfile. O conteúdo fora dele não pode ser usado, o que geralmente dificulta os procedimentos de compilação complexos.

Joyeux anniversaire pour ami
Joyeux anniversaire pour ami

O BuildKit v0.8 melhora essa situação, permitindo que você use vários contextos com cada compilação que você faz. Isso facilita a referência de arquivos que podem residir em locais completamente separados, como um arquivo em seu diretório de trabalho e uma dependência de uma URL remota.

Neste artigo, explicaremos por que vários contextos de compilação são úteis e como você pode usá-los com a versão mais recente da CLI do Docker. Primeiro, vamos recapitular o que é contexto de construção e por que tantas pessoas tiveram problemas no passado.

Objetivo do contexto de construção

O Docker é baseado em daemons. O processo que executa suas construções de imagem é separado do processo CLI que emite o comando. O daemon pode estar localizado em um host remoto que não pode acessar diretamente o sistema de arquivos da sua máquina.

O contexto de compilação refere-se aos arquivos que são passados ​​para o daemon do Docker quando ocorre uma compilação. É por isso que seu Dockerfile só pode referenciar conteúdo dentro do contexto.

É comum correr docker build com . como seu argumento, o que torna seu diretório de trabalho o contexto de compilação:

docker build -t my-website:latest .

Isso permite referências a qualquer caminho dentro do seu diretório de trabalho:

FROM httpd:latest
COPY index.html /var/www/html/index.html

Você não pode chegar perto de copiar nada. Acima o diretório de trabalho em seu sistema de arquivos:

FROM httpd:latest
COPY index.html /var/www/html/index.html
COPY ../company-css/company.css /var/www/html/company.css

Cada arquivo necessário em sua imagem de contêiner deve existir em um único diretório que você pode usar como contexto de compilação. Isso pode ser problemático em situações como a mostrada acima, em que você deseja obter dependências de origem que não estão em sua árvore de projeto.

Como usar vários contextos de compilação

Vários contextos de compilação agora são suportados no BuildKit v0.8 e posterior quando você opta pela sintaxe Dockerfile v1.4. Essas versões são fornecidas com a CLI do Docker a partir da versão 20.10.13. Você deve poder usá-los hoje se estiver executando a versão mais recente do Docker.

Você deve construir sua imagem com o BuildKit para usar vários contextos. Eles não são compatíveis com o gerador legado. Use o docker buildx build comando em vez de simples docker build:

$ docker buildx build -t my-website:latest .

Agora você pode usar o --build-context sinalizador para definir vários contextos de compilação nomeados:

$ docker buildx build -t my-website:latest . 
    --build-context company-css=../company-css 
    --build-context company-js=../company-js 

Ajuste seu Dockerfile para fazer referência ao conteúdo destes contextos:

#syntax=docker/dockerfile:1.4
FROM httpd:latest
COPY index.html /var/www/html/index.html
COPY --from=company-css /company.css /var/www/html/company.css
COPY --from=company-js /company.js /var/www/html/company.js

Isso ilustra como você pode copiar arquivos e pastas que estão fora do contexto de compilação principal, independentemente de sua posição na árvore do sistema de arquivos.

A declaração de sintaxe do Dockerfile v1.4 é necessária para habilitar o suporte para o recurso. Você pode então usar o --from opção com ADD S COPY instruções para extrair arquivos de contextos de compilação nomeados, semelhante a fazer referência a um recurso em um estágio de compilação anterior.

ordem de prioridade

Vários contextos de compilação modificam a ordem de resolução de recursos para o --from bandeira. O Docker agora corresponderá à chave que você fornecer (--from=key) usando o seguinte procedimento:

  • Procure um contexto de compilação nomeado definido com o --build-context bandeira.
  • Encontre um estágio de compilação anterior criado com FROM my-image:latest AS stage-name.
  • Crie um novo estágio de compilação online usando a chave fornecida como a imagem do estágio.

Isso significa que você pode usar contextos nomeados para substituir dependências remotas definidas pelos estágios de compilação.

Considere este exemplo:

#syntax=docker/dockerfile:1.4
FROM my-org/company-scss:latest AS css
RUN sass company.scss company.css

FROM httpd:latest
COPY index.html /var/www/html/index.html
COPY --from=css /company.css /var/www/html/company.css

Essa imagem do Docker extrai alguns recursos remotos de outra imagem compartilhada do Docker. Isso pode criar dificuldades quando você estiver testando seu projeto; pode haver um bug na dependência que você deseja corrigir rapidamente.

Contextos de compilação nomeados permitem que você substitua o css nome do estágio para fornecer um arquivo local:

$ docker buildx build -t my-website:latest . --build-context css=css/

Isso copiará seu diretório de trabalho css/company.css arquivo na imagem final, em vez da versão fornecida pelo my-org/company-scss:latest dependência.

A ordem de resolução significa que as substituições podem ser aplicadas mesmo que sua imagem não use estágios de compilação nomeados. Ao definir um contexto de compilação com o mesmo nome de uma imagem, seu Dockerfile extrairá o conteúdo desse contexto, em vez da imagem de registro original.

$ docker buildx build -t my-website:latest . --build-context my-org/company-scss:latest=css/

URLs remotos

Contextos de compilação nomeados suportam todas as fontes que docker build já aceito:

  • --build-context my-context=../local/path – Um caminho em seu sistema de arquivos.
  • --build-context my-context=https://github.com/user/repo.git – Um repositório Git remoto.
  • --build-context my-context=https://example.com/data.tar – Um tarball remoto fornecido por um servidor HTTP.
  • --build-context my-context=docker-image://busybox:latest – O conteúdo de outra imagem do Docker.

As fontes remotas simplificam ainda mais as substituições de dependência. Você pode apontar diretamente para um repositório Git bifurcado ou uma tag de imagem do Docker diferente, tudo isso sem alterar seu Dockerfile.

Montando arquivos de um contexto de compilação

Contextos de compilação nomeados funcionam com RUN instruções também. Você pode usar --mount=from para executar um executável de outro contexto de compilação.

#syntax=docker/dockerfile:1.4
RUN --mount=from=name-of-build-context demo-executable

Isso monta o arquivo sem copiá-lo para a camada atual, o que ajuda a melhorar o desempenho. demo-executable ele não existirá na imagem final.

Reconstruir imagens com precisão

Outro caso de uso para contextos de construção nomeados diz respeito à reconstrução de imagens no futuro. Dockerfiles com instruções como FROM alpine:3.15 Eles não são totalmente reproduzíveis. As tags de imagem são mutáveis, então alpine:3.15 ele pode conter conteúdo diferente no futuro, após o lançamento de um novo patch. Isso significa que as imagens reconstruídas não têm garantia de produzir as mesmas camadas que suas versões originais.

Você pode resolver esse problema inspecionando os metadados da primeira compilação para descobrir a imagem de base exata que foi usada:

$ docker buildx imagetools inspect --format '{{json .BuildInfo}}' my-image:latest
{
    ...
    "sources": [
        {
            "type": "docker-image",
            "ref": "docker.io/library/alpine:3.15",
            "pin": "sha256:4edbd2beb5f78b1014028f4fbb99f3237d9561100b6881aabbf5acce2c4f9454"
        }
    ]
    ...
}

Agora você pode definir um contexto de compilação nomeado chamado alpine:3.15 que aponta para a versão exata que foi usada anteriormente:

$ docker buildx build -t my-image:latest . --build-context alpine:3.15=docker-image://[email protected]cce2c4f9454

Isso facilita a criação de uma reconstrução precisa de uma imagem criada anteriormente, sem precisar modificar seu Dockerfile.

conclusão

Vários contextos de compilação oferecem mais opções para organizar Dockerfiles complexos e árvores de diretórios de projetos. Eles resolvem desafios de usabilidade de longa data que você pode enfrentar com um único contexto de construção.

Os contextos de compilação nomeados permitem incluir dependências fora da árvore e fazer substituições ad-hoc. Eles funcionam bem em conjunto com os estágios de construção nomeados existentes do Docker. A combinação dos dois recursos ajuda a criar Dockerfiles modulares que podem ser personalizados em tempo de compilação.

Você pode começar com vários contextos de compilação hoje atualizando para o Docker 20.10.13 ou posterior e usando docker buildx para criar suas imagens. As distribuições autônomas do BuildKit também estão disponíveis quando você não deseja instalar a CLI inteira do Docker.