80 lines
2.6 KiB
Docker
80 lines
2.6 KiB
Docker
# syntax=docker/dockerfile:1.7
|
|
#
|
|
# Two stages: build the console, then build a static Go binary with it
|
|
# embedded. The result is a single file with no runtime dependencies beyond
|
|
# libc, which is what makes a scratch/distroless base safe.
|
|
|
|
ARG NODE_IMAGE=node:22-alpine
|
|
ARG GO_IMAGE=golang:1.23-alpine
|
|
ARG RUNTIME_IMAGE=gcr.io/distroless/static-debian12:nonroot
|
|
|
|
# ---- stage 1: the admin console -------------------------------------------
|
|
FROM ${NODE_IMAGE} AS web
|
|
|
|
WORKDIR /src/web
|
|
|
|
# Dependencies first: this layer is only rebuilt when package-lock.json moves,
|
|
# not on every source edit.
|
|
COPY web/package.json web/package-lock.json* ./
|
|
RUN npm ci --no-audit --no-fund
|
|
|
|
COPY web/ ./
|
|
|
|
# vite.config.ts writes to ../internal/web/dist, which is where the Go embed
|
|
# directive looks.
|
|
RUN mkdir -p /src/internal/web && npm run build \
|
|
&& test -f /src/internal/web/dist/index.html
|
|
|
|
# ---- stage 2: the binary ---------------------------------------------------
|
|
FROM ${GO_IMAGE} AS build
|
|
|
|
ARG VERSION=dev
|
|
ARG TARGETOS=linux
|
|
ARG TARGETARCH=amd64
|
|
|
|
WORKDIR /src
|
|
|
|
# The placeholder dist directory keeps the embed directive valid even if the
|
|
# console stage was skipped.
|
|
COPY internal/web/dist/ internal/web/dist/
|
|
COPY --from=web /src/internal/web/dist/ internal/web/dist/
|
|
|
|
# Module cache first, for the same reason.
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
COPY . .
|
|
|
|
# CGO off: the resolver, bbolt and the TLS stack are all pure Go, and a static
|
|
# binary is what lets the runtime stage be distroless-static.
|
|
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
|
|
go build -trimpath \
|
|
-ldflags "-s -w -X git.k8s-git-k6n.net/mats/fancy-dns/internal/app.Version=${VERSION}" \
|
|
-o /out/fancy-dns ./cmd/fancy-dns
|
|
|
|
# ---- stage 3: runtime ------------------------------------------------------
|
|
FROM ${RUNTIME_IMAGE}
|
|
|
|
# 53 is the DNS service itself, 853 is DoT, 443 is DoH, 8080 is the console.
|
|
EXPOSE 53/udp 53/tcp
|
|
EXPOSE 853/tcp
|
|
EXPOSE 443/tcp
|
|
EXPOSE 8080/tcp
|
|
|
|
# The bbolt files and downloaded lists live here; mount a volume over it.
|
|
VOLUME ["/var/lib/fancy-dns"]
|
|
|
|
COPY --from=build /out/fancy-dns /usr/local/bin/fancy-dns
|
|
COPY --from=build /src/deploy/config.example.yaml /etc/fancy-dns/config.example.yaml
|
|
COPY --from=build /src/deploy/zones/ /etc/fancy-dns/zones/
|
|
|
|
USER nonroot:nonroot
|
|
|
|
# The liveness probe, not the readiness one: it answers 200 while the process
|
|
# is up, which is what a crash-loop detector wants.
|
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
|
CMD ["/usr/local/bin/fancy-dns", "-version"]
|
|
|
|
ENTRYPOINT ["/usr/local/bin/fancy-dns"]
|
|
CMD ["-config", "/etc/fancy-dns/config.yaml"]
|