Staging no Dokploy
Como staging é declarado e convergido (apply), publicado em ordem (deploy) e o que conferir com o auto-deploy ligado.
Staging roda no Dokploy como aplicações separadas, declaradas em infra/dokploy/src/staging.config.ts e convergidas
por um script sobre a API do Dokploy. compose.yaml continua sendo a pilha local e a referência do que cada serviço
precisa.
| Serviço | Tipo no Dokploy | Origem |
|---|---|---|
postgres | Banco (Postgres 18) | postgres:18.6-alpine; senha gerada uma vez e mantida pelo Dokploy |
redis | Banco (tipo Redis, Valkey 8) | valkey/valkey:8.1.10-alpine; senha gerada uma vez e mantida pelo Dokploy |
elasticmq | Aplicação (imagem Docker) | softwaremill/elasticmq-native:1.7.1, com elasticmq.conf montado |
migrator | Aplicação (GitHub, alvo migrator) | One-shot: restart none, update continue |
workers | Aplicação (GitHub, alvo workers) | 45 s de graça na parada (orçamento de drenagem) |
api | Aplicação (GitHub, alvo runtime) | Domínio HTTPS (Let's Encrypt) na porta 3000, 30 s de graça na parada |
garage | Aplicação (imagem Docker) | dxflrs/garage:v2.4.1, garage.toml montado, dois volumes, domínio S3 (Backups) |
garage-init | Aplicação (imagem Docker) | curlimages/curl:8.22.0 rodando o script de inicialização (one-shot) |
As aplicações GitHub constroem o repositório novapromotora-labs/monalisa, branch main, com auto-deploy ligado
(ver Auto-deploy).
Variáveis em três camadas
- Projeto: valores comuns a todos os ambientes (pool e timeouts do banco,
CORS_CREDENTIALS). - Ambiente staging:
DATABASE_URL,REDIS_URL, o endpointMONALISA_SQS_*do ElasticMQ,LOG_LEVEL,CORS_ORIGINSe o token de administração do Garage. - Aplicação: só o que cada uma usa, quase sempre como referência
${{project.NOME}}ou${{environment.NOME}}, que o Dokploy resolve no deploy.
dokploy:apply: convergir
bun run dokploy:apply --dry-run # só o plano: nomes de variáveis, nunca valores
bun run dokploy:apply # converge; uma segunda execução informa "no changes"A chave da API do Dokploy vem do cofre do operador e nunca é commitada, impressa ou registrada.
- Encontra ou cria ambiente, bancos e aplicações pelo nome e altera só os campos que diferem.
- Mescla cada camada de variáveis com o que o Dokploy já tem: variáveis que ele não gerencia sobrevivem.
DATABASE_URLeREDIS_URLsão reconstruídas a cada execução a partir da senha e do host que o Dokploy guarda, então acompanham um banco recriado. - Segredos gerados (
PLATFORM_BOOTSTRAP_PASSWORD, os segredos do Garage e as senhas dos bancos na criação) só são criados quando faltam e nunca são sobrescritos. A saída nomeia variáveis, nunca valores. - Uma variável removida de
staging.config.tsnão é apagada do Dokploy: remova-a na interface. - A imagem de um banco só é atualizada no lugar dentro da mesma linha (repositório, major e variante:
postgres:18.6-alpine→postgres:18.7-alpine). Outra linha para com erro: um major do PostgreSQL não lê o diretório de dados de outro, e o Valkey 8 não carrega o formato RDB do Redis 7.4. Nesses casos o serviço precisa de backup, remoção na interface e recriação peloapply. O mesmo vale para ogarage, preso adxflrs/garage:v2.*: uma major do Garage muda o formato em disco. - Sem o domínio S3 configurado, o
applypula os backups com um aviso.
PLATFORM_BOOTSTRAP_PASSWORD é gerada pelo primeiro apply e fica só no ambiente do migrator. Ela não é impressa,
a não ser com --reveal-bootstrap-password, que escreve só a senha no stdout e é recusado quando o stdout é um
terminal. Só o primeiro deploy a lê.
dokploy:deploy: publicar em ordem
bun run dokploy:deploy # a partir de um checkout de main em dia- Sobe PostgreSQL e Redis se não estão rodando e espera o Dokploy reportá-los no ar; depois o ElasticMQ, se não está rodando.
- Publica o migrator. O status de deploy do Dokploy cobre o build e a atualização do serviço, não o código de saída de
um one-shot; por isso o comando lê as tarefas do swarm do migrator e só continua quando a tarefa nova termina
Complete. Tarefa falha ou rejeitada, saída diferente de zero, nenhuma tarefa nova ou resposta ilegível param o deploy antes dos workers e da API. - Publica os workers e a API.
- Consulta
https://<domínio>/readyaté responder 200 e informar olatestMigrationesperado: a migration mais nova do checkout local (por isso rodar a partir do commit que o Dokploy constrói), ou--expect-migration <nome>. Um 200 de uma tarefa antiga da API, ainda servindo durante a atualização, não passa. - Só então cuida do armazenamento de backups: sobe o Garage se não está rodando e roda o
garage-init(conferido comoCompletedo mesmo jeito) até ele ter terminado uma vez, ou de novo com--reinit. Uma falha do Garage ou dogarage-initnunca segura a versão: o comando falha no fim, dizendo que a versão está no ar.
Cada requisição tem timeout e cada espera tem prazo de 20 minutos.
O migrator (como o garage-init) é one-shot e roda com restart none e update FailureAction: continue, Monitor: 0. Sem isso, uma tarefa
que termina com 0 dentro da janela de monitoramento contaria como atualização falha e o swarm voltaria o serviço à
especificação anterior (com um DATABASE_URL antigo), e quem decide se tenta de novo é o comando de deploy, não o swarm.
Auto-deploy
O auto-deploy fica ligado por padrão para o migrator, a API e os workers (autoDeploy em staging.config.ts;
dokploy:apply --no-auto-deploy desliga até o próximo apply sem a flag). A cada push em main, o Dokploy republica
os três, cada um por conta própria, sem ordem entre eles.
O portão de prontidão garante a correção: a API e os workers novos ficam
não prontos (/ready responde 503, os workers não consomem) até o migrator aplicar a migration do build, então uma API
nova nunca serve sobre um schema antigo.
Ele não garante que o deploy convirja:
- ninguém lê o código de saída do migrator, então um migrator que falha passa despercebido;
- uma tarefa nova da API que continua não pronta além do healthcheck, enquanto o migrator ainda roda, pode deixar a atualização do swarm parada na tarefa antiga (o Dokploy não define ação de falha de atualização para a API e os workers).
Por isso, depois de um push, confira a versão: o /ready precisa informar o latestMigration novo. Se não
informar, republique a API (ou o migrator, se ele falhou), ou rode bun run dokploy:deploy, o caminho ordenado que
confere cada passo. Se a instância do Dokploy tiver notificações configuradas, ligue a de deploy falho.
Quando a versão adiciona uma task ou um assinante, os workers podem subir depois da API; mensagens para uma unidade ainda desconhecida voltam para a fila com backoff (ver Ordem de deploy).
Outros cuidados
- O
deploynão mexe num ElasticMQ nem num Garage que estão rodando: uma mudança emelasticmq.conf(gravada peloapply) só vale depois de republicar oelasticmqna interface; o mesmo vale paragarage.tomle ogarage. - As filas do ElasticMQ são em memória: reiniciá-lo perde mensagens que o relay já enviou, e as runs delas ficam em
queued. - Staging não tem agendador externo, então tarefas agendadas (como
maintenance.purge) não rodam lá. - O
/readyexpõelatestMigrationpublicamente; produção precisa reavaliar isso.