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 agendadasfpm— gerenciador de processos FastCGI, combine com nginxapache— 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 \
bcmathComposer 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-authoritativeAjustando 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.iniO 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-dataExecutando 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 1Montando 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
- Conteinerizando uma aplicação PHP
- Compilações em múltiplas etapas e otimização
- Docker Compose para ambientes locais
- CI/CD com GitHub Actions