Fix master-api Docker runtime: flat deps, explicit env, longer health start period.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
96a0bbface
commit
4e232e8ef6
3 changed files with 62 additions and 41 deletions
|
|
@ -25,13 +25,13 @@
|
|||
"fastify": "^5.2.1",
|
||||
"ioredis": "^5.4.2",
|
||||
"nanoid": "^5.0.9",
|
||||
"prisma": "^6.3.1",
|
||||
"stremio-addon-sdk": "^1.6.10",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.7",
|
||||
"@types/ws": "^8.5.14",
|
||||
"prisma": "^6.3.1",
|
||||
"tsx": "^4.19.2",
|
||||
"typescript": "^5.7.3"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,33 +2,49 @@ FROM node:20-alpine AS base
|
|||
RUN corepack enable && corepack prepare pnpm@9.15.4 --activate
|
||||
WORKDIR /app
|
||||
|
||||
FROM base AS deps
|
||||
COPY package.json pnpm-workspace.yaml ./
|
||||
COPY apps/master-api/package.json ./apps/master-api/
|
||||
COPY packages/shared-types/package.json ./packages/shared-types/
|
||||
COPY packages/protocol/package.json ./packages/protocol/
|
||||
RUN pnpm install --no-frozen-lockfile
|
||||
|
||||
FROM base AS builder
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY --from=deps /app/apps ./apps
|
||||
COPY --from=deps /app/packages ./packages
|
||||
COPY package.json pnpm-workspace.yaml ./
|
||||
COPY packages ./packages
|
||||
COPY apps/master-api ./apps/master-api
|
||||
RUN pnpm --filter @media-cluster/shared-types build \
|
||||
&& pnpm --filter @media-cluster/protocol build
|
||||
COPY packages ./packages
|
||||
RUN pnpm install --no-frozen-lockfile
|
||||
RUN pnpm --filter @media-cluster/shared-types build
|
||||
RUN pnpm --filter @media-cluster/protocol build
|
||||
WORKDIR /app/apps/master-api
|
||||
RUN pnpm exec prisma generate && pnpm build
|
||||
RUN pnpm exec prisma generate
|
||||
RUN pnpm build
|
||||
|
||||
# Assemble a flat runtime directory (avoids broken pnpm symlinks in final image)
|
||||
WORKDIR /app
|
||||
RUN mkdir -p /out/node_modules/@media-cluster \
|
||||
&& cp -R apps/master-api/dist /out/dist \
|
||||
&& cp -R apps/master-api/prisma /out/prisma \
|
||||
&& cp apps/master-api/package.json /out/package.json \
|
||||
&& cp -R packages/shared-types /out/node_modules/@media-cluster/shared-types \
|
||||
&& cp -R packages/protocol /out/node_modules/@media-cluster/protocol
|
||||
|
||||
FROM node:20-alpine AS runner
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
RUN apk add --no-cache openssl wget
|
||||
COPY --from=builder /app/apps/master-api/dist ./dist
|
||||
COPY --from=builder /app/apps/master-api/package.json ./package.json
|
||||
COPY --from=builder /app/apps/master-api/prisma ./prisma
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
COPY --from=builder /app/packages ./packages
|
||||
RUN apk add --no-cache openssl wget python3 make g++
|
||||
COPY --from=builder /out/ ./
|
||||
|
||||
# Drop workspace: protocol deps; keep prisma CLI for migrate
|
||||
RUN node -e "\
|
||||
const fs=require('fs');\
|
||||
const p=JSON.parse(fs.readFileSync('package.json','utf8'));\
|
||||
delete p.dependencies['@media-cluster/protocol'];\
|
||||
delete p.dependencies['@media-cluster/shared-types'];\
|
||||
p.dependencies.prisma = (p.devDependencies && p.devDependencies.prisma) || '6.3.1';\
|
||||
delete p.devDependencies;\
|
||||
delete p.scripts;\
|
||||
fs.writeFileSync('package.json', JSON.stringify(p, null, 2));"
|
||||
|
||||
RUN npm install --omit=dev \
|
||||
&& npx prisma generate \
|
||||
&& apk del python3 make g++
|
||||
|
||||
EXPOSE 3000
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=5 \
|
||||
CMD wget -qO- http://127.0.0.1:3000/health || exit 1
|
||||
|
||||
CMD ["sh", "-c", "npx prisma migrate deploy && node dist/app.js"]
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
# Docker Compose tuned for Dokploy
|
||||
# Deploy as: Compose application → Git provider → compose path:
|
||||
# deploy/docker/docker-compose.dokploy.yml
|
||||
# Docker Compose for Dokploy
|
||||
# Compose path: deploy/docker/docker-compose.dokploy.yml
|
||||
#
|
||||
# Set environment variables in the Dokploy UI (Environment tab).
|
||||
# Dokploy writes them to .env next to this compose file.
|
||||
# Put secrets in Dokploy Environment tab (NOT env_file).
|
||||
# Dokploy injects them for ${VAR} substitution.
|
||||
|
||||
services:
|
||||
postgres:
|
||||
|
|
@ -11,15 +10,16 @@ services:
|
|||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-media}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-media_cluster}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER:-media} -d $${POSTGRES_DB:-media_cluster}"]
|
||||
test: ["CMD-SHELL", "pg_isready -U \"$$POSTGRES_USER\" -d \"$$POSTGRES_DB\""]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
retries: 10
|
||||
start_period: 10s
|
||||
networks:
|
||||
- media-cluster
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ services:
|
|||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
retries: 10
|
||||
networks:
|
||||
- media-cluster
|
||||
|
||||
|
|
@ -41,28 +41,35 @@ services:
|
|||
context: ../..
|
||||
dockerfile: deploy/docker/Dockerfile.master-api
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
HOST: 0.0.0.0
|
||||
PORT: 3000
|
||||
PORT: "3000"
|
||||
DATABASE_URL: postgresql://${POSTGRES_USER:-media}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-media_cluster}
|
||||
REDIS_URL: redis://redis:6379
|
||||
SESSION_SECRET: ${SESSION_SECRET:?SESSION_SECRET is required}
|
||||
ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@localhost}
|
||||
ADMIN_PASSWORD: ${ADMIN_PASSWORD:-changeme123}
|
||||
PUBLIC_URL: ${PUBLIC_URL:-https://master.vonas.nl}
|
||||
TMDB_API_KEY: ${TMDB_API_KEY:-}
|
||||
PLAYBACK_IDLE_TIMEOUT_SECONDS: ${PLAYBACK_IDLE_TIMEOUT_SECONDS:-1200}
|
||||
PLAYBACK_ABSOLUTE_LIFETIME_SECONDS: ${PLAYBACK_ABSOLUTE_LIFETIME_SECONDS:-43200}
|
||||
NODE_HEARTBEAT_INTERVAL_SECONDS: ${NODE_HEARTBEAT_INTERVAL_SECONDS:-30}
|
||||
NODE_OFFLINE_THRESHOLD_SECONDS: ${NODE_OFFLINE_THRESHOLD_SECONDS:-90}
|
||||
HIDE_UNAVAILABLE_TITLES: ${HIDE_UNAVAILABLE_TITLES:-false}
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
# Host ports (avoid Dokploy UI on :3000)
|
||||
ports:
|
||||
- "3100:3000"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
|
||||
interval: 30s
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
retries: 10
|
||||
start_period: 90s
|
||||
networks:
|
||||
media-cluster:
|
||||
aliases:
|
||||
|
|
@ -78,12 +85,10 @@ services:
|
|||
environment:
|
||||
HOSTNAME: 0.0.0.0
|
||||
PORT: "3000"
|
||||
# Prefer compose DNS; fallback via published host port
|
||||
MASTER_API_URL: http://master-api:3000
|
||||
NEXT_PUBLIC_API_URL: http://master-api:3000
|
||||
depends_on:
|
||||
master-api:
|
||||
condition: service_healthy
|
||||
- master-api
|
||||
ports:
|
||||
- "3101:3000"
|
||||
networks:
|
||||
|
|
|
|||
Loading…
Reference in a new issue