The combined stack now includes PocketBase as a first-class service instead of assuming an external one: a Docker/pocketbase image built from the release binary that bundles the pb_migrations and upserts the superuser on boot, so a fresh stack checks/creates its collections and super-admin the same way DriverVault does. Add production compose variants (registry images) and .env(.prod).example files for both Docker/ and Docker AIO/, a top-level compose name, a PocketBase healthcheck with a service_healthy dependency, and env-driven ports. Move the containerized PocketBase to :8070 (the live remote PB stays 10.2.1.10:8026). Add a root .dockerignore to trim the repo-root build context used by the pocketbase and AIO images. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
151 lines
5.7 KiB
Docker
151 lines
5.7 KiB
Docker
# 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 8070:8070 \
|
|
# -v pilotvault_pb:/pb/pb_data pilotvault-aio
|
|
#
|
|
# Internal ports (loopback-wired): PocketBase 8070, 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:8070" \
|
|
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:8070 --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 8070
|
|
|
|
ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
|