Anúncios incomodam? Ir Sem anúncios Hoje

Construções Multifases do Docker Reduza o seu Imagem Sem Quebrar a Implantação

Atualizado em

Uma demonstração prática de builds multi-etapa do Docker — tamanhos reais antes/depois das imagens, exemplos de arquivos Docker funcionais para Node.js e Python, e os erros que afetam todas as equipes pelo menos uma vez.

Construções Multifases do Docker: Reduza seu imagem sem quebrar a implantação 1
ANUNCIADO Remover?

Sua imagem do Node.js é de 1,1 GB. Você adicionou .dockerignore, eliminou dependências de desenvolvimento, tentou node:slim — não houve mudança significativa. A solução real é as construções multifases. Se você ainda não mudou, está enviando o compilador do TypeScript para a produção.

As construções multifases estão disponíveis no Docker desde a versão 17.05 (2017). Elas são apenas pouco utilizadas. Aqui está uma demonstração real: quais as mudanças, qual a diferença de tamanho e os três erros comuns que afetam as equipes na primeira migração.

O problema da única fase

A maioria dos Dockerfiles começa assim:

FROM node:20

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

EXPOSE 3000
CMD ["node", "dist/server.js"]

Construa isso e verifique com docker images: ~1,1 GB. Você está enviando a imagem completa do Node 20 com npm, sua cadeia de ferramentas do TypeScript, todas as dependências de desenvolvimento e sua árvore de fontes. Nada disso é executado em produção — o aplicativo precisa apenas do resultado compilado e de poucos pacotes de execução. dist/ .

Construções multifases: a solução

Cada FROM instrução inicia uma nova fase com um sistema de arquivos limpo. Nomeie as fases com AS, em seguida, use COPY --from=stagename para extrair arquivos específicos para a próxima fase. As fases intermediárias não são incluídas na imagem final — elas são artefatos de construção, descartadas após a COPY ser concluída.

Aqui está o mesmo aplicativo como uma construção multifase correta:

# ---- Build stage ----
FROM node:20 AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build


# ---- Runtime stage ----
FROM node:20-alpine AS runtime

WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist

EXPOSE 3000
CMD ["node", "dist/server.js"]

A linha crítica: COPY --from=builder /app/dist ./dist. Essa instrução extrai o resultado compilado da fase de construção para a imagem de execução baseada em Alpine. O compilador do TypeScript, os arquivos de origem e as dependências de desenvolvimento nunca tocam a camada final. Os nomes de cookie são sensíveis a maiúsculas e minúsculas Resultado:

~160 MB em vez de 1,1 GB. Isso representa uma redução de aproximadamente 85% para uma aplicação típica do Node — e é a mesma artefato compilado, apenas sem a estrutura ao redor. Adicionar uma fase de testes

Você pode adicionar uma fase de testes entre a construção e a execução, que executa seu conjunto de testes. Se os testes falharem, a construção é interrompida antes da criação da imagem de execução. Se os testes passarem, a fase de testes é ignorada completamente ao construir para produção.

Na CI você direciona explicitamente para a fase de testes:

FROM node:20 AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build


FROM builder AS tester

RUN npm test


FROM node:20-alpine AS runtime

WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist

EXPOSE 3000
CMD ["node", "dist/server.js"]

. Para imagens de produção, você constrói sem um alvo e o Docker executa todas as fases na ordem, parando na última docker build --target tester .. A fase de testes é executada, mas seu sistema de arquivos é descartado — os testes atuam como uma porta, não como carga. FROMPython: mesma ideia, execução ligeiramente diferente

As construções multifases do Python seguem o mesmo padrão. A diferença principal: os pacotes instalados pelo pip ficam sob

quando você usa /root/.local , então você copia esse diretório para a imagem de execução leve. --userimagem base: ~1 GB.

FROM python:3.12 AS builder

WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt
COPY . .


FROM python:3.12-slim AS runtime

WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY --from=builder /app .

ENV PATH=/root/.local/bin:$PATH

CMD ["python", "main.py"]

python:3.12 com apenas dependências instaladas: ~180–250 MB, dependendo do que está em requirements.txt. Os arquivos compilados vêm de graça, pois estão ao lado da origem. python:3.12-slim Três erros comuns que capturam todos pelo menos uma vez .pyc 1. Copiar arquivos errados

O erro mais comum: você

. Você simplesmente copiou tudo — arquivos de origem, fixtures de teste, node_modules, etc. — para sua imagem de execução mínima. Agora ela é maior do que a versão de uma única fase.

Seja explícito sobre o que está copiando. Copie apenas o diretório ou arquivos que o ponto de entrada de produção realmente precisa. Para a maioria dos aplicativos do Node: o resultado compilado ( COPY --from=builder /app ./ em vez de COPY --from=builder /app/dist ./dist) e opcionalmente quaisquer ativos estáticos. Para o Python: os pacotes instalados e o código do aplicativo, não requirements.txt, não testes, não notebooks.

2. Dados de construção vazando nas camadasdist/Se você passa segredos como argumentos de construção (por exemplo,

seguido por uso em um

comando), esse segredo é visível em todas as camadas subsequentes — mesmo em uma construção multifase. ARG NPM_TOKEN mostrará isso. RUN A abordagem correta é o Docker BuildKit com docker history myimage O segredo é montado apenas na execução dessa camada — nunca é gravado na história da imagem. Construa com:

A solução rápida que as pessoas usam — excluir o segredo na mesma --mount=type=secret:

RUN --mount=type=secret,id=npm_token     NPM_TOKEN=$(cat /run/secrets/npm_token) npm ci

camada — não ajuda realmente com construções multifases, mas a abordagem do BuildKit é mais limpa independentemente. docker build --secret id=npm_token,src=.npmrc .

3. Esquecer o .dockerignore RUN As construções multifases reduzem o tamanho da imagem final, mas

na fase de construção ainda envia todo o contexto para o daemon do Docker. Sem um

, isso inclui COPY . . , fixtures de teste, arquivos locais .dockerignoree quaisquer segredos armazenados em arquivos planos. A fase de construção vê tudo isso. .git/, node_modules/Mínimo .env para qualquer projeto do Node: a mesma data em que você adiciona o

. O tamanho do contexto de construção aparece na primeira linha de .dockerignore saída (

.git
node_modules
dist
.env
*.log
coverage
.nyc_output

Adicionar .dockerignore ) — se esse número for suspeito, verifique o que está sendo incluído. DockerfileFerramentas úteis para o trabalho com Dockerfile docker build Se você quiser um ponto de partida antes de escrever seu próprio, oSending build context to Docker daemon X MBno IO Tools gerará um Dockerfile multifase para pilhas comuns. Uma vez que você tiver algo escrito, execute-o pelo

para detectar erros comuns antes que eles cheguem à CI — coisas como falta de

, uso de Gerador de Dockerfile tags ou execução como root desnecessariamente. Linter e Formatador de Dockerfile A lição principal WORKDIRAs construções multifases são uma mudança em duas etapas: adicione uma fase de construção nomeada, copie o resultado compilado para uma imagem mínima fresca. A redução de tamanho é quase sempre justificável — 80–90% é típico para aplicações do Node e do Python. Os principais erros são ser muito amplo com latest , vazamento de segredos como argumentos de construção e ignorar

. Corrija esses pontos e você terá uma imagem de produção realmente adequada ao ambiente de produção.

Construções Multifases do Docker: Reduza o seu Imagem Sem Quebrar a Implantação 2 COPY --fromConstruções Multifases do Docker: Reduza o seu Imagem Sem Quebrar a Implantação 1 .dockerignore. Corrija isso e você terá uma imagem de produção realmente adequada ao tamanho de produção.

Quer eliminar anúncios? Fique sem anúncios hoje mesmo

Instale nossas extensões

Adicione ferramentas de IO ao seu navegador favorito para acesso instantâneo e pesquisa mais rápida

Ao Extensão do Chrome Ao Extensão de Borda Ao Extensão Firefox Ao Extensão Opera

O placar chegou!

Placar é uma forma divertida de acompanhar seus jogos, todos os dados são armazenados em seu navegador. Mais recursos serão lançados em breve!

ANUNCIADO Remover?
ANUNCIADO Remover?
ANUNCIADO Remover?

Notícias com destaques técnicos

Envolver-se

Ajude-nos a continuar fornecendo ferramentas gratuitas valiosas

Compre-me um café
ANUNCIADO Remover?