# 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.27-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 real console bundle goes in *after* the source tree, so the COPY above
# (which carries only the .gitkeep placeholder from a fresh clone) cannot
# clobber it. `all:dist` in the embed directive needs the directory itself to
# exist, which the placeholder guarantees.
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

# The console is a separate binary in the same image: run it with
# `command: ["/usr/local/bin/fancy-dns-console"]`. It shares the embedded UI.
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-console ./cmd/fancy-dns-console

# ---- 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 /out/fancy-dns-console /usr/local/bin/fancy-dns-console
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"]
