fix(docker): reach services by unique aliases, not bare service names
In Dokploy, services with a domain join the shared dokploy-network, where another project also has an `api`. nginx proxied /api to `api:3000`, so Docker DNS returned both containers and half of the requests went to the other app: 404 "Cannot POST /api/auth/token" on sign-in and "sign-in not configured" when /api/auth/config was answered by it. Services now get task-stream-* aliases on the project network and nginx and the API use them (task-stream-api, -postgres, -mongo, -redis). The API's OPENAPI_FILE is empty in the container; docs 07 explain the aliases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
# Same-origin API for the SPA: REST under /api, GraphQL (HTTP + WebSocket) under /graphql.
|
||||
# The API is reached by its unique alias (task-stream-api), not by the service name `api`:
|
||||
# on a shared network (Dokploy) another project's `api` would get half of the requests.
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
@@ -9,13 +11,13 @@ server {
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://api:3000;
|
||||
proxy_pass http://task-stream-api:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
location /graphql {
|
||||
proxy_pass http://api:3000;
|
||||
proxy_pass http://task-stream-api:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
# No ports are published here: services only talk over the compose network, and the web is
|
||||
# exposed through the platform's proxy (Dokploy domain → service `web`, port 80).
|
||||
#
|
||||
# Services talk to each other by unique aliases (task-stream-*), never by the bare service
|
||||
# name: on a shared network (Dokploy's dokploy-network) other projects also have an `api`,
|
||||
# `postgres` or `redis`, and Docker DNS would hand out theirs too.
|
||||
#
|
||||
# Locally, `docker compose` also loads docker-compose.override.yml, which publishes the ports:
|
||||
# docker compose up -d --build → everything: web on http://localhost:8080
|
||||
# docker compose up -d postgres mongo redis → only infrastructure (then `npx nx serve api` / `npx nx serve web`)
|
||||
@@ -16,6 +20,7 @@ services:
|
||||
secrets: [nexus_token]
|
||||
image: task-stream-web
|
||||
expose: ['80']
|
||||
networks: [default]
|
||||
depends_on:
|
||||
api: { condition: service_healthy }
|
||||
restart: unless-stopped
|
||||
@@ -27,12 +32,15 @@ services:
|
||||
secrets: [nexus_token]
|
||||
image: task-stream-api
|
||||
expose: ['3000']
|
||||
networks:
|
||||
default:
|
||||
aliases: [task-stream-api]
|
||||
environment:
|
||||
POSTGRES_URL: postgres://taskstream:taskstream@postgres:5432/taskstream
|
||||
POSTGRES_URL: postgres://taskstream:taskstream@task-stream-postgres:5432/taskstream
|
||||
# No migrations yet: TypeORM creates the event store and lookup tables.
|
||||
POSTGRES_SYNCHRONIZE: 'true'
|
||||
MONGO_URL: mongodb://mongo:27017/taskstream_read
|
||||
REDIS_URL: redis://redis:6379
|
||||
MONGO_URL: mongodb://task-stream-mongo:27017/taskstream_read
|
||||
REDIS_URL: redis://task-stream-redis:6379
|
||||
EVENT_STREAM_KEY: task-stream:events
|
||||
EVENTS_BRIDGE_ENABLED: 'true'
|
||||
PIREON_BASE_URL: https://oauth.pireon.dev
|
||||
@@ -40,8 +48,10 @@ services:
|
||||
PIREON_CLIENT_ID: ${PIREON_CLIENT_ID:-}
|
||||
PIREON_CLIENT_SECRET: ${PIREON_CLIENT_SECRET:-}
|
||||
GRAPHQL_PLAYGROUND: 'true'
|
||||
# The SDL file is only useful in development (codegen).
|
||||
# The SDL / OpenAPI files are only useful in development (codegen); the
|
||||
# document is still served at /api/docs-json.
|
||||
GRAPHQL_SCHEMA_FILE: ''
|
||||
OPENAPI_FILE: ''
|
||||
depends_on:
|
||||
postgres: { condition: service_healthy }
|
||||
mongo: { condition: service_healthy }
|
||||
@@ -50,6 +60,9 @@ services:
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
networks:
|
||||
default:
|
||||
aliases: [task-stream-postgres]
|
||||
environment:
|
||||
POSTGRES_USER: taskstream
|
||||
POSTGRES_PASSWORD: taskstream
|
||||
@@ -62,6 +75,9 @@ services:
|
||||
|
||||
mongo:
|
||||
image: mongo:8
|
||||
networks:
|
||||
default:
|
||||
aliases: [task-stream-mongo]
|
||||
volumes: [mongo-data:/data/db]
|
||||
healthcheck:
|
||||
test: ['CMD', 'mongosh', '--quiet', '--eval', 'db.adminCommand("ping")']
|
||||
@@ -70,6 +86,9 @@ services:
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
networks:
|
||||
default:
|
||||
aliases: [task-stream-redis]
|
||||
command: ['redis-server', '--appendonly', 'yes']
|
||||
volumes: [redis-data:/data]
|
||||
healthcheck:
|
||||
|
||||
@@ -27,6 +27,15 @@ docker compose down # parar (-v borra los datos)
|
||||
|
||||
Para probar en local exactamente lo de producción: `docker compose -f docker-compose.yml up -d --build`.
|
||||
|
||||
### Nombres únicos en la red
|
||||
|
||||
Los servicios se llaman entre sí por **alias únicos** (`task-stream-api`, `task-stream-postgres`, `task-stream-mongo`,
|
||||
`task-stream-redis`), no por el nombre del servicio. Al dar dominio a un servicio, Dokploy lo conecta a la red
|
||||
compartida `dokploy-network`, donde otros proyectos también tienen un `api`, un `postgres` o un `redis`: con nombres
|
||||
genéricos, el DNS de Docker devuelve también los suyos y nginx reparte las peticiones entre ambos (síntoma: la mitad
|
||||
de las llamadas a `/api/*` responden `404 Cannot GET …` y el login dice «no configurado»). Si añades un servicio,
|
||||
dale su alias `task-stream-*` y úsalo en las URLs.
|
||||
|
||||
Todos tienen healthcheck; `web` espera a que `api` esté sana, y `api` a las tres bases de datos.
|
||||
|
||||
### Imágenes
|
||||
@@ -78,6 +87,8 @@ donde los lee Compose.
|
||||
| `AUTH_SESSION_TTL_SECONDS` | `60` | Cuánto se confía en un token validado antes de volver a preguntar a Pireon |
|
||||
| `GRAPHQL_PLAYGROUND` | `true` | GraphiQL e introspección |
|
||||
| `GRAPHQL_SCHEMA_FILE` | `apps/api/schema.gql` | Dónde escribir el SDL (vacío = no escribir; así está en Docker) |
|
||||
| `SWAGGER_ENABLED` | `true` | API REST documentada: Swagger UI en `/api/docs`, OpenAPI en `/api/docs-json` |
|
||||
| `OPENAPI_FILE` | `apps/api/openapi.json` | Dónde escribir el documento OpenAPI al arrancar (vacío = no escribir; así en Docker) |
|
||||
|
||||
La web no tiene configuración de entorno: llama a la API en su mismo origen (`/api`, `/graphql`).
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user