Docker
O template yiisoft/app vem com uma configuração Docker pronta para desenvolvimento, testes e produção. Com ela, você não precisa instalar PHP, extensões nem servidor web na sua máquina: tudo roda em containers, com as mesmas versões para todo o time. Este capítulo percorre os arquivos que o template cria e os comandos do Makefile que os usam.
WARNING
O guia foi escrito num ambiente sem Docker, então os comandos abaixo não foram executados aqui. O que está descrito vem da leitura dos arquivos do template.
Os arquivos
docker/
Dockerfile # imagem com estágios: base, dev, prod-builder e prod
Caddyfile # configuração do servidor em produção
compose.yml # o que é comum a todos os ambientes
.env # variáveis do compose (não chegam ao app)
dev/
compose.yml # ambiente de desenvolvimento
Caddyfile
.env # variáveis do app em desenvolvimento
override.env.example
test/
compose.yml # ambiente de testes
.env
prod/
compose.yml # deploy em Docker Swarm
.env
Makefile # atalhos para os comandos do docker compose
.dockerignoreA imagem: FrankenPHP
O Dockerfile parte da imagem dunglas/frankenphp:1-php8.2-bookworm. O FrankenPHP é um servidor de aplicação PHP construído sobre o Caddy: o mesmo processo serve os arquivos estáticos e executa o PHP, sem PHP-FPM nem Nginx à parte.
O estágio base instala as extensões que o Yii usa (opcache, mbstring, intl, pdo e outras). Os outros estágios partem dele:
dev: adiciona o Xdebug e o Composer, cria um usuário com o mesmo UID e GID do seu usuário na máquina e copia odocker/dev/Caddyfile.prod-builder: copia o projeto e rodacomposer install --no-dev --classmap-authoritative.prod: defineAPP_ENV=prod, copia odocker/Caddyfilee o resultado doprod-builder, e roda comowww-data.
O Caddyfile manda toda requisição que não é um arquivo existente para o index.php, com /app/public como raiz:
{$SERVER_NAME::80} {
encode zstd br gzip
php_server {
try_files {path} index.php
root /app/public
}
}Nessa configuração, o FrankenPHP roda em modo clássico: cada requisição executa o public/index.php do zero, como no PHP-FPM. O modo worker, em que a aplicação fica carregada na memória, aparece em Servidores de longa duração.
Variáveis de ambiente
Há dois tipos de arquivo .env em docker/, e eles não se misturam:
docker/.envalimenta odocker composee oMakefile: nome da stack (STACK_NAME=app), porta de desenvolvimento (DEV_PORT=80), domínio e endereço SSH de produção, nome e tag da imagem. Essas variáveis não chegam à aplicação.docker/dev/.env,docker/test/.envedocker/prod/.envsão carregados dentro do container e chegam à aplicação. O de desenvolvimento defineAPP_ENV=dev,APP_DEBUG=trueeXDEBUG_MODE=develop.
Cada ambiente aceita ainda um override.env, opcional e ignorado pelo Git, para ajustes da sua máquina. O exemplo do template define APP_HOST_PATH. Essa variável é usada pela configuração do tratamento de erros: os links "abrir no editor" da página de erro trocam o caminho /app/ do container pelo caminho do projeto na sua máquina.
E o .env da raiz do projeto, usado com ./yii serve? Dentro dos containers ele não é lido. O src/bootstrap.php só carrega esse arquivo quando a variável APP_ENV não está definida no ambiente e o vlucas/phpdotenv está instalado. Nos containers, APP_ENV sempre vem definida, e na imagem de produção o phpdotenv nem existe, porque é instalado com --no-dev.
Desenvolvimento: make up, make shell
Os comandos do dia a dia estão no Makefile, que exige make (Linux, macOS ou WSL no Windows). Todos usam docker compose -f docker/compose.yml -f docker/dev/compose.yml.
make build # constrói a imagem de desenvolvimento
make up # sobe o ambiente em segundo plano
make down # derruba os containers
make stop # para sem remover
make clear # remove containers e volumes
make help # lista todos os alvosCom o ambiente no ar, o app responde em http://localhost (a porta vem de DEV_PORT). O docker/dev/compose.yml monta a pasta do projeto em /app, então o que você edita na sua máquina vale na hora, sem reconstruir a imagem.
Para entrar no container:
make shellIsso roda docker compose exec app /bin/bash, então o ambiente precisa estar de pé. Lá dentro, você usa ./yii, composer e vendor/bin/* normalmente.
Para comandos isolados, há atalhos que criam um container temporário (docker compose run --rm), então funcionam mesmo com o ambiente parado:
make yii migrate:up
make yii pais:listar
make composer outdatedTudo que vem depois do alvo é repassado ao comando. O Makefile tem um truque no início para que o make não trate migrate:up como outro alvo.
O make build passa o seu UID e GID para a imagem. Assim, os arquivos criados dentro do container (em runtime/ ou vendor/) pertencem ao seu usuário, e não ao root.
Xdebug
A imagem de desenvolvimento já tem o Xdebug, no modo develop (mensagens de erro melhoradas, sem depurador passo a passo). O docker/compose.yml mapeia host.docker.internal para a máquina hospedeira, que é o endereço que o Xdebug usa para chegar à sua IDE. Para depurar passo a passo, mude XDEBUG_MODE no docker/dev/override.env, por exemplo para debug, e suba o ambiente de novo.
Testes e ferramentas
O ambiente de testes usa docker/test/compose.yml, com a mesma imagem de desenvolvimento e o docker/test/.env: APP_ENV=test, APP_DEBUG=false, APP_C3=true e XDEBUG_MODE=coverage.
make test # vendor/bin/codecept run
make test-coverage # com relatório de cobertura em HTML
make codecept run UnitO APP_C3=true faz o public/index.php carregar o c3.php, que coleta a cobertura das requisições feitas pelos testes web. Os detalhes das suítes estão em Testes: visão geral.
As ferramentas de qualidade de código também têm atalho: make psalm, make rector, make cs-fix e make composer-dependency-analyser.
Produção
O template prepara o deploy em Docker Swarm:
make prod-build # docker build --target prod
make prod-push # envia a imagem para o registro
make prod-deploy # docker stack deploy no servidor de PROD_SSHO docker/prod/compose.yml define duas réplicas e atualização gradual: cada réplica nova sobe antes de a antiga cair (order: start-first), e se a atualização falhar o Swarm volta para a versão anterior (failure_action: rollback). A pasta runtime/ fica num volume, para os logs sobreviverem a um novo deploy.
O serviço não publica portas. Ele entra na rede externa caddy_public e declara as labels caddy e caddy.reverse_proxy, que são lidas por um proxy Caddy rodando no mesmo Swarm (no formato usado pelo projeto caddy-docker-proxy). Esse proxy não faz parte do template: você precisa tê-lo no servidor, ou adaptar o compose para o proxy que já usa.
Antes do primeiro deploy, ajuste PROD_HOST, PROD_SSH, IMAGE e IMAGE_TAG em docker/.env, e coloque segredos em docker/prod/override.env, que não vai para o Git.
O .dockerignore deixa entrar na imagem só o necessário: config/, public/, src/, o yii, os arquivos do Composer, os Caddyfile e os .env. Testes, runtime/ e vendor/ ficam de fora. O vendor/ de produção é criado dentro da imagem.
Comparando com o Yii2
Os templates do Yii2 traziam um docker-compose.yml simples, baseado na imagem yiisoftware/yii2-php. O template do Yii3 usa FrankenPHP, separa desenvolvimento, testes e produção em arquivos próprios e inclui um caminho de deploy com Docker Swarm.