← Voltar ao blog

Ambiente local do Magento 2 com Docker e Warden

Rodrigo Biazzi

Um projeto Magento 2 tem mais peças móveis do que a maioria das aplicações PHP. PHP-FPM, um servidor web, MySQL ou MariaDB, OpenSearch, Redis ou Valkey, Varnish, RabbitMQ e um mail catcher precisam rodar juntos, em versões iguais às da produção. Instalar tudo isso à mão no notebook funciona até o segundo projeto precisar de outra versão do PHP.

O Docker resolve o problema das versões. O Warden, uma ferramenta open source construída em cima do Docker Compose, resolve a fiação. Este artigo passa por um setup de Warden para o Magento 2.4.8, do primeiro env-init até uma loja funcionando com Xdebug, e os hábitos que mantêm tudo funcionando.

Por que um ambiente em containers

O ponto principal é a paridade. Se a produção roda PHP 8.3 com OpenSearch 2 e MariaDB, o ambiente local deve rodar o mesmo. Bugs que só aparecem com um modo específico do MySQL ou um analyzer específico do OpenSearch são muito mais fáceis de pegar quando as versões batem.

O segundo ponto é o isolamento. Cada projeto tem seus próprios containers, seu próprio banco e seus próprios hostnames. Você pode parar um projeto e subir outro sem desinstalar nada, e um dev novo consegue uma loja rodando a partir de um repositório e um dump de banco, em vez de uma página de notas de instalação.

O que o Warden oferece

O Warden roda alguns serviços globais uma vez por máquina e depois uma stack por projeto:

  • Traefik como reverse proxy, para cada projeto ter um hostname como app.myshop.test
  • Uma root CA local, para esses hostnames funcionarem em HTTPS sem avisos do navegador
  • dnsmasq para resolver *.test para a sua máquina
  • Mailhog (ou Mailpit, conforme a versão) para capturar e-mails enviados
  • Containers por projeto para nginx, PHP-FPM, um PHP-FPM separado com Xdebug, o banco, Redis, OpenSearch, Varnish e RabbitMQ, cada um ligável e desligável no .env do projeto

No macOS, o Warden sincroniza o código para dentro dos containers com Mutagen em vez de um bind mount simples. Essa é a diferença entre um ambiente utilizável e um em que toda página leva vários segundos.

Primeira execução

Instale o Docker e o Warden, depois suba os serviços globais uma vez:

warden svc up

Dentro da pasta do projeto, crie o arquivo de ambiente e um certificado para o domínio:

cd ~/Sites/myshop
warden env-init myshop magento2
warden sign-certificate myshop.test

O env-init escreve um arquivo .env. Esse arquivo é a configuração real da stack, então leia e ajuste antes de iniciar qualquer coisa.

O arquivo .env

Um exemplo resumido para um projeto 2.4.8:

WARDEN_ENV_NAME=myshop
WARDEN_ENV_TYPE=magento2
WARDEN_WEB_ROOT=/

TRAEFIK_DOMAIN=myshop.test
TRAEFIK_SUBDOMAIN=app

WARDEN_DB=1
WARDEN_OPENSEARCH=1
WARDEN_ELASTICSEARCH=0
WARDEN_VARNISH=1
WARDEN_RABBITMQ=1
WARDEN_REDIS=1

PHP_VERSION=8.3
COMPOSER_VERSION=2
MARIADB_VERSION=11.4
OPENSEARCH_VERSION=2.12
RABBITMQ_VERSION=3.13
REDIS_VERSION=7.2
VARNISH_VERSION=7.4

Os nomes exatos das variáveis e as versões disponíveis dependem da release do Warden que você tem, então confira o arquivo gerado em vez de copiar este. O hábito importante é definir cada versão igual ao que a produção roda e commitar o .env no repositório para todos usarem a mesma stack.

Se você não precisa de um serviço, desligue. Varnish e RabbitMQ consomem memória, e muitas tarefas não precisam deles. Você pode religá-los quando for trabalhar com full page cache ou consumers de queue.

Iniciando o ambiente

warden env up
warden shell

O warden env up baixa as imagens e inicia os containers do projeto. O warden shell abre um shell no container PHP como usuário www-data, na raiz do projeto. Tudo que toca no Magento roda de lá: Composer, bin/magento, PHPUnit.

Para comandos avulsos eu prefiro não abrir um shell interativo:

warden shell -c "bin/magento cache:flush"
warden shell -c "composer install"

Evite rodar o bin/magento no host. O PHP do host é de outra versão e tem outras extensões, e os hostnames db, redis e opensearch só resolvem dentro da rede do Docker. Rodar o docker exec direto também funciona, mas é fácil acabar como root e criar arquivos que o usuário do PHP-FPM não consegue gravar depois.

Instalando um Magento novo

Para um projeto novo, crie-o com Composer de dentro do shell e depois rode o instalador apontando para os hostnames dos containers:

bin/magento setup:install \
  --backend-frontname=backend \
  --db-host=db --db-name=magento \
  --db-user=magento --db-password=magento \
  --search-engine=opensearch \
  --opensearch-host=opensearch --opensearch-port=9200 \
  --opensearch-index-prefix=magento2 --opensearch-enable-auth=0 \
  --amqp-host=rabbitmq --amqp-port=5672 \
  --amqp-user=guest --amqp-password=guest \
  --session-save=redis --session-save-redis-host=redis \
  --session-save-redis-db=2 \
  --cache-backend=redis --cache-backend-redis-server=redis \
  --cache-backend-redis-db=0 \
  --page-cache=redis --page-cache-redis-server=redis \
  --page-cache-redis-db=1 \
  --http-cache-hosts=varnish:80

bin/magento config:set web/unsecure/base_url https://app.myshop.test/
bin/magento config:set web/secure/base_url https://app.myshop.test/
bin/magento deploy:mode:set developer

As credenciais de banco magento / magento são o padrão do Warden. Toda opção acima acaba em app/etc/env.php, que é tratado com mais detalhe em env.php e config.php explicados.

Importando um projeto existente

Na maior parte do tempo você entra num projeto que já existe. Os passos são:

  1. Clone o repositório e rode warden env up
  2. Rode composer install dentro do container
  3. Importe um dump de banco sanitizado
  4. Crie ou ajuste o app/etc/env.php para os hostnames dos containers
  5. Corrija as base URLs e rode setup:upgrade

A importação do banco manda o dump em stream para o container do banco:

gunzip -c ~/dumps/myshop.sql.gz | warden db import

Depois, dentro do shell:

bin/magento setup:upgrade
bin/magento indexer:reindex
bin/magento cache:flush

Nunca importe um dump bruto de produção sem limpar. E-mails de clientes, credenciais de gateway de pagamento e endpoints de integração em core_config_data podem fazer uma loja local mandar e-mails de verdade ou chamar APIs reais. O artigo sobre sanitizar o banco mostra o que remover.

Xdebug

O Warden roda um segundo container PHP-FPM com o Xdebug carregado. As requisições só vão para ele quando o cookie XDEBUG_SESSION está presente, então os carregamentos normais de página continuam rápidos. Instale uma extensão de navegador que define o cookie, configure o PhpStorm com um server cujo nome combine com o domínio e cujo mapeamento de caminho aponte a raiz do projeto para /var/www/html, e comece a escutar.

Para comandos CLI, use o debug shell:

warden debug

O setup completo do PhpStorm e os motivos comuns para os breakpoints serem ignorados estão em depurando o Magento 2 com Xdebug.

Hábitos do dia a dia

Mantenha o developer mode e os caches certos

O developer mode mostra erros e gera código sob demanda. Mantenha a maioria dos caches ativos mesmo em developer mode e desative só os contra os quais você está trabalhando, normalmente layout, block_html e full_page para trabalho de frontend. Uma loja com todos os caches desligados é mais lenta do que precisa e esconde bugs relacionados a cache.

Limpe o código gerado com intenção

Quando a assinatura de um construtor muda, apague o generated/code das classes afetadas ou a pasta inteira. Limpar tudo depois de toda mudança desperdiça tempo, já que o Magento regenera na próxima requisição.

Pare o que você não está usando

Cada projeto com OpenSearch, MariaDB e RabbitMQ pode usar vários gigabytes de RAM. Rode warden env down quando trocar de projeto. O banco fica num volume do Docker, então sobrevive a uma parada.

Leia o mail catcher

Os e-mails transacionais vão para o mail catcher global em webmail.warden.test. É o lugar para testar templates de e-mail de pedido e de customer sem enviar nada de verdade.

Problemas comuns

  • O navegador diz que o certificado é inválido. A root CA do Warden não foi confiada, ou o certificado foi assinado para um domínio diferente do TRAEFIK_DOMAIN. Rode o sign-certificate de novo com o nome certo e reinicie.
  • Loop de redirect ou redirect para a produção. As base URLs em core_config_data ainda apontam para o domínio no ar. Atualize com config:set ou direto no banco.
  • O container do OpenSearch encerra. Em geral é memória. Dê mais RAM ao Docker ou reduza o heap na configuração do serviço.
  • Arquivos pertencentes ao root. Alguém rodou comandos como root no container. Corrija a propriedade e volte para o warden shell.

Com o ambiente estável, o mesmo setup de containers é uma boa base para rodar testes localmente. Veja testes de integração no Magento 2 para rodar o framework de testes contra um banco separado na mesma stack.

FAQ

O Warden é melhor que docker-magento ou DDEV para Magento 2?

Os três funcionam. O Warden dá a cada projeto a própria stack atrás de um proxy Traefik compartilhado com TLS local, e o arquivo .env dele mantém as versões dos serviços próximas da produção. Escolha o que o seu time vai de fato manter.

Por que o Magento é lento no Docker no macOS?

Bind mounts entre o macOS e a VM Linux são lentos para uma base de código com dezenas de milhares de arquivos. O Warden sincroniza os arquivos com Mutagen no macOS para evitar isso. Dê também memória suficiente ao Docker, já que o OpenSearch e o MySQL precisam dela.

Devo rodar o bin/magento no host ou dentro do container?

Dentro do container. A versão do PHP, as extensões e hostnames como db e redis só existem lá. Use warden shell ou warden shell -c com o comando.

Posso usar um dump do banco de produção localmente?

Pode, mas sanitize antes. Remova ou anonimize dados de clientes, mude as base URLs e desative as configurações de pagamento, e-mail e integrações para a cópia local não conseguir falar com serviços reais.

Atendo como freelancer em Magento e Adobe Commerce, incluindo a montagem de ambientes locais para times. Se você precisa de ajuda com isso, fale comigo.

Artigos relacionados