# syntax=docker/dockerfile:1.6 # # visionA-backend / api-server — multi-stage Docker image # # 設計原則(對齊 build-deploy.md §2 與 backend CLAUDE.md §9): # - Multi-stage:builder 階段負責編譯,runtime 階段只帶 binary(image 最小化) # - CGO_ENABLED=0:產出 static binary,可直接放進 alpine/distroless # - Non-root user:降低 container escape 風險 # - HEALTHCHECK:container 層級健康檢查(K8s / docker-compose 會用到) # # Build: # docker build -f docker/Dockerfile.api-server -t visiona/api-server:dev . # 執行目錄為 visionA-backend/,因此 COPY . . 會把整個 backend 帶進 builder。 # ---- Stage 1: builder ---------------------------------------------------- FROM golang:1.26-alpine AS builder # git 給 go mod download 用(部分 module path 會需要) RUN apk add --no-cache git ca-certificates WORKDIR /src # 先 COPY go.mod / go.sum,讓 dependency layer 可以被 cache(只有改依賴才重跑) COPY go.mod go.sum ./ RUN go mod download # 複製其餘原始碼 COPY . . # 編譯 api-server: # - CGO_ENABLED=0:pure Go static binary(alpine 可以直接跑) # - -ldflags="-s -w":strip debug info,縮小 binary 大小 # - -trimpath:去掉原始碼路徑,避免洩漏 builder 主機資訊 ENV CGO_ENABLED=0 GOOS=linux RUN go build -trimpath -ldflags="-s -w" -o /out/api-server ./cmd/api-server # ---- Stage 2: runtime ---------------------------------------------------- FROM alpine:3.19 # 安裝 curl 給 HEALTHCHECK 用 + ca-certificates 給未來 HTTPS out-bound 用 # (Phase 0 雛形沒 outbound HTTPS,但預裝不增加太多體積,避免日後踩雷) RUN apk add --no-cache ca-certificates curl tzdata && \ addgroup -S -g 1001 visiona && \ adduser -S -u 1001 -G visiona visiona WORKDIR /app # 建立 storage 目錄(讓 LocalFS backend 預設路徑可寫) RUN mkdir -p /app/data/storage && chown -R visiona:visiona /app # 複製 binary COPY --from=builder --chown=visiona:visiona /out/api-server /app/api-server # 切到非 root USER visiona:visiona # api-server 預設 listen 3721(對齊 local-tool,見 config/config.go ServerConfig.Port) EXPOSE 3721 # 預設環境變數:容器內的儲存路徑。 # 實際部署時由 docker-compose 或 K8s ConfigMap / Secret 覆蓋。 ENV VISIONA_HOST=0.0.0.0 \ VISIONA_API_PORT=3721 \ VISIONA_STORAGE_LOCALFS_ROOT=/app/data/storage \ VISIONA_LOG_LEVEL=info # Container 層級 healthcheck — docker / compose 會用。 # 30s 週期、3s timeout、連續 3 次失敗視為 unhealthy。 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -fsS http://localhost:3721/healthz || exit 1 ENTRYPOINT ["/app/api-server"]