Deploy · MemphisLab Docs
MemphisLab Docs
Checklist Mobile

Deploy

Como colocar uma versão do checklist-mobile no ar e como reverter

Roda no cluster k3s (repositório k3s-platform), um namespace por cliente. O padrão de build e release é o mesmo do license-manager — o k3s-platform builda a imagem dentro do cluster via buildkitd e o GitOps em apps/checklist.yaml + clients/<slug>.yaml decide o que roda onde.

Risco conhecido: build duplicado

O CI do próprio repositório checklist-mobile (GitHub Actions, não CircleCI — o .circleci/config.yml que existe no repo é um stub não funcional) builda docker/deploy/Dockerfile e publica em ghcr.io/finattogroup/frota-checklist a cada push em master e a cada tag v*. É o mesmo pacote de imagem que o k3s-platform escreve. Enquanto esse job existir, uma tag v* empurrada pelo CI do próprio repositório sobrescreve uma imagem buildada pela plataforma, com um Dockerfile diferente do que o k3s-platform mantém. Antes de assumir que uma imagem em produção veio de um make app-release, confira image.tag em apps/checklist.yaml contra o histórico de tags publicadas no GHCR.

Os jobs quality, tests e mobile desse mesmo CI continuam sendo o gate de qualidade real — é só o job build que é redundante com a plataforma.

Deploy

No repositório k3s-platform:

make app-release APP=checklist REF=v0.4.0
git commit -am "release(checklist): v0.4.0" && git push

Isso builda a partir da tag/ref informada, publica a imagem multi-arch, atualiza source.ref/image.tag em apps/checklist.yaml, e o commit é o que efetivamente dispara o rollout: o ArgoCD sincroniza todos os clientes que apontam platform.app: checklist assim que vê o novo image.tag.

Para segurar um cliente numa versão anterior (não seguir o release geral), definir image.tag diretamente em clients/<slug>.yaml — isso tem prioridade sobre o valor de apps/checklist.yaml.

Onde roda

  • Cluster k3s, um namespace por cliente (ex.: demo), domínio <slug>.frota.memphislab.com.br
  • Servido por Laravel Octane sobre FrankenPHP, porta 8080, healthcheck em /up
  • Fila (queue worker) e agendador (scheduler CronJob) ligados — o projeto tem fleet:evaluate-attention agendado diariamente

Por rodar em Octane, não em modo clássico do FrankenPHP, este serviço não é coberto pela correção de TLS scheme que a plataforma aplica via Caddyfile (Octane gera o próprio Caddyfile e ignora o da plataforma). Se asset()/url() saírem como http:// atrás do Traefik, é aqui que precisa mexer (trustProxies() em bootstrap/app.php), não na plataforma.

Variáveis de ambiente

Chaves próprias em extraSecretKeys (apps/checklist.yaml):

  • JWT_SECRET — assinatura dos tokens JWT da API; gerado automaticamente na provisão do cliente (generatedSecretKeys)
  • LICENSE_SERIAL_KEY — credencial deste cliente junto ao license-manager; selado vazio, precisa ser preenchido manualmente por cliente

Outras variáveis (extraEnv), com propósito:

  • JWT_TTL — tempo de vida do token JWT, em minutos
  • LICENSE_MANAGER_URL — endereço do license-manager a consultar
  • LICENSE_HTTP_TIMEOUT — timeout da chamada HTTP ao license-manager
  • LICENSE_ENFORCE — liga/desliga o bloqueio por licença (hoje false em todos os clientes)
  • LICENSE_FAIL_OPEN — decide se uma falha ao consultar o license-manager libera ou bloqueia o acesso
  • LICENSE_CNPJ — CNPJ que identifica este cliente junto ao license-manager
  • LICENSE_MODULE_FLEET / LICENSE_MODULE_CHECKLIST / LICENSE_MODULE_MAINTENANCE — mapeiam os módulos internos da aplicação para os códigos de módulo cadastrados no license-manager

Migrations

O job de migrate roda as migrations e o seeder DefaultUserSeeder a cada deploy — precisa ser idempotente (firstOrCreate), porque roda em todo upgrade, não só na primeira instalação.

Rollback

Mesmo fluxo do license-manager: reverter o commit que mudou apps/checklist.yaml e dar push, ou usar make client-upgrade CLIENT=<slug> TAG=<versão anterior> para reverter um cliente específico sem afetar os demais.

Diagnóstico

make client-status CLIENT=<slug>   # pods, HPA, PVCs, ingress, Postgres
make client-logs   CLIENT=<slug>
make client-shell  CLIENT=<slug>