Dockerfile vs buildpacks: qual escolher para a sua aplicação?

Um cartão Dockerfile e um cartão buildpacks que convergem numa única imagem de contentor

Em resumo

  • Num Dockerfile, cada passo do build é escrito à mão; os Cloud Native Buildpacks detetam a linguagem e constroem a imagem a partir do código-fonte, sem Dockerfile.
  • Os buildpacks são indicados para aplicações padrão em linguagens suportadas e deixam a manutenção da imagem base a cargo do builder; um Dockerfile é indicado para pacotes de sistema específicos, stacks invulgares e controlo total sobre a imagem.
  • Ambos produzem uma imagem de contentor, por isso pode começar com um e mudar mais tarde.
  • Na Nodion, pode escolher Buildpacks ou Dockerfile por aplicação: as aplicações com buildpacks escutam na PORT definida pela Nodion, as aplicações com Dockerfile na porta de EXPOSE ou do separador Processes.

Tanto um Dockerfile como os buildpacks transformam o seu código-fonte numa imagem de contentor. A diferença está em quem escreve os passos do build: com um Dockerfile, define-os manualmente; com buildpacks, é o buildpack que os deduz a partir do seu código. Use buildpacks para uma aplicação web padrão numa linguagem suportada, e use um Dockerfile quando precisar de controlo total sobre a imagem ou usar uma stack que nenhum buildpack deteta.

O que é um Dockerfile

Nas palavras da própria Docker, um Dockerfile é «a text document that contains all the commands a user could call on the command line to assemble an image», ou seja, um documento de texto com todos os comandos que um utilizador poderia executar na linha de comandos para montar uma imagem. Escolhe-se uma imagem base, instalam-se pacotes do sistema, copia-se o código, instalam-se as dependências e define-se o comando de arranque. É o utilizador que define cada linha, com controlo total e toda a responsabilidade pela manutenção.

FROM node:24-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Duas funcionalidades determinam a forma como os Dockerfiles se escrevem na prática:

  • Cache de camadas: a imagem é construída em camadas (layers), e o Docker guarda-as em cache. Quando uma camada muda, todas as camadas seguintes também são reconstruídas. É por isso que o exemplo copia o package.json e instala as dependências antes de copiar o resto do código.
  • Builds em várias etapas: várias instruções FROM no mesmo ficheiro, cada uma a iniciar uma nova etapa. Compila-se numa etapa e copia-se apenas o resultado para uma imagem final pequena, deixando para trás os compiladores e as ferramentas de build.

O que são buildpacks

Um buildpack é software que analisa o seu código-fonte e determina como fazer o seu build. Os Cloud Native Buildpacks são a norma aberta para isso. Um build passa por fases fixas: detect encontra os buildpacks que correspondem ao seu código, build transforma o código-fonte em artefactos executáveis (por exemplo, ao instalar um runtime e as dependências e ao compilar), e export escreve a imagem OCI final. Não precisa de um Dockerfile; ficheiros opcionais como um Procfile ou project.toml permitem configurar o build e os processos.

Três propriedades distinguem os buildpacks:

  • Imagens de build e de execução separadas: os compiladores e os ficheiros de cabeçalho ficam na imagem de build, e a aplicação é entregue na imagem de execução (run image), sem eles.
  • Rebase: quando a imagem de execução recebe uma atualização, o pack rebase aponta a imagem da aplicação para a nova base sem refazer o build da aplicação.
  • Reprodutibilidade: o lifecycle fixa as datas e horas das camadas num valor constante, pelo que o mesmo código-fonte, o mesmo builder e os mesmos buildpacks produzem a mesma imagem, desde que os próprios buildpacks gerem um resultado reprodutível.

Mais contexto em Cloud Native Buildpacks explicados.

Dockerfile vs buildpacks em resumo

DockerfileBuildpacks
ControloTotal: imagem base, pacotes, utilizadores, estrutura de ficheirosDentro das opções do buildpack: versões fixadas, Procfile, pacotes extra
ManutençãoCabe-lhe atualizar a imagem base e cada passoO responsável pela manutenção do builder atualiza a stack e os buildpacks de linguagem
Atualizações de segurançaNovo build com uma imagem base corrigida; tem de estar atento às correçõesAs atualizações do builder trazem imagens base corrigidas no build seguinte; uma imagem existente precisa de um novo build ou de um rebase explícito
ReprodutibilidadeDepende do rigor com que fixa as imagens e os pacotesIntegrada para as mesmas entradas, com marcas temporais fixas nas camadas
Velocidade de buildRápido com uma cache de camadas bem ordenada; uma alteração no início reconstrói tudo o que vem a seguirAs camadas em cache, como as dependências, são restauradas entre builds
Multi-stageSim, várias etapas FROMDesnecessário: as ferramentas de build ficam na imagem de build
Stacks invulgaresTudo o que for possível instalar numa imagemApenas o que o builder deteta

Quando escolher buildpacks

  • A sua aplicação está escrita numa linguagem suportada pelo builder, como Node.js, Python, Ruby, PHP, Go, Rust, Java, .NET ou Elixir, ou é um site estático.
  • Não quer manter por conta própria as imagens base nem os pacotes do sistema operativo.
  • Executa muitos serviços e quer que todos sejam construídos da mesma forma.
  • A sua equipa conhece a linguagem, não o Docker.

Quando escolher um Dockerfile

  • Precisa de uma imagem base específica, de pacotes do sistema além dos que um buildpack instala, ou de um utilizador personalizado.
  • A sua linguagem ou framework não é detetada pelo builder.
  • O projeto já inclui um Dockerfile funcional, como acontece em muitas aplicações open source.
  • Quer uma imagem mínima graças a um build multi-stage, ou exatamente a mesma imagem localmente, em CI e em produção.

Como a Nodion suporta ambos

Em Applications → New, liga um repositório Git e escolhe Buildpacks ou Dockerfile. A análise dá preferência ao Dockerfile quando encontra um. Pode alterar a estratégia mais tarde em Settings; a alteração aplica-se no deploy seguinte. Se fizer o build noutro lado, faça antes deploy de uma imagem pré-construída.

Buildpacks na Nodion

  • Os Cloud Native Buildpacks da própria Nodion, na stack nodion-26 (Ubuntu 26.04 LTS). Detetam Node.js, Python, Ruby, PHP, Go, Rust, Elixir, Java, .NET e sites estáticos.
  • O processo é executado com um utilizador sem privilégios de root. Os pacotes Debian adicionais são declarados no project.toml ou num Aptfile; os respetivos scripts de manutenção (maintainer scripts) não são executados.
  • Um Procfile define os tipos de processo; caso contrário, a configuração por omissão da linguagem define o processo web.
  • Porta: a Nodion define PORT. A aplicação deve escutar nessa porta; a maioria dos comandos predefinidos usa a porta 8080 se a variável não estiver definida.
web: gunicorn myapp.wsgi --bind 0.0.0.0:$PORT
worker: python worker.py

Dockerfile na Nodion

  • A opção Base directory define o contexto de build, e um .dockerignore nesse diretório é respeitado.
  • Os Dockerfiles com várias etapas funcionam. Não há seletor de etapa, por isso é a última etapa que é executada.
  • As variáveis de ambiente marcadas como Build são passadas como build args (ARG). Os segredos (secrets) do BuildKit não são transmitidos.
  • Porta: a Nodion não define PORT numa aplicação com Dockerfile. Configure a aplicação para escutar na porta do processo web, que vem pré-preenchida a partir de EXPOSE e pode ser alterada no separador Processes; se a lista de processos estiver vazia, a Nodion usa o EXPOSE da imagem e, depois, 8080. A aplicação tem de escutar em todas as interfaces, não apenas em localhost.
  • Health check: a disponibilidade (readiness) é verificada com um HTTP GET ao caminho do health check definido em Settings (por omissão /). Uma resposta 2xx ou 3xx indica que a aplicação está operacional. Um HEALTHCHECK na imagem é ignorado.
  • O USER da imagem é respeitado.

Todos os detalhes estão na documentação dos buildpacks e na documentação do Dockerfile. Ainda não sabe qual escolher? Comece com buildpacks e acrescente um Dockerfile no dia em que precisar de algo que eles não conseguem fazer.

Perguntas frequentes

Preciso de um Dockerfile para fazer deploy de um contentor?

Não. Os buildpacks constroem uma imagem de contentor diretamente a partir do código-fonte, sem Dockerfile no repositório. Também pode fazer deploy de uma imagem pré-construída a partir de um registry.

Os buildpacks são melhores do que um Dockerfile?

Nenhum é melhor em termos gerais. Os buildpacks exigem menos manutenção para aplicações padrão em linguagens suportadas, enquanto um Dockerfile dá controlo total sobre a imagem e funciona com qualquer stack.

Posso usar um Dockerfile multi-stage na Nodion?

Sim. Os Dockerfiles multi-stage funcionam. Não há seletor de etapa, por isso a imagem executada é a da última etapa.

Em que porta deve a minha aplicação escutar?

Com buildpacks, a aplicação deve escutar na porta indicada pela variável de ambiente PORT, definida pela Nodion. Com um Dockerfile, a Nodion não define PORT: configure a aplicação para escutar na porta do processo web, obtida de EXPOSE ou definida no separador Processes, em todas as interfaces.

Dê uma cloud ao seu agente.

Ganhe até 15 € de crédito ao registar-se.

Continuar com o GitHub

ou com e-mail

Fique a par das novidades.

Novidades do produto, sem spam. Pode cancelar a subscrição a qualquer momento.