Adds a StepRunUpdater step that starts app-dono-updater after the app container comes up: a poll loop (docker pull, compare image IDs, recreate on change) baked into the official docker:cli image via `sh -c`, reusing the same docker run argv as the initial container start so the two can't drift. Not built on Watchtower: containrrr/watchtower was archived upstream in Dec 2025 with no maintained successor recommended for production use, so this avoids taking on that dependency.
235 lines
10 KiB
Markdown
235 lines
10 KiB
Markdown
# App do Dono — Instalador Cliente (TUI)
|
|
|
|
Instalador de terminal (TUI) que faz, em poucos passos guiados, a configuração e o
|
|
provisionamento do **middleware cliente** do "App do Dono". Esse middleware roda na
|
|
infraestrutura do **tenant** (cliente) e é responsável por intermediar a comunicação
|
|
entre os servidores do tenant e o **servidor central** da davinTI.
|
|
|
|
A ferramenta cuida de tudo de ponta a ponta: valida o Docker, autentica no registry
|
|
privado, baixa as imagens, coleta as configurações via formulários no terminal, gera
|
|
os arquivos de configuração (`config.toml` e `envs`) e sobe os containers necessários.
|
|
|
|
> Construído com [Bubble Tea](https://github.com/charmbracelet/bubbletea),
|
|
> [Bubbles](https://github.com/charmbracelet/bubbles) e
|
|
> [Lip Gloss](https://github.com/charmbracelet/lipgloss) (linha Charm v2).
|
|
|
|
---
|
|
|
|
## Sumário
|
|
|
|
- [App do Dono — Instalador Cliente (TUI)](#app-do-dono--instalador-cliente-tui)
|
|
- [Sumário](#sumário)
|
|
- [O que ele faz](#o-que-ele-faz)
|
|
- [Pré-requisitos](#pré-requisitos)
|
|
- [Como usar](#como-usar)
|
|
- [Navegação na interface](#navegação-na-interface)
|
|
- [Fluxo de instalação](#fluxo-de-instalação)
|
|
- [Conectividade: IP público vs. vproxy](#conectividade-ip-público-vs-vproxy)
|
|
- [Arquivos gerados](#arquivos-gerados)
|
|
- [Containers e rede Docker](#containers-e-rede-docker)
|
|
- [Build a partir do código](#build-a-partir-do-código)
|
|
- [Documentação adicional](#documentação-adicional)
|
|
|
|
---
|
|
|
|
## O que ele faz
|
|
|
|
O instalador conduz o operador por um assistente (wizard) no terminal que:
|
|
|
|
1. **Verifica o Docker** na máquina (encerra com instruções se não houver).
|
|
2. **Autentica** no registry Docker privado (`hub.davinti.com.br`).
|
|
3. **Baixa a imagem** do app cliente (`app-dono/app-cliente`).
|
|
4. Pergunta se a máquina possui **IP público**:
|
|
- **Sim** → segue direto para a configuração da aplicação.
|
|
- **Não** → configura o túnel **vproxy** (WireGuard) e sobe esse container antes.
|
|
5. Coleta, via formulários, as configurações de **aplicação, servidor, banco de dados
|
|
e certificados**.
|
|
6. **Gera o `config.toml`** e sobe o container `app-dono-cliente`.
|
|
7. Sobe o container **`app-dono-updater`**, que mantém o `app-dono-cliente`
|
|
atualizado automaticamente a cada novo push em `:latest`.
|
|
8. Exibe a confirmação de sucesso.
|
|
|
|
## Pré-requisitos
|
|
|
|
- **Docker** instalado e em execução na máquina de destino.
|
|
- O instalador **não** instala o Docker automaticamente — se não encontrar, ele
|
|
orienta a instalação manual e encerra.
|
|
- **Credenciais** do registry privado `hub.davinti.com.br`.
|
|
- **Token de inscrição** (enrollment token) gerado no painel web do App do Dono.
|
|
- Quando **não** houver IP público: dados do túnel **vproxy** (chave privada, IP
|
|
virtual, pre-shared key e mapeamento de proxy).
|
|
- Diretório local com os **certificados** mTLS do cliente (`client.crt`, `client.key`,
|
|
`ca.crt`).
|
|
|
|
## Como usar
|
|
|
|
Baixe o binário pré-compilado correspondente ao seu sistema operacional (distribuído
|
|
via S3 — veja o time de infraestrutura) e execute:
|
|
|
|
```bash
|
|
chmod +x installer-linux-amd64
|
|
./installer-linux-amd64
|
|
```
|
|
|
|
Ou rode direto a partir do código-fonte:
|
|
|
|
```bash
|
|
go run ./cmd
|
|
```
|
|
|
|
### Navegação na interface
|
|
|
|
| Tecla | Ação |
|
|
| ------------------ | ------------------------------------- |
|
|
| `Tab` / `↓` | Próximo campo |
|
|
| `Shift+Tab` / `↑` | Campo anterior |
|
|
| `←` / `→` | Alternar opção (campos de seleção) |
|
|
| `Enter` | Confirmar campo / avançar etapa |
|
|
| `Esc` | Voltar à etapa anterior |
|
|
| `r` | Tentar novamente (em telas de erro) |
|
|
| Qualquer tecla | Avançar em telas de status |
|
|
| `Ctrl+C` | Sair a qualquer momento |
|
|
|
|
## Fluxo de instalação
|
|
|
|
```
|
|
┌──────────────────┐
|
|
│ Verifica Docker │ ──── não instalado ──► orienta instalação e encerra
|
|
└────────┬─────────┘
|
|
│ instalado
|
|
▼
|
|
┌──────────────────┐
|
|
│ Login Registry │
|
|
└────────┬─────────┘
|
|
▼
|
|
┌──────────────────┐
|
|
│ Baixa imagem │ (app-cliente)
|
|
│ app-cliente │
|
|
└────────┬─────────┘
|
|
▼
|
|
┌──────────────────┐
|
|
│ Tem IP público? │
|
|
└───┬──────────┬───┘
|
|
│ Sim │ Não
|
|
│ ▼
|
|
│ ┌──────────────────┐
|
|
│ │ Config. vproxy │ → gera "envs" → baixa imagem vproxy → sobe container vproxy
|
|
│ └────────┬─────────┘
|
|
│ │
|
|
▼ ▼
|
|
┌─────────────────────────────────────────┐
|
|
│ Config. Aplicação → Servidor → │
|
|
│ Banco de Dados → Certificados │
|
|
└────────────────────┬────────────────────┘
|
|
▼
|
|
┌──────────────────┐
|
|
│ Revisão (Review) │ ← esc volta para editar
|
|
└────────┬─────────┘
|
|
▼
|
|
┌──────────────────┐
|
|
│ Gera config.toml │
|
|
└────────┬─────────┘
|
|
▼
|
|
┌──────────────────┐
|
|
│ Sobe container │ (app-dono-cliente)
|
|
│ app-dono-cliente │
|
|
└────────┬─────────┘
|
|
▼
|
|
┌──────────────────┐
|
|
│ Sobe container │ (app-dono-updater,
|
|
│ de auto-update │ atualiza o app-cliente sozinho)
|
|
└────────┬─────────┘
|
|
▼
|
|
✅ Concluído
|
|
```
|
|
|
|
## Conectividade: IP público vs. vproxy
|
|
|
|
O middleware cliente precisa se comunicar com o servidor central. A forma de
|
|
conectividade depende da infraestrutura do tenant:
|
|
|
|
- **Com IP público:** a comunicação é direta; o passo do vproxy é pulado.
|
|
- **Sem IP público:** sobe-se o container **vproxy** (túnel WireGuard, imagem
|
|
`davinti-vproxy`), que estabelece o túnel de saída e expõe os serviços necessários
|
|
através do `PROXY_EDPS`. O protocolo padrão é **UDP** (melhor desempenho); caso
|
|
firewalls restritivos bloqueiem UDP, é possível selecionar **TCP**.
|
|
|
|
## Arquivos gerados
|
|
|
|
O instalador gera dois arquivos no diretório de execução:
|
|
|
|
- **`config.toml`** — configuração do app cliente (servidor, banco, certificados,
|
|
aplicação, log). É montado dentro do container em `/app/config.toml`.
|
|
- **`envs`** — variáveis de ambiente do vproxy/WireGuard (gerado somente quando não há
|
|
IP público). É passado ao container via `--env-file`.
|
|
|
|
Ambos os arquivos são reaproveitados como **valores padrão** caso já existam ao reabrir
|
|
o instalador (no caso do `config.toml`).
|
|
|
|
## Containers e rede Docker
|
|
|
|
`app-dono-cliente` e `vproxy` são conectados à rede Docker **`app-dono_app`** (criada
|
|
automaticamente se não existir). O `app-dono-updater` fica fora dessa rede — ele só fala
|
|
com o daemon Docker via socket, não com os outros containers pela rede.
|
|
|
|
| Container | Imagem | Quando sobe |
|
|
| --------------------- | ------------------------------------------------ | -------------------- |
|
|
| `app-dono-cliente` | `hub.davinti.com.br:443/app-dono/app-cliente` | Sempre |
|
|
| `vproxy` | `hub.davinti.com.br:443/davinti-vproxy` | Quando não há IP púb.|
|
|
| `app-dono-updater` | `docker:cli` | Sempre |
|
|
|
|
Características:
|
|
|
|
- Todos sobem com `--restart unless-stopped`.
|
|
- O container do app expõe a porta configurada no host, mapeando para a `8080` interna,
|
|
e monta o `config.toml` e o diretório de certificados como volumes.
|
|
- O `vproxy` roda com `--cap-add=NET_ADMIN` e acesso a `/dev/net/tun`.
|
|
- O `app-dono-updater` **não** é o Watchtower — esse projeto foi arquivado pelos
|
|
mantenedores originais em dez/2025 sem um sucessor mantido recomendado para produção.
|
|
Em vez disso, é um loop simples (`sh -c`) rodando na imagem oficial `docker:cli`: a
|
|
cada 5 minutos baixa a imagem do `app-dono-cliente`, compara com a que está rodando e,
|
|
se mudou, recria o container. Usa as mesmas credenciais do login feito no passo 2 (via
|
|
`~/.docker/config.json`) e precisa de acesso ao socket do Docker
|
|
(`/var/run/docker.sock`) para poder recriar o container.
|
|
- O **modo compatibilidade** (`seccomp=unconfined`) pode ser ativado para máquinas
|
|
antigas onde o seccomp padrão causa problemas.
|
|
|
|
## Build a partir do código
|
|
|
|
Requer **Go 1.25+**. O `Makefile` gera binários estáticos para múltiplas plataformas:
|
|
|
|
```bash
|
|
make build # compila para linux/darwin/windows (amd64/arm64) em ./dist
|
|
make build VERSION=2.0.0 # define a versão
|
|
make clean # remove ./dist
|
|
|
|
# Publicação no S3 (requer S3_BUCKET):
|
|
make push S3_BUCKET=meu-bucket VERSION=1.0.0
|
|
make release S3_BUCKET=meu-bucket VERSION=2.0.0
|
|
make help # lista variáveis e alvos
|
|
```
|
|
|
|
Para um build local rápido:
|
|
|
|
```bash
|
|
go build -o installer ./cmd
|
|
./installer
|
|
```
|
|
|
|
A versão é gravada no binário em tempo de build (`make build VERSION=1.2.0`) e pode ser
|
|
consultada sem abrir a interface:
|
|
|
|
```bash
|
|
./installer --version # ex.: app-dono installer 1.2.0
|
|
```
|
|
|
|
Um `go build` simples (sem o `Makefile`) deixa a versão como `dev`.
|
|
|
|
## Documentação adicional
|
|
|
|
- [docs/fluxo.md](docs/fluxo.md) — detalhamento de cada etapa do assistente.
|
|
- [docs/configuracao.md](docs/configuracao.md) — referência de todos os campos de
|
|
configuração e dos arquivos gerados.
|
|
- [docs/arquitetura.md](docs/arquitetura.md) — visão da arquitetura interna do código
|
|
(modelo Bubble Tea, comandos, etapas).
|