# syntax=docker/dockerfile:1 # # pansy ships as one static binary with the web build embedded. This is a # three-stage build: compile the frontend, embed it into the Go binary, then # copy that single binary into a minimal runtime image. # ---- stage 1: build the web bundle ------------------------------------------ FROM node:22-alpine AS web WORKDIR /web COPY web/package.json web/package-lock.json ./ RUN --mount=type=cache,target=/root/.npm npm ci COPY web/ ./ RUN npm run build # ---- stage 2: build the static Go binary (web bundle embedded) -------------- FROM golang:1.26-alpine AS build # GOWORK=off matches the Makefile: pansy is a standalone module, built without # any parent workspace even if one leaks into the build context. ENV CGO_ENABLED=0 GOTOOLCHAIN=auto GOWORK=off WORKDIR /src COPY go.mod go.sum ./ RUN --mount=type=cache,target=/go/pkg/mod go mod download COPY . . # Overlay the freshly built frontend into the embed directory before compiling # (//go:embed all:dist in internal/webdist). COPY --from=web /web/dist ./internal/webdist/dist RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ go build -trimpath -ldflags "-s -w" -o /out/pansy ./cmd/pansy # ---- stage 3: minimal runtime ----------------------------------------------- FROM alpine:3.20 ARG BUILD_COMMIT=unknown ARG BUILD_BRANCH=unknown ARG BUILD_TIME=unknown LABEL org.opencontainers.image.title="pansy" \ org.opencontainers.image.description="Self-hostable garden planner" \ org.opencontainers.image.source="https://gitea.stevedudenhoeffer.com/steve/pansy" \ org.opencontainers.image.revision="${BUILD_COMMIT}" \ org.opencontainers.image.version="${BUILD_BRANCH}" \ org.opencontainers.image.created="${BUILD_TIME}" # ca-certificates: outbound TLS (e.g. OIDC discovery). tzdata: correct local time. RUN apk add --no-cache ca-certificates tzdata \ && adduser -D -u 10001 pansy \ && mkdir -p /data \ && chown pansy:pansy /data COPY --from=build /out/pansy /usr/local/bin/pansy USER pansy # The SQLite database lives on the /data volume so it survives container updates. ENV PANSY_PORT=8080 \ PANSY_DB=/data/pansy.db WORKDIR /data VOLUME /data EXPOSE 8080 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD wget -q -O - "http://127.0.0.1:${PANSY_PORT}/api/v1/healthz" || exit 1 ENTRYPOINT ["/usr/local/bin/pansy"]