0Pricing
PHP Academy · Aula

Conteinerizando uma aplicação PHP

Escreva um Dockerfile PHP pronto para produção.

Conteinerizando uma aplicação PHP é uma aula grátis de PHP Academy no CoddyKit. Esta é a aula 1 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 colocar PHP em contêineres

Distribuir PHP de forma reproduzível significa fixar a versão exata do interpretador, as extensões e as bibliotecas do OS junto com o seu código. Uma imagem Docker fornece a todos os ambientes — computador pessoal, integração contínua e produção — o mesmo php -v e o mesmo conjunto de ext-*.

Nesta lição, construiremos uma imagem pronta para produção: PHP-FPM, apenas as extensões necessárias, configurações ajustadas, um usuário sem privilégios de superusuário e uma verificação de integridade.

FPM versus Apache como base

As imagens oficiais do PHP vêm em várias variantes. Para uma aplicação web de produção atrás do nginx/traefik, prefira php:8.3-fpm-alpine (menor) ou php:8.3-fpm (Debian, glibc — menos surpresas com bibliotecas nativas).

  • cli — processos, filas e tarefas agendadas
  • fpm — gerenciador de processos FastCGI, combine com nginx
  • apache — Apache integrado, conveniente, mas mais pesado

Fixe a versão secundária. Nunca use :latest em produção.

# Base image choice in your Dockerfile
FROM php:8.3-fpm-alpine AS base

# Why alpine? ~30MB base vs ~140MB Debian.
# Tradeoff: musl libc, occasional native-extension friction.

Instalando extensões

Nunca use apt install php-xxx dentro dessas imagens — use os auxiliares incluídos docker-php-ext-install, docker-php-ext-configure e pecl. O script install-php-extensions (mlocati) é o atalho consagrado que obtém para você os cabeçalhos de desenvolvimento corretos.

FROM php:8.3-fpm-alpine

# Grab the helper that resolves build deps automatically
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 \
        pdo_mysql \
        opcache \
        intl \
        zip \
        redis \
        bcmath

Composer na imagem

Copie o binário do Composer da imagem oficial, em vez de baixar um instalador usando o curl. Execute composer install com --no-dev e --optimize-autoloader para produção e copie apenas composer.json/composer.lock primeiro, para que a camada de dependências seja armazenada em cache independentemente das alterações no código-fonte.

COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

WORKDIR /app

# Cache-friendly: deps layer invalidates only when lock changes
COPY composer.json composer.lock ./
RUN composer install \
        --no-dev \
        --no-scripts \
        --no-autoloader \
        --prefer-dist

COPY . .
RUN composer dump-autoload --optimize --classmap-authoritative

Ajustando o php.ini

A imagem base inclui os modelos php.ini-production e php.ini-development. Ative o modelo de produção e depois coloque suas próprias substituições em conf.d — esse diretório é mesclado por último, portanto prevalece.

Principais valores de produção: opcache.enable=1, opcache.validate_timestamps=0 (código imutável na imagem) e um memory_limit sensato.

# Activate production ini
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

# Custom overrides win because conf.d loads last
COPY docker/php/zz-app.ini $PHP_INI_DIR/conf.d/zz-app.ini

O arquivo de substituição do OPcache

Esta é a maior melhoria isolada em produção. Com validate_timestamps=0, o PHP nunca consulta os arquivos a cada solicitação — mas isso significa que você MUST reconstruir a imagem para implantar alterações (exatamente o que queremos em contêineres imutáveis).

; docker/php/zz-app.ini
memory_limit = 256M
expose_php = Off

opcache.enable = 1
opcache.enable_cli = 0
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 0
opcache.preload = /app/preload.php
opcache.preload_user = www-data

Executando sem privilégios de superusuário

A imagem já define www-data. Executar o FPM como superusuário aumenta desnecessariamente a superfície de ataque. Defina o proprietário dos caminhos graváveis (cache, registros) e mude para esse usuário usando USER antes de CMD.

O processo mestre do FPM ainda se vincula a portas privilegiadas? Não — o FPM escuta na porta 9000 (sem privilégios), portanto executar sem superusuário é simples.

# Make runtime-writable dirs owned by the runtime user
RUN chown -R www-data:www-data /app/var /app/storage 2>/dev/null || true

USER www-data

EXPOSE 9000
CMD ["php-fpm"]

Verificações de integridade

Os orquestradores precisam de um sinal de que o FPM está realmente ativo, não apenas de que o processo existe. cgi-fcgi pode fazer uma verificação no ponto de acesso /status ou /ping do FPM. Primeiro, ative pm.status_path e ping.path no conjunto de processos do FPM.

# In www.conf pool config:
;   ping.path = /ping
;   ping.response = pong

# Dockerfile HEALTHCHECK using cgi-fcgi
RUN install-php-extensions @composer >/dev/null 2>&1 || true

HEALTHCHECK --interval=10s --timeout=3s --retries=3 \
  CMD SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET \
      cgi-fcgi -bind -connect 127.0.0.1:9000 || exit 1

Montando o Dockerfile

Aqui está um Dockerfile de produção coerente de estágio único. Na próxima lição, vamos dividi-lo em vários estágios para remover as ferramentas de compilação. Observe a ordem: dependências → configuração → código-fonte → autoload → troca de usuário.

FROM php:8.3-fpm-alpine

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 pdo_mysql opcache intl zip redis

COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /app

RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY docker/php/zz-app.ini $PHP_INI_DIR/conf.d/

COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist
COPY . .
RUN composer dump-autoload --optimize --classmap-authoritative && \
    chown -R www-data:www-data /app/var

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

Verificando a compilação

Após a compilação, faça uma verificação básica do que realmente foi parar na imagem: a versão do PHP, as extensões carregadas e se a validação do OPcache está desativada. Um script rápido da CLI confirma o contrato de execução do qual seu aplicativo depende.

<?php
// Run inside the container: php verify.php
echo 'PHP ' . PHP_VERSION . PHP_EOL;

$required = ['pdo_mysql', 'opcache', 'intl', 'zip'];
foreach ($required as $ext) {
    printf("%-12s %s\n", $ext, extension_loaded($ext) ? 'OK' : 'MISSING');
}

var_dump((bool) ini_get('opcache.enable'));
?>

Higiene do contexto de compilação

Um .dockerignore mantém o contexto de compilação pequeno e impede que segredos e um excesso de dependências vazem para a imagem e invalidem o cache. Exclua vendor, VCS, arquivos env e ferramentas locais.

# .dockerignore
.git
.gitignore
vendor/
node_modules/
.env
.env.*
tests/
*.md
docker-compose*.yml
storage/logs/*
var/cache/*

Verificação rápida

Por que definir opcache.validate_timestamps=0 em uma imagem de produção?

Recapitulação

Você criou uma imagem PHP-FPM de produção: uma imagem base 8.3-fpm-alpine fixada, instalou apenas as extensões necessárias usando o script instalador, copiou o Composer e as dependências armazenadas em cache em sua própria camada, ativou o php.ini de produção com uma substituição do OPcache, trocou para o usuário www-data e adicionou uma verificação de integridade do FPM.

Hábitos essenciais: fixe as versões, armazene a camada de dependências em cache, execute sem privilégios de root, desative a validação de carimbos de data e hora e mantenha o contexto de compilação enxuto com .dockerignore.

Perguntas Frequentes

A aula “Conteinerizando uma aplicação PHP” é grátis?

Sim — o texto completo de “Conteinerizando uma aplicação PHP” é 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 “Conteinerizando uma aplicação PHP”?

Escreva um Dockerfile PHP pronto para produçã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 1 de 4.

Quanto tempo leva a aula “Conteinerizando uma aplicação PHP”?

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