## Stage 1: Build frontend bundle FROM node:20.18-slim AS frontend WORKDIR /build COPY package.json package-lock.json* ./ RUN npm ci --ignore-scripts COPY esbuild.mjs tsconfig.json ./ COPY src/wled_controller/static/ ./src/wled_controller/static/ RUN npm run build ## Stage 2: Python application FROM python:3.11.11-slim AS runtime LABEL maintainer="Alexei Dolgolyov " LABEL org.opencontainers.image.title="LED Grab" LABEL org.opencontainers.image.description="Ambient lighting system that captures screen content and drives LED strips in real time" LABEL org.opencontainers.image.version="0.2.0" LABEL org.opencontainers.image.url="https://git.dolgolyov-family.by/alexei.dolgolyov/wled-screen-controller-mixed" LABEL org.opencontainers.image.source="https://git.dolgolyov-family.by/alexei.dolgolyov/wled-screen-controller-mixed" LABEL org.opencontainers.image.licenses="MIT" WORKDIR /app # Install system dependencies for screen capture and health check RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ libxcb1 \ libxcb-randr0 \ libxcb-shm0 \ libxcb-xfixes0 \ libxcb-shape0 \ && rm -rf /var/lib/apt/lists/* # Install Python dependencies first (layer caching optimization). # Copy pyproject.toml with a minimal package stub so pip can resolve deps. # The real source is copied afterward, keeping the dep layer cached. COPY pyproject.toml . RUN mkdir -p src/wled_controller && touch src/wled_controller/__init__.py \ && pip install --no-cache-dir ".[notifications]" \ && rm -rf src/wled_controller # Copy source code and config (invalidates cache only when source changes) COPY src/ ./src/ COPY config/ ./config/ # Copy built frontend bundle from stage 1 COPY --from=frontend /build/src/wled_controller/static/dist/ ./src/wled_controller/static/dist/ # Create non-root user for security RUN groupadd --gid 1000 ledgrab \ && useradd --uid 1000 --gid ledgrab --shell /bin/bash --create-home ledgrab \ && mkdir -p /app/data /app/logs \ && chown -R ledgrab:ledgrab /app USER ledgrab # Expose API port EXPOSE 8080 # Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ CMD curl -f http://localhost:8080/health || exit 1 # Set Python path ENV PYTHONPATH=/app/src # Run the application CMD ["uvicorn", "wled_controller.main:app", "--host", "0.0.0.0", "--port", "8080"]