# Multi-stage: build frontend → package with backend # ── Stage 1: Build React frontend ──────────────────────────────────────────── FROM node:22-slim AS frontend-build WORKDIR /app/frontend COPY frontend/package.json frontend/package-lock.json* ./ RUN npm ci --prefer-offline 2>/dev/null || npm install COPY frontend/ . RUN npm run build # ── Stage 2: Backend + static files ────────────────────────────────────────── FROM python:3.12-slim WORKDIR /app # System deps for SSH (to collect node metrics) + tailscale CLI RUN apt-get update && apt-get install -y --no-install-recommends \ openssh-client curl gnupg ca-certificates && \ rm -rf /var/lib/apt/lists/* && \ # Install kubectl curl -fsSL "https://dl.k8s.io/release/$(curl -fsSL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" -o /usr/local/bin/kubectl && \ chmod +x /usr/local/bin/kubectl && \ # Install tailscale CLI curl -fsSL https://pkgs.tailscale.com/stable/debian/bookworm.noarmor.gpg -o /usr/share/keyrings/tailscale-archive-keyring.gpg && \ curl -fsSL https://pkgs.tailscale.com/stable/debian/bookworm.tailscale-keyring.list -o /etc/apt/sources.list.d/tailscale.list && \ apt-get update && apt-get install -y --no-install-recommends tailscale && \ rm -rf /var/lib/apt/lists/* COPY backend/requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY backend/ . # Copy built frontend into static directory COPY --from=frontend-build /app/frontend/dist /app/static # SSH config for connecting to cluster nodes RUN mkdir -p /root/.ssh && \ echo "Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n IdentityFile /root/.ssh/id_ed25519" > /root/.ssh/config && \ chmod 600 /root/.ssh/config COPY backend/entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh EXPOSE 8787 ENTRYPOINT ["/entrypoint.sh"]