0Pricing
PHP Academy · Aula

Compilações em múltiplas etapas e otimização

Reduza as imagens e separe a compilação da execução.

Compilações em múltiplas etapas e otimização é uma aula grátis de PHP Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de PHP Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de PHP Academy inclui 4 aulas no total.

Por que usar vários estágios

Uma imagem de estágio único leva o Composer, as dependências de compilação, os cabeçalhos de desenvolvimento e sua pasta tests/ para a produção. As compilações com vários estágios permitem compilar e instalar tudo em um estágio construtor completo e copiar apenas os artefatos finalizados para um estágio de execução enxuto.

Resultado: imagens menores, uma superfície de ataque menor, transferências mais rápidas e nenhum compilador enviado para a produção.

Estágios nomeados

Cada FROM ... AS name inicia um novo estágio. Os estágios posteriores podem usar COPY --from=name para copiar arquivos dos anteriores. Apenas o estágio final se torna sua imagem; os estágios intermediários são descartados, mas permanecem armazenados em cache.

# Stage 1: dependencies
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --prefer-dist --ignore-platform-reqs

# Stage 2: runtime
FROM php:8.3-fpm-alpine AS runtime
WORKDIR /app
COPY --from=vendor /app/vendor ./vendor
COPY . .

Separando as dependências de compilação

A compilação de extensões precisa de autoconf, gcc e cabeçalhos de desenvolvimento — nada disso pertence ao ambiente de execução. Use o instalador em um estágio construtor e depois copie os arquivos .so compilados e o arquivo ini correspondente de conf.d para um estágio de execução limpo.

FROM php:8.3-fpm-alpine AS ext-builder
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions && \
    install-php-extensions redis igbinary opcache intl

FROM php:8.3-fpm-alpine AS runtime
# Copy compiled extensions + their enable configs
COPY --from=ext-builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=ext-builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/

Ordem do armazenamento das camadas em cache

O Docker armazena as camadas em cache de cima para baixo e invalida tudo abaixo de uma camada alterada. Ordene da que muda menos para a que muda mais frequentemente:

  • Base + extensões (raramente)
  • composer.lock + instalação (ocasionalmente)
  • Código-fonte do aplicativo (a cada confirmação)
  • Geração do autoload (a cada confirmação)

Isso significa que uma alteração somente no código reutiliza integralmente a camada vendor armazenada em cache.

# BAD: copying all source before composer install
# busts the vendor layer on every code change
COPY . .
RUN composer install

# GOOD: lock first, then source
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-autoloader
COPY . .
RUN composer dump-autoload --optimize

Montagens de cache do BuildKit

Com o BuildKit (DOCKER_BUILDKIT=1), você pode montar um cache persistente que sobrevive entre as compilações sem acabar na imagem. Isso é perfeito para o cache global do Composer, pois as compilações repetidas deixam de baixar os pacotes novamente.

# syntax=docker/dockerfile:1
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN --mount=type=cache,target=/tmp/composer-cache \
    COMPOSER_CACHE_DIR=/tmp/composer-cache \
    composer install --no-dev --prefer-dist

Medindo o tamanho da imagem

Inspecione o detalhamento das camadas para encontrar excessos. docker history mostra o tamanho adicionado por cada instrução; ferramentas como dive mostram o espaço desperdiçado. O objetivo é ter um estágio de execução sem compiladores, sem Composer e sem dependências de desenvolvimento.

# Compare sizes
docker images myapp

# Per-layer contribution
docker history --no-trunc --format '{{.Size}}\t{{.CreatedBy}}' myapp:latest

# Deep inspection of wasted bytes
dive myapp:latest

Enxugando o estágio final

O estágio de execução NÃO deve conter o Composer, o script instalador de extensões nem sua suíte de testes. Copie vendor e o código-fonte dos estágios construtores; nunca execute composer no estágio final. Remova o instalador depois de usá-lo, caso precise executá-lo nesse estágio.

FROM php:8.3-fpm-alpine AS runtime
WORKDIR /app

# bring extensions + vendor in from builders — no Composer here
COPY --from=ext-builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=ext-builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/
COPY --from=vendor /app/vendor ./vendor
COPY . .

USER www-data
CMD ["php-fpm"]

Limitações de Distroless / Scratch

O PHP não pode ser executado em um scratch verdadeiramente vazio — ele precisa da libc e de bibliotecas compartilhadas. O limite prático é alpine (musl) ou um Debian mínimo no estilo distroless. O Alpine é menor, mas fique atento às bibliotecas nativas que esperam glibc; se ocorrerem falhas de segmentação com NSS/ICU, use php:8.3-fpm-bookworm como alternativa.

# Smallest practical PHP runtime
FROM php:8.3-fpm-alpine

# If musl causes native-lib issues (e.g., some ICU edge cases),
# the glibc Debian slim variant is the safe fallback:
# FROM php:8.3-fpm-bookworm

Direcionando os estágios

Um único Dockerfile pode atender ao desenvolvimento e à produção por meio de --target. Adicione um estágio dev sobre o estágio de execução, reintroduzindo as dependências de desenvolvimento do Composer e o Xdebug; use --target=runtime para a produção e --target=dev localmente.

FROM runtime AS dev
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions && \
    install-php-extensions xdebug @composer
USER root
RUN composer install   # includes dev deps

# Build prod:  docker build --target runtime -t app:prod .
# Build dev:   docker build --target dev     -t app:dev  .

Raciocinando sobre os tamanhos das camadas

Um modelo mental rápido ajuda você a prever o comportamento do cache. Este trecho da CLI simula o erro clássico de crescimento ilimitado da camada em contraste com um crescimento limitado, ilustrando por que é importante combinar a limpeza no mesmo RUN.

<?php
// Simulate layer sizes (MB) for two strategies
$installSteps = [120, 8, 8, 8];

// Separate RUN per step keeps temp files in layers
$separate = array_sum($installSteps);

// Single RUN with cleanup removes temp files before commit
$combined = max($installSteps); // peak, then cleaned

echo "Separate layers total: {$separate} MB\n";
echo "Combined+cleanup:       {$combined} MB\n";
echo 'Saved: ' . ($separate - $combined) . " MB\n";
?>

Combine e limpe em um único RUN

Cada RUN é uma camada; excluir arquivos em uma camada posterior não reduz o tamanho da imagem, porque as camadas anteriores ainda contêm os bytes. Instale, use e limpe tudo em um único RUN para que os arquivos temporários nunca sejam confirmados na imagem.

RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS && \
    pecl install redis && \
    docker-php-ext-enable redis && \
    apk del .build-deps && \
    rm -rf /tmp/pear /var/cache/apk/*

Verificação rápida

Por que as dependências de compilação precisam ser removidas no mesmo RUN em que foram instaladas?

Recapitulação

As compilações com vários estágios mantêm compiladores e dependências de desenvolvimento fora da produção. Você aprendeu a nomear estágios e usar COPY --from para copiar artefatos, ordenar as camadas da menos à mais volátil para aproveitar o cache, usar montagens de cache do BuildKit para o Composer, medir o tamanho com docker history/dive, escolher deliberadamente entre alpine e glibc, direcionar os estágios de desenvolvimento e produção e combinar a instalação e a limpeza em um único RUN.

Perguntas Frequentes

A aula “Compilações em múltiplas etapas e otimização” é grátis?

Sim — o texto completo de “Compilações em múltiplas etapas e otimização” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de PHP Academy, atualize para CoddyKit PRO. O curso de PHP Academy inclui 4 aulas no total.

O que vou aprender em “Compilações em múltiplas etapas e otimização”?

Reduza as imagens e separe a compilação da execução. Você pratica PHP Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar PHP Academy?

Nenhuma experiência prévia é necessária. PHP Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Compilações em múltiplas etapas e otimização”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de PHP Academy?

Sim. Cada aula de PHP Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Conteinerizando uma aplicação PHP
  2. Compilações em múltiplas etapas e otimização
  3. Docker Compose para ambientes locais
  4. CI/CD com GitHub Actions
← Voltar para PHP Academy