Dockerfile vs buildpacks: qual escolher para a sua aplicação?
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.jsone instala as dependências antes de copiar o resto do código. - Builds em várias etapas: várias instruções
FROMno 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 rebaseaponta 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
| Dockerfile | Buildpacks | |
|---|---|---|
| Controlo | Total: imagem base, pacotes, utilizadores, estrutura de ficheiros | Dentro das opções do buildpack: versões fixadas, Procfile, pacotes extra |
| Manutenção | Cabe-lhe atualizar a imagem base e cada passo | O responsável pela manutenção do builder atualiza a stack e os buildpacks de linguagem |
| Atualizações de segurança | Novo build com uma imagem base corrigida; tem de estar atento às correções | As 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 |
| Reprodutibilidade | Depende do rigor com que fixa as imagens e os pacotes | Integrada para as mesmas entradas, com marcas temporais fixas nas camadas |
| Velocidade de build | Rápido com uma cache de camadas bem ordenada; uma alteração no início reconstrói tudo o que vem a seguir | As camadas em cache, como as dependências, são restauradas entre builds |
| Multi-stage | Sim, várias etapas FROM | Desnecessário: as ferramentas de build ficam na imagem de build |
| Stacks invulgares | Tudo o que for possível instalar numa imagem | Apenas 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.tomlou numAptfile; os respetivos scripts de manutenção (maintainer scripts) não são executados. - Um
Procfiledefine os tipos de processo; caso contrário, a configuração por omissão da linguagem define o processoweb. - 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
.dockerignorenesse 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
PORTnuma aplicação com Dockerfile. Configure a aplicação para escutar na porta do processo web, que vem pré-preenchida a partir deEXPOSEe pode ser alterada no separador Processes; se a lista de processos estiver vazia, a Nodion usa oEXPOSEda 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. UmHEALTHCHECKna imagem é ignorado. - O
USERda 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.