Public
Watch
1
Fork
You've already forked deployai
0
0

Latest commit

maotovisk
feat: add ghcr management
All checks were successful
Release / release (push) Successful in 45s
bc01b87 2026-08-07 14:14:27 -03:00 10 commits
2026-08-07 14:14:27 -03:00
2026-08-07 10:37:10 -03:00
2026-08-07 14:14:27 -03:00
2026-08-07 10:37:10 -03:00
2026-08-07 10:37:10 -03:00
2026-08-07 10:37:10 -03:00
2026-08-07 11:12:26 -03:00
2026-08-07 11:12:26 -03:00
2026-08-07 14:14:27 -03:00

deployai

Um gerenciador pequeno de deploys Docker Compose, com TUI, webhook assinado do GitHub, login opcional no GHCR e integração não-invasiva com um Caddy já existente.

Como funciona

Cada subdiretório de projects_dir é um projeto e contém exatamente os arquivos operacionais da aplicação:

projects/
└── minha-app/
    ├── .env
    ├── compose.yml
    └── config.toml

Em um deploy, o deployai:

  1. opcionalmente executa git pull --ff-only no diretório do projeto;
  2. autentica no registry, se configurado;
  3. valida o Compose e a rede externa;
  4. conecta o container Caddy à rede do projeto, caso necessário;
  5. executa docker compose pull e up -d --wait para todos os serviços habilitados no arquivo, respeitando depends_on e healthchecks;
  6. grava atomicamente um snippet do Caddy e executa o reload.

O snippet só é publicado depois que os serviços ficam saudáveis. Em caso de falha, containers e logs são preservados para diagnóstico e a rota anterior do Caddy não é alterada.

Instalação

Requer Docker com o plugin Compose e um Caddy já em execução. Em Linux amd64 ou arm64, instale a release mais recente como o usuário que executará o deployai:

curl -fsSL https://git.maot.dev/maot/deployai/raw/branch/main/install.sh | sh

O instalador detecta a arquitetura, baixa o binário e checksums.txt da release mais recente, valida o SHA-256 e instala em ~/.local/bin/deployai. Para escolher uma versão ou diretório:

curl -fsSL https://git.maot.dev/maot/deployai/raw/branch/main/install.sh \
  | sh -s -- v0.1.0

curl -fsSL https://git.maot.dev/maot/deployai/raw/branch/main/install.sh \
  | INSTALL_DIR=/opt/deployai/bin sh

Não execute com sudo se quiser usar o serviço systemd do usuário e o auto-update. O diretório do binário deve permanecer gravável por esse usuário.

Para compilar do código-fonte, requer Go 1.23+:

make build
install -m 0755 deployai ~/.local/bin/deployai

Na primeira execução não é necessário criar a configuração manualmente. O deployai abre um setup wizard, pergunta pelos diretórios, Caddy, webhook e GHCR, valida cada resposta, apresenta uma revisão final, cria os diretórios e grava ~/.config/deployai/config.toml com permissão 0600.

O TUI é a interface padrão:

deployai

Ele lista o estado de cada Compose, permite navegar com ↑/↓, iniciar um deploy com d/enter, configurar as credenciais do GitHub/GHCR com g, consultar o webhook com s, rotacionar seu segredo com S e reler projetos e estados com r. Pressione ? a qualquer momento para abrir o cheatsheet de atalhos em um modal centralizado.

A interface ocupa todo o viewport do terminal. A lista de projetos, os detalhes do projeto selecionado e a atividade recente ficam em painéis visualmente separados. Uma action bar fixa na parte inferior mostra apenas os atalhos válidos para o contexto atual; assistentes e confirmações aparecem como modais, sem deslocar o workspace.

Pressione n para abrir o assistente modal de novos projetos. Ele coleta domínio, serviço, porta, rede e dados do webhook, cria o config.toml, gera um segredo seguro e oferece duas formas de iniciar os arquivos:

  • modelo mínimo, com um compose.yml contendo services e o nome do serviço e um .env vazio;
  • colagem direta do compose.yml e .env completos em editores multilinha.

O .env e o .webhook-secret são gravados com permissão 0600. Se alguma etapa da criação falhar, o diretório parcial é removido e o projeto não aparece na lista.

Para reabrir o wizard e alterar a configuração posteriormente:

deployai setup

Também é possível usar examples/config.toml como referência e o projeto em examples/projects/minha-app como base. Renomeie .env.example para .env.

Também há dois comandos operacionais, úteis para serviço e automação:

deployai deploy minha-app
deployai serve

Use -config /caminho/config.toml antes do comando para escolher outro arquivo.

Serviço systemd

O webhook pode ser instalado como um serviço systemd do usuário, sem sudo:

export GITHUB_ACTOR="seu-usuario"
export GHCR_TOKEN="seu-token"
deployai service install

O instalador:

  1. grava as credenciais do registry em ~/.config/deployai/service.env com permissão 0600, se o login estiver habilitado;
  2. cria ~/.config/systemd/user/deployai-webhook.service;
  3. executa systemctl --user daemon-reload e enable --now.

Os segredos de webhook pertencem a cada projeto e não ficam no arquivo de ambiente do serviço. Consulte o serviço com:

systemctl --user status deployai-webhook
journalctl --user -u deployai-webhook -f

Para que serviços do usuário iniciem no boot mesmo sem uma sessão aberta, o administrador do host deve habilitar lingering uma vez:

sudo loginctl enable-linger "$USER"

O serviço usa exatamente o binário e o arquivo de configuração empregados no momento da instalação. Execute deployai service install novamente depois de mover o binário ou mudar o caminho do config.

Releases e atualização automática

O workflow .forgejo/workflows/release.yml roda os testes e publica binários Linux estáticos para amd64 e arm64, além de checksums.txt. Ele usa o token temporário do próprio Forgejo Actions; não é necessário cadastrar um token pessoal. É necessário haver um runner online com o label docker e Actions habilitado no repositório.

Crie e envie uma tag semântica para publicar:

git tag -a v0.1.0 -m "v0.1.0"
git push origin v0.1.0

Binários de release consultam a release mais recente ao iniciar. Quando há uma versão mais nova para sua arquitetura, o deployai baixa o asset, valida o SHA-256, substitui atomicamente seu próprio executável e reinicia o mesmo comando. Falha de rede ou de atualização gera apenas um aviso; a execução normal continua.

Consulte a versão ou desative a consulta automática quando necessário:

deployai version
DEPLOYAI_NO_UPDATE=1 deployai

Configuração global

projects_dir = "/srv/deployai/projects"

[caddy]
container = "caddy"
snippets_dir = "/srv/caddy/sites"
reload = ["caddy", "reload", "--config", "/etc/caddy/Caddyfile"]

[webhook]
listen = "127.0.0.1:9080"

[registry]
login = true
host = "ghcr.io"
username_env = "GITHUB_ACTOR"
token_env = "GHCR_TOKEN"

O diretório snippets_dir deve estar montado no container Caddy e importado pelo Caddyfile principal. Por exemplo:

import /etc/caddy/sites/*.caddy

Se o Caddy usa uma configuração em JSON ou não importa esse diretório, deixe snippets_dir vazio; o deploy continuará funcionando sem gerenciar rotas.

Configuração de projeto

hostnames = ["app.example.com"]
service = "minha-app"
port = 8080
proxy_network = "caddy"
compose_file = "compose.yml"
health_timeout = "90s"

repository = "minha-org/minha-app"
branch = "main"
git_pull = false

Todos os serviços habilitados no Compose são atualizados e iniciados durante o deploy. service seleciona apenas o serviço HTTP que receberá o tráfego do Caddy; ele não limita o deploy a esse serviço. É o nome DNS desse serviço na rede Docker compartilhada, não uma porta publicada no host. A rede informada deve existir e também ser declarada como external no Compose. Use nomes de serviço únicos quando vários projetos compartilharem a mesma rede, evitando DNS ambíguo. O serviço deve ter um healthcheck; sem ele, o Compose só consegue confirmar que o container está em execução.

GHCR

Com registry.login = true, defina:

export GITHUB_ACTOR="seu-usuario"
export GHCR_TOKEN="seu-token"

No TUI, pressione g para consultar o estado dessas credenciais e salvá-las sem expor o token. Os valores ficam em ~/.config/deployai/service.env com permissão 0600, são carregados automaticamente pelos comandos do deployai e também são usados pelo serviço webhook na próxima inicialização.

Para imagens privadas, o token precisa ao menos de read:packages. O segredo é enviado ao docker login por stdin e nunca aparece nos argumentos do processo. Também é possível deixar login = false e usar as credenciais já armazenadas no Docker credential store.

Webhook do GitHub

Inicie deployai serve sob seu supervisor de processos e exponha POST /webhook/github/<projeto> por HTTPS. Cada projeto recebe automaticamente um segredo aleatório de 256 bits em .webhook-secret, com permissão 0600. No TUI, selecione o projeto e pressione s para consultar:

Endpoint: /webhook/github/minha-app
Secret: 7f1c...e92a

Cadastre no GitHub a URL completa desse endpoint e o segredo exibido. O endpoint valida obrigatoriamente X-Hub-Signature-256 com o segredo daquele projeto e também confirma que repositório e branch do payload correspondem ao config.toml. Ele aceita estes eventos:

  • push, filtrado por repository e branch;
  • workflow_run, somente quando concluído com sucesso e na branch configurada;
  • registry_package, filtrado pelo repositório.

GET /healthz pode ser usado pelo supervisor. Para pipelines de imagem, o evento workflow_run do workflow que publica no GHCR costuma ser o gatilho mais previsível.

Pressione S no TUI para rotacionar o segredo. A operação pede confirmação e o webhook do GitHub precisará ser atualizado com o novo valor. Se o diretório do projeto for um repositório Git, inclua .webhook-secret no .gitignore; esse arquivo nunca deve ser versionado.

Sobre zero downtime

O MVP faz deploy com health gate e só troca/publica a rota depois da saúde ser confirmada. Isso evita encaminhar tráfego para uma aplicação ainda iniciando, mas o Docker Compose isoladamente não garante sobreposição entre a instância antiga e a nova. Zero downtime estrito requer blue-green (dois nomes/projetos de Compose e troca de upstream) ou um orquestrador com rolling update. Essa pode ser a próxima camada sem alterar o formato básico dos projetos.

Segurança e operação

  • Não coloque tokens no TOML nem no .env do projeto.
  • Restrinja o socket Docker e execute o deployai apenas em host confiável; acesso ao Docker equivale, na prática, a privilégio administrativo no host.
  • Exponha o webhook somente atrás de TLS e limite acesso ao TUI ao terminal do servidor.
  • O app nunca cria, remove ou recria o container Caddy; no máximo o conecta à rede declarada, grava o snippet e executa o comando de reload configurado.