From 1a13c4d2f24676b163fb131bddf3ddffa332b8cd Mon Sep 17 00:00:00 2001 From: Pulse Agent Date: Wed, 20 May 2026 19:05:42 -0300 Subject: [PATCH] =?UTF-8?q?docs(template):=20swarm-stack-template.yml=20?= =?UTF-8?q?=E2=80=94=20Attachable=3Dfalse=20explicado,=20CLI=20Swarm=20rec?= =?UTF-8?q?omendado,=20project=20em=20modo=20CLI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- runbooks/swarm-stack-template.yml | 75 +++++++++++++------------------ 1 file changed, 32 insertions(+), 43 deletions(-) diff --git a/runbooks/swarm-stack-template.yml b/runbooks/swarm-stack-template.yml index 9492e07..4ac1b79 100644 --- a/runbooks/swarm-stack-template.yml +++ b/runbooks/swarm-stack-template.yml @@ -8,7 +8,7 @@ cp runbooks/swarm-stack-template.yml runbooks/.yml # 2. Editar: services, imagens, réplicas, labels Caddy vim runbooks/.yml -# 3. Deploy +# 3. Deploy via Docker CLI (Swarm nativo — recomendado) docker stack deploy -c runbooks/.yml # 4. Aplicar labels Caddy via Docker CLI (obrigatório — Swarm não herda do compose) @@ -18,6 +18,21 @@ docker service update \ _ ``` +## ⚠️ Rede `public` — Attachable=false + +| Método | Funciona? | Motivo | +|--------|-----------|--------| +| `docker stack deploy` (CLI) | ✅ SIM | Daemon Docker local ignora a restrição | +| Portainer API (`POST /api/stacks`) | ❌ NÃO | Docker Remote API respeita `Attachable=false` | + +**Decisão**: Usar `docker stack deploy` CLI para todas as stacks. +Stacks criadas por CLI aparecem no `docker stack ls` e no Swarm, mas +NÃO aparecem como gerenciáveis no Portainer UI. + +Para ter controle total pelo Portainer, a rede `public` precisaria ser recriada com +`--attachable`, o que causaria uma breve interrupção nos containers existentes. +Atualmente não vale a pena — 19 containers em produção usam `public`. + --- ## Template Completo (v3.9) @@ -27,10 +42,9 @@ version: '3.9' networks: public: - external: true # rede overlay swarm existente — NÃO criá-la aqui + external: true # overlay swarm — Attachable=false (modelo atual) services: - : image: : networks: @@ -54,10 +68,10 @@ services: ## Regras Obrigatórias ### 1. Rede `public` -- É a **única rede overlay attachable** do cluster -- Criada uma única vez por cluster: `docker network create --driver overlay --attachable public` +- É a **única rede overlay** do cluster Octal +- Criada uma única vez: `docker network create --driver overlay --attachable public` +- `Attachable: false` no modelo atual — não alterar sem planejamento - Nunca declarar `external: false` em services — quebra Swarm -- Nunca criar nova rede por stack — causa fragmentação ### 2. Nomes de serviço - **SEM prefixo** no compose: Swarm injeta `_` automaticamente @@ -68,53 +82,28 @@ services: - **NÃO funcionam pelo compose** — `deploy.labels` não vira `Config.Labels` - Aplicar **obrigatoriamente** via CLI após deploy: `docker service update --label-add 'caddy=' _` -- Formato: `caddy=` + `caddy.reverse_proxy={{upstreams }}` ### 4. Labels Traefik (fallback opcional) -- Funcionam pelo compose se colocadas em `deploy.labels`: +- Funcionam pelo compose via `deploy.labels`: ```yaml deploy: labels: - traefik.enable=true - traefik.http.routers..rule=Host(``) - - traefik.http.services..loadbalancer.server.port= ``` -### 5. Registro no Portainer -```bash -# Login admin → JWT -JWT=$(curl -sk -X POST https://dock.octal.tec.br/api/auth \ - -H 'Content-Type: application/json' \ - --data-raw '{"Username":"admin","Password":"***"}' | python3 -c "import json,sys;print(json.loads(sys.stdin.read())['jwt'])") - -# Criar stack (type=2 = SwarmStack) -curl -sk -X POST 'https://dock.octal.tec.br/api/stacks?method=string&type=2&endpointId=1' \ - -H "Authorization: Bearer $JWT" \ - -H 'Content-Type: application/json' \ - -d '{"Name":"","SwarmID":"plz2xbh64yzhgy88jb9stm0pc","StackFileContent":"'"$(cat .yml)"'"}' | python3 -m json.tool -``` - --- ## Stacks Existentes (referência) -| Stack | ID | Serviços | Domínio | -|-------|-----|----------|---------| -| `git` | 9 | gitea | `git.octal.tec.br` | -| `bot` | 2 | beebot, redis | `ai.octal.tec.br` | -| `pro` | 7 | leantime, db | `manager.octal.tec.br` | -| `design` | 6 | penpot (7 svc) | — | -| `proxy` | — | caddy, test-octal | `test.octal.tec.br` | -| `project` | 12 | games-demo, projects-landing | `games.octal.tec.br` | - ---- - -## Troubleshooting - -| Erro | Causa | Fix | -|------|-------|-----| -| `network public not manually attachable` | Rede `public` não existe ou `Attachable: False` | Criar com `docker network create --driver overlay --attachable public` | -| Serviços não aparecem no Portainer | Criado por `docker stack deploy` (CLI), não pela API | Registrar via API ou aceitar que está compatível Swarm nativo | -| Labels Caddy não aplicam | `deploy.labels` não vira `Config.Labels` no Swarm | Usar `docker service update --label-add` | -| Duplicação de nome (`project_project_X`) | Nomes com prefixo no compose | Remover prefixo, deixar Swarm injetar | -| 401 na API Portainer | Token `ptr_` não é JWT | Login `/api/auth` admin → JWT | +| Stack | Criada por | Controlável Portainer? | +|-------|------------|----------------------| +| `git` | Portainer API | ✅ SIM | +| `bot` | Portainer API | ✅ SIM | +| `pro` | Portainer API | ✅ SIM | +| `design` | Portainer API | ✅ SIM | +| `proxy` | Portainer API | ✅ SIM | +| `project` | `docker stack deploy` CLI | ⚠️ NÃO (Attachable=false) | +| `dock` | Portainer API | ✅ SIM | +| `code` | Portainer API | ✅ SIM | +| `database` | Portainer API | ✅ SIM |