docker: 3-binary deployment (presentation, worker, playout)
This commit is contained in:
@@ -11,24 +11,38 @@
|
|||||||
# TRAEFIK_CERT_RESOLVER cert resolver name for TLS (default: letsencrypt)
|
# TRAEFIK_CERT_RESOLVER cert resolver name for TLS (default: letsencrypt)
|
||||||
# FRONTEND_HOST public hostname for the frontend e.g. tv.example.com
|
# FRONTEND_HOST public hostname for the frontend e.g. tv.example.com
|
||||||
# BACKEND_HOST public hostname for the backend API e.g. tv-api.example.com
|
# BACKEND_HOST public hostname for the backend API e.g. tv-api.example.com
|
||||||
|
# PLAYOUT_HOST public hostname for playout streams e.g. tv-playout.example.com
|
||||||
#
|
#
|
||||||
# Remember: NEXT_PUBLIC_API_URL in .env must be the *public* backend URL,
|
# Remember: NEXT_PUBLIC_API_URL in .env must be the *public* backend URL,
|
||||||
# e.g. https://tv-api.example.com/api/v1, and you must rebuild after changing it.
|
# e.g. https://tv-api.example.com/api/v1, and you must rebuild after changing it.
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|
||||||
backend:
|
presentation:
|
||||||
ports: [] # Traefik handles ingress; no direct port exposure needed
|
ports: []
|
||||||
networks:
|
networks:
|
||||||
- default
|
- default
|
||||||
- traefik
|
- traefik
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
- "traefik.docker.network=${TRAEFIK_NETWORK:-traefik_proxy}"
|
- "traefik.docker.network=${TRAEFIK_NETWORK:-traefik_proxy}"
|
||||||
- "traefik.http.routers.ktv-backend.rule=Host(`${BACKEND_HOST}`)"
|
- "traefik.http.routers.ktv-presentation.rule=Host(`${BACKEND_HOST}`)"
|
||||||
- "traefik.http.routers.ktv-backend.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}"
|
- "traefik.http.routers.ktv-presentation.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}"
|
||||||
- "traefik.http.routers.ktv-backend.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}"
|
- "traefik.http.routers.ktv-presentation.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}"
|
||||||
- "traefik.http.services.ktv-backend.loadbalancer.server.port=3000"
|
- "traefik.http.services.ktv-presentation.loadbalancer.server.port=3000"
|
||||||
|
|
||||||
|
playout:
|
||||||
|
ports: []
|
||||||
|
networks:
|
||||||
|
- default
|
||||||
|
- traefik
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=${TRAEFIK_NETWORK:-traefik_proxy}"
|
||||||
|
- "traefik.http.routers.ktv-playout.rule=Host(`${PLAYOUT_HOST}`)"
|
||||||
|
- "traefik.http.routers.ktv-playout.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}"
|
||||||
|
- "traefik.http.routers.ktv-playout.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}"
|
||||||
|
- "traefik.http.services.ktv-playout.loadbalancer.server.port=9090"
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
ports: []
|
ports: []
|
||||||
|
|||||||
77
compose.yml
77
compose.yml
@@ -1,19 +1,19 @@
|
|||||||
services:
|
services:
|
||||||
|
|
||||||
# ── Backend (Rust / Axum) ──────────────────────────────────────────────────
|
# ── Presentation (Rust / Axum — HTTP API) ────────────────────────────────
|
||||||
backend:
|
presentation:
|
||||||
build: ./k-tv-backend
|
build:
|
||||||
|
context: ./k-tv-backend
|
||||||
|
target: presentation
|
||||||
|
image: registry.gabrielkaszewski.dev/k-tv-presentation:latest
|
||||||
ports:
|
ports:
|
||||||
- "${BACKEND_PORT:-3000}:3000"
|
- "${BACKEND_PORT:-3000}:3000"
|
||||||
environment:
|
environment:
|
||||||
- HOST=0.0.0.0
|
- HOST=0.0.0.0
|
||||||
- PORT=3000
|
- PORT=3000
|
||||||
- DATABASE_URL=sqlite:///app/data/k-tv.db?mode=rwc
|
- DATABASE_URL=sqlite:///app/data/k-tv.db?mode=rwc
|
||||||
# Allow requests from the browser (the user-facing frontend URL)
|
|
||||||
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS}
|
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS}
|
||||||
# Auth — generate with: openssl rand -hex 32
|
|
||||||
- JWT_SECRET=${JWT_SECRET}
|
- JWT_SECRET=${JWT_SECRET}
|
||||||
# Cookie secret — generate with: openssl rand -base64 64
|
|
||||||
- COOKIE_SECRET=${COOKIE_SECRET}
|
- COOKIE_SECRET=${COOKIE_SECRET}
|
||||||
- JWT_EXPIRY_HOURS=${JWT_EXPIRY_HOURS:-24}
|
- JWT_EXPIRY_HOURS=${JWT_EXPIRY_HOURS:-24}
|
||||||
- SECURE_COOKIE=${SECURE_COOKIE:-false}
|
- SECURE_COOKIE=${SECURE_COOKIE:-false}
|
||||||
@@ -21,7 +21,6 @@ services:
|
|||||||
- ALLOW_REGISTRATION=${ALLOW_REGISTRATION:-true}
|
- ALLOW_REGISTRATION=${ALLOW_REGISTRATION:-true}
|
||||||
- DB_MAX_CONNECTIONS=${DB_MAX_CONNECTIONS:-5}
|
- DB_MAX_CONNECTIONS=${DB_MAX_CONNECTIONS:-5}
|
||||||
- DB_MIN_CONNECTIONS=${DB_MIN_CONNECTIONS:-1}
|
- DB_MIN_CONNECTIONS=${DB_MIN_CONNECTIONS:-1}
|
||||||
# Jellyfin — all three required for schedule generation
|
|
||||||
- JELLYFIN_BASE_URL=${JELLYFIN_BASE_URL}
|
- JELLYFIN_BASE_URL=${JELLYFIN_BASE_URL}
|
||||||
- JELLYFIN_API_KEY=${JELLYFIN_API_KEY}
|
- JELLYFIN_API_KEY=${JELLYFIN_API_KEY}
|
||||||
- JELLYFIN_USER_ID=${JELLYFIN_USER_ID}
|
- JELLYFIN_USER_ID=${JELLYFIN_USER_ID}
|
||||||
@@ -34,40 +33,60 @@ services:
|
|||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 3
|
retries: 3
|
||||||
|
|
||||||
|
# ── Worker (background jobs) ─────────────────────────────────────────────
|
||||||
|
worker:
|
||||||
|
build:
|
||||||
|
context: ./k-tv-backend
|
||||||
|
target: worker
|
||||||
|
image: registry.gabrielkaszewski.dev/k-tv-worker:latest
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=sqlite:///app/data/k-tv.db?mode=rwc
|
||||||
|
- JELLYFIN_BASE_URL=${JELLYFIN_BASE_URL}
|
||||||
|
- JELLYFIN_API_KEY=${JELLYFIN_API_KEY}
|
||||||
|
- JELLYFIN_USER_ID=${JELLYFIN_USER_ID}
|
||||||
|
volumes:
|
||||||
|
- backend_data:/app/data
|
||||||
|
depends_on:
|
||||||
|
presentation:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# ── Playout (HLS streaming) ──────────────────────────────────────────────
|
||||||
|
playout:
|
||||||
|
build:
|
||||||
|
context: ./k-tv-backend
|
||||||
|
target: playout
|
||||||
|
image: registry.gabrielkaszewski.dev/k-tv-playout:latest
|
||||||
|
ports:
|
||||||
|
- "${PLAYOUT_PORT:-9090}:9090"
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=sqlite:///app/data/k-tv.db?mode=rwc
|
||||||
|
- PLAYOUT_LISTEN_ADDR=0.0.0.0:9090
|
||||||
|
- PLAYOUT_STORAGE_PATH=/tmp/k-tv-playout
|
||||||
|
- PLAYOUT_SEGMENT_DURATION=${PLAYOUT_SEGMENT_DURATION:-6}
|
||||||
|
volumes:
|
||||||
|
- backend_data:/app/data
|
||||||
|
depends_on:
|
||||||
|
presentation:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
# ── Frontend (Next.js) ────────────────────────────────────────────────────
|
# ── Frontend (Next.js) ────────────────────────────────────────────────────
|
||||||
frontend:
|
frontend:
|
||||||
build:
|
build:
|
||||||
context: ./k-tv-frontend
|
context: ./k-tv-frontend
|
||||||
args:
|
args:
|
||||||
# Browser-visible backend URL — baked into the client bundle at build time.
|
|
||||||
# Rebuild the image after changing this.
|
|
||||||
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:4000/api/v1}
|
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:4000/api/v1}
|
||||||
|
NEXT_PUBLIC_PLAYOUT_URL: ${NEXT_PUBLIC_PLAYOUT_URL:-http://localhost:9090}
|
||||||
|
image: registry.gabrielkaszewski.dev/k-tv-frontend:latest
|
||||||
ports:
|
ports:
|
||||||
- "${FRONTEND_PORT:-3001}:3001"
|
- "${FRONTEND_PORT:-3001}:3001"
|
||||||
environment:
|
environment:
|
||||||
# Server-side API URL — uses Docker's internal network, never exposed.
|
API_URL: http://presentation:3000/api/v1
|
||||||
# Next.js API routes (e.g. /api/stream/[channelId]) use this.
|
|
||||||
API_URL: http://backend:3000/api/v1
|
|
||||||
depends_on:
|
depends_on:
|
||||||
backend:
|
presentation:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
backend_data:
|
backend_data:
|
||||||
|
|
||||||
# ── Optional: PostgreSQL ───────────────────────────────────────────────────
|
|
||||||
# Uncomment the db service and set DATABASE_URL in backend's environment:
|
|
||||||
# DATABASE_URL: postgres://ktv:${POSTGRES_PASSWORD}@db:5432/ktv
|
|
||||||
#
|
|
||||||
# db:
|
|
||||||
# image: postgres:16-alpine
|
|
||||||
# environment:
|
|
||||||
# POSTGRES_USER: ktv
|
|
||||||
# POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
||||||
# POSTGRES_DB: ktv
|
|
||||||
# volumes:
|
|
||||||
# - db_data:/var/lib/postgresql/data
|
|
||||||
# restart: unless-stopped
|
|
||||||
#
|
|
||||||
# db_data:
|
|
||||||
|
|||||||
@@ -1,31 +1,30 @@
|
|||||||
FROM rust:1.92 AS builder
|
FROM rust:1.92 AS builder
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
|
RUN cargo build --release -p presentation -p worker -p playout
|
||||||
|
|
||||||
# Build the release binary
|
# Presentation image
|
||||||
RUN cargo build --release -p api
|
FROM debian:bookworm-slim AS presentation
|
||||||
|
|
||||||
FROM debian:bookworm-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends libssl3 ca-certificates && rm -rf /var/lib/apt/lists/*
|
||||||
# Install OpenSSL, CA certs, and ffmpeg (provides ffprobe for local-files duration scanning)
|
COPY --from=builder /app/target/release/k-tv .
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
||||||
libssl3 \
|
|
||||||
ca-certificates \
|
|
||||||
ffmpeg \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
COPY --from=builder /app/target/release/api .
|
|
||||||
|
|
||||||
|
|
||||||
# Create data directory for SQLite
|
|
||||||
RUN mkdir -p /app/data
|
RUN mkdir -p /app/data
|
||||||
|
|
||||||
ENV DATABASE_URL=sqlite:///app/data/template.db
|
|
||||||
ENV SESSION_SECRET=supersecretchangeinproduction
|
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
CMD ["./k-tv"]
|
||||||
|
|
||||||
CMD ["./api"]
|
# Worker image
|
||||||
|
FROM debian:bookworm-slim AS worker
|
||||||
|
WORKDIR /app
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends libssl3 ca-certificates ffmpeg && rm -rf /var/lib/apt/lists/*
|
||||||
|
COPY --from=builder /app/target/release/k-tv-worker .
|
||||||
|
RUN mkdir -p /app/data
|
||||||
|
CMD ["./k-tv-worker"]
|
||||||
|
|
||||||
|
# Playout image
|
||||||
|
FROM debian:bookworm-slim AS playout
|
||||||
|
WORKDIR /app
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends libssl3 ca-certificates ffmpeg && rm -rf /var/lib/apt/lists/*
|
||||||
|
COPY --from=builder /app/target/release/k-tv-playout .
|
||||||
|
RUN mkdir -p /app/data /tmp/k-tv-playout
|
||||||
|
EXPOSE 9090
|
||||||
|
CMD ["./k-tv-playout"]
|
||||||
|
|||||||
Reference in New Issue
Block a user