-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocker-compose.example.yml
More file actions
195 lines (188 loc) · 8.58 KB
/
Copy pathdocker-compose.example.yml
File metadata and controls
195 lines (188 loc) · 8.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
name: 9rtksync-stack
services:
9rtk-router:
image: decolua/9router:latest
container_name: 9rtk-router
hostname: 9rtk-router
networks:
# Duas redes de proposito (ver o bloco `networks:` no fim do arquivo):
# a propria, de gestao, onde so o sincronizador desta stack o alcanca; e
# a de inferencia, onde o LiteLLM o encontra pelo nome `9rtk-router`.
- 9rtksync-net
- rtk-inference-net
restart: unless-stopped
ports:
# Porta interna 20128 (padrao do 9Router); publicada em 8081 no host.
# A 20128 do host fica para a stack do artigo (claudegravity), que usa
# a porta padrao -- assim as duas rodam juntas sem colidir.
- "127.0.0.1:8081:20128"
environment:
- DATA_DIR=/app/data
- PORT=20128
- HOSTNAME=0.0.0.0
- NEXT_PUBLIC_BASE_URL=http://localhost:8081
- NODE_ENV=production
# Sem valor de fallback: um default publicado em arquivo de exemplo vira
# a senha real de toda implantacao que so copiou e colou. O compose
# recusa subir ate que as duas variaveis estejam definidas no .env.
- INITIAL_PASSWORD=${INITIAL_PASSWORD:?defina INITIAL_PASSWORD no .env}
- JWT_SECRET=${JWT_SECRET:?defina JWT_SECRET no .env (openssl rand -hex 32)}
- REQUIRE_API_KEY=false
# REQUIRE_LOGIN=false so e aceitavel porque a porta acima esta presa em
# 127.0.0.1. Ao expor 20128 na rede, mude para true.
- REQUIRE_LOGIN=false
volumes:
- 9router_data:/app/data
9rtk-sync:
# Mesmo uid do gateway. Os dois compartilham o volume, e este servico
# cria db/ e logs/ no startup: rodando como root, esses diretorios
# nasciam com dono root e o 9router -- que roda como `node` (1000) --
# perdia a escrita no proprio volume, recusando o login com
# "EACCES: permission denied, mkdir '/app/data/db/backups'".
user: "1000:1000"
image: ghcr.io/pathbit/9rtksync:latest
container_name: 9rtk-sync
hostname: 9rtk-sync
networks:
- 9rtksync-net
restart: unless-stopped
ports:
# Porta interna 9090 (igual no OminiRTKSync); publicada em 9091 no host.
# O bind em 127.0.0.1 mantem o painel e o SQLite fora da internet.
- "127.0.0.1:9091:9090"
volumes:
- 9router_data:/app/data
- ${HOME}:/root/host:ro
- 9rtksync_logs:/app/logs
environment:
- HOST_HOME=/root/host
- DB_PATH=/app/data/db/data.sqlite
- ROUTER_URL=${ROUTER_URL:-http://9rtk-router:20128}
- SYNC_INTERVAL=${SYNC_INTERVAL:-300}
- REFRESH_MARGIN=${REFRESH_MARGIN:-900}
- CRON_ENABLED=${CRON_ENABLED:-1}
# - CRON_INTERVAL=300 # herda SYNC_INTERVAL quando omitido
- ENABLE_WEB_DASHBOARD=${ENABLE_WEB_DASHBOARD:-1}
- WEB_PORT=${WEB_PORT:-9090}
- DASHBOARD_USER=${DASHBOARD_USER:-admin}
- DASHBOARD_PASSWORD=${DASHBOARD_PASSWORD:-}
# Credencial de emergencia (usuario 'admin' + este valor como senha).
# Se omitida, e gerada no primeiro boot e registrada no arquivo de log.
# - DASHBOARD_RECOVERY_HASH=
# Validacao viva de credenciais: pergunta ao provedor se a chave ainda e
# aceita, em vez de assumir que uma conexao esta saudavel por carregar uma
# credencial. Anunciadas no .env.example e lidas pelo Settings, faltava
# repassa-las ao container.
- CREDENTIAL_CHECK_ENABLED=${CREDENTIAL_CHECK_ENABLED:-1}
- CREDENTIAL_CHECK_TIMEOUT=${CREDENTIAL_CHECK_TIMEOUT:-8}
# Entrada federada (SSO). Vazia = o segredo do cliente e administrado pela
# tela e gravado com modo 0600; preenchida = o ambiente vence e a tela
# trava o campo. SSO_DISABLED=1 desliga o SSO sem tocar no banco.
- OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET:-}
- SSO_DISABLED=${SSO_DISABLED:-0}
- LOG_DIR=${LOG_DIR:-/app/logs}
- LOG_RETENTION_DAYS=${LOG_RETENTION_DAYS:-30}
- LOG_LEVEL=${LOG_LEVEL:-INFO}
depends_on:
- 9rtk-router
healthcheck:
test: ["CMD", "/opt/venv/bin/python3", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:9090/healthz', timeout=3)"]
interval: 15s
timeout: 5s
retries: 3
start_period: 10s
# --- Acesso remoto (opcional, nao sobe por padrao) -----------------------
#
# Os dois servicos abaixo so existem quando voce pede o perfil:
# docker compose --profile tunel up -d # URL publica via Cloudflare
# docker compose --profile tailnet up -d # so quem esta na sua tailnet
#
# ANTES DE LIGAR QUALQUER UM DOS DOIS, leia docs/wiki/Remote-Access.md. O
# resumo: com a porta presa em 127.0.0.1, REQUIRE_LOGIN=false e aceitavel
# porque so a sua maquina alcanca. No instante em que um tunel sobe, esse
# raciocinio se inverte -- e o proprio painel do gateway avisa isso em
# vermelho ("Change the default dashboard password before activating the
# tunnel").
9rtk-tunel:
# Um container em vez do botao do gateway: o botao instala o cloudflared
# DENTRO do container do gateway, que e efemero -- recriar a stack desfaz a
# instalacao. Aqui o tunel e uma peca declarada, que sobe e desce com o
# resto e deixa rastro no compose.
image: cloudflare/cloudflared:latest
container_name: 9rtk-tunel
hostname: 9rtk-tunel
profiles: ["tunel"]
restart: unless-stopped
# Sem TUNNEL_TOKEN: quick tunnel, URL aleatoria a cada subida, zero
# configuracao, boa para uma demonstracao. Com TUNNEL_TOKEN de um tunel
# nomeado: URL estavel e a possibilidade de por o Cloudflare Access na
# frente, que autentica ANTES de a requisicao chegar no gateway.
command: >-
tunnel --no-autoupdate
${TUNNEL_TOKEN:+run --token ${TUNNEL_TOKEN}}
${TUNNEL_TOKEN:---url http://9rtk-router:20128}
networks:
- 9rtksync-net
depends_on:
- 9rtk-router
9rtk-tailnet:
# Diferenca que decide a escolha: o tunel da uma URL que QUALQUER UM com o
# endereco alcanca; a tailnet so admite dispositivo que voce cadastrou.
# Para um painel que le credenciais, a segunda e quase sempre a certa.
image: tailscale/tailscale:latest
container_name: 9rtk-tailnet
# UNICA excecao a regra "container_name igual ao hostname" desta stack, e de
# proposito: o hostname deste container vira o NOME DO NO na tailnet, ou seja,
# o endereco que voce digita no navegador (http://9rtk:9090). Com
# `9rtk-tailnet` viraria http://9rtk-tailnet:9090 -- mais longo de
# digitar, e sem ganho nenhum, porque dentro da stack ninguem alcanca este
# container pelo nome: ele existe para expor o painel para FORA.
hostname: 9rtk
profiles: ["tailnet"]
restart: unless-stopped
environment:
# Gere em https://login.tailscale.com/admin/settings/keys (chave efemera,
# para o no sumir sozinho quando o container morrer). Sem `:?` de
# proposito: o compose interpola tudo ANTES de filtrar por perfil, entao
# exigir aqui cobraria a chave ate de quem nunca vai usar este perfil.
# Quem cobra e o proprio container, na partida, e so quando o perfil sobe.
- TS_AUTHKEY=${TS_AUTHKEY:-}
- TS_STATE_DIR=/var/lib/tailscale
- TS_USERSPACE=true
# Publica o painel e o gateway na tailnet, cada um na sua porta.
- TS_SERVE_CONFIG=/config/serve.json
volumes:
- 9rtk_tailnet:/var/lib/tailscale
networks:
- 9rtksync-net
volumes:
9rtk_tailnet:
9router_data:
9rtksync_logs:
networks:
9rtksync-net:
name: 9rtksync-net
# Rede propria da stack. Na rede default, duas stacks no mesmo
# daemon resolvem o mesmo nome curto e nao da para saber a qual
# gateway o sincronizador se conectou.
# POR QUE SAO DUAS REDES
#
# A de cima e de GESTAO e continua isolada: so o sincronizador desta stack
# fala com este gateway. E isso que garante que o painel do 9RTKSync nunca
# leia, sem querer, o gateway do irmao -- antes, com todos na rede default,
# o mesmo nome curto resolvia para stacks diferentes e ninguem sabia a qual
# gateway o painel estava conectado. Nao desfaca.
#
# Esta e de INFERENCIA e e compartilhada de proposito: e o unico lugar onde
# o LiteLLM (litellmrtk-router) e os gateways se enxergam, para que uma
# requisicao que chega no LiteLLM possa sair por http://9rtk-router:20128/v1.
# So os gateways e o LiteLLM entram nela; os sincronizadores NAO -- eles nao
# tem o que fazer no caminho de inferencia, e mante-los de fora preserva o
# isolamento de gestao.
#
# `external: true` porque a rede e compartilhada pelas tres stacks: ela nao
# pertence a nenhuma, nasce e morre fora do ciclo de vida de qualquer uma:
# docker network create rtk-inference-net
rtk-inference-net:
name: rtk-inference-net
external: true