# syntax=docker/dockerfile:1 # # All-in-one PilotVault image: PocketBase + API Server + Web App in ONE container, # supervised by supervisord. Convenience/demo image — for production run the three # services separately (see Docker/docker-compose.yml). # # BUILD CONTEXT MUST BE THE REPO ROOT (this Dockerfile COPYs from "API Server/" # and "Web App/"). From E:\VS Code Projects\PilotVault run: # # docker build -f "Docker AIO/Dockerfile" -t pilotvault-aio . # docker run -p 8090:8090 -p 8080:8080 -p 8026:8026 \ # -v pilotvault_pb:/pb/pb_data pilotvault-aio # # Internal ports (loopback-wired): PocketBase 8026, API Server 8080, Web App 8090. # ============================================================================= # Stage 1 — build the API Server's embedded Vue panel (-> internal/api/dist) # ============================================================================= FROM node:22-alpine AS panel WORKDIR /panel COPY ["API Server/panel/package.json", "API Server/panel/package-lock.json", "./"] RUN npm ci COPY ["API Server/panel/", "./"] RUN npm run build # ============================================================================= # Stage 2 — build the API Server static binary (go.mod pins go 1.26) # ============================================================================= FROM golang:1.26-alpine AS api-build WORKDIR /src COPY ["API Server/go.mod", "API Server/go.sum", "./"] RUN go mod download COPY ["API Server/cmd/", "./cmd/"] COPY ["API Server/internal/", "./internal/"] # Overlay the freshly built panel so //go:embed all:dist picks it up. COPY --from=panel /internal/api/dist ./internal/api/dist RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" \ -o /out/api-server ./cmd/server # ============================================================================= # Stage 3 — build the Web App's embedded Vue UI (-> web/) # ============================================================================= FROM node:22-alpine AS ui WORKDIR /ui COPY ["Web App/ui/package.json", "Web App/ui/package-lock.json", "./"] RUN npm ci COPY ["Web App/ui/", "./"] RUN npm run build # ============================================================================= # Stage 4 — build the Web App static binary (go.mod pins go 1.24) # ============================================================================= FROM golang:1.24-alpine AS web-build WORKDIR /src COPY ["Web App/go.mod", "Web App/go.sum", "./"] RUN go mod download COPY ["Web App/main.go", "Web App/bff.go", "./"] # Overlay the freshly built UI so //go:embed web picks it up. COPY --from=ui /web ./web RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" \ -o /out/dji-web-app . # ============================================================================= # Stage 5 — fetch the PocketBase binary # ============================================================================= FROM alpine:latest AS pocketbase # Override with --build-arg PB_VERSION=x.y.z / PB_ARCH=arm64 as needed. ARG PB_VERSION=0.22.21 ARG PB_ARCH=amd64 RUN apk add --no-cache unzip wget ca-certificates \ && wget -O /tmp/pb.zip \ "https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_${PB_ARCH}.zip" \ && unzip /tmp/pb.zip -d /pb \ && rm /tmp/pb.zip # ============================================================================= # Stage 6 — runtime: alpine:latest running all three under supervisord # ============================================================================= FROM alpine:latest RUN apk add --no-cache ca-certificates tzdata supervisor WORKDIR /app COPY --from=api-build /out/api-server ./api-server COPY --from=web-build /out/dji-web-app ./dji-web-app COPY --from=pocketbase /pb/pocketbase ./pocketbase # JS migrations (schema + seed accounts) applied by PocketBase on first serve. COPY ["API Server/pocketbase/pb_migrations/", "/pb/pb_migrations/"] # --- Runtime configuration (loopback-wired between the three services) --------- # API Server reads API_ADDR / POCKETBASE_URL / CORS_ALLOW_ORIGINS / POCKETBASE_ADMIN_* # Web App reads ADDR / API_BASE # NOTE: these bundle default credentials for convenience — override at `docker run`. ENV API_ADDR=":8080" \ POCKETBASE_URL="http://127.0.0.1:8026" \ CORS_ALLOW_ORIGINS="*" \ POCKETBASE_ADMIN_EMAIL="admin@dji.local" \ POCKETBASE_ADMIN_PASSWORD="djiadmin2026!" \ ADDR=":8090" \ API_BASE="http://127.0.0.1:8080" # --- supervisord: PocketBase first, then API Server, then Web App -------------- RUN cat > /etc/supervisord.conf <<'EOF' [supervisord] nodaemon=true user=root logfile=/dev/null logfile_maxbytes=0 pidfile=/run/supervisord.pid [program:pocketbase] priority=10 directory=/pb # Ensure the service-account superuser exists, then serve on the internal port. command=/bin/sh -c "/app/pocketbase superuser upsert \"$POCKETBASE_ADMIN_EMAIL\" \"$POCKETBASE_ADMIN_PASSWORD\" --dir=/pb/pb_data ; exec /app/pocketbase serve --http=0.0.0.0:8026 --dir=/pb/pb_data --migrationsDir=/pb/pb_migrations" autorestart=true startsecs=3 stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 [program:api-server] priority=20 directory=/app command=/app/api-server autorestart=true startsecs=3 stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 [program:web-app] priority=30 directory=/app command=/app/dji-web-app autorestart=true startsecs=3 stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 EOF # PocketBase data (SQLite). Mount a volume here to persist across restarts. VOLUME ["/pb/pb_data"] EXPOSE 8090 8080 8026 ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]