check / check (push) Failing after 1s
The image had never been run. A trial run (fresh named volume, port 8080, real targets, no notification endpoints) showed it exited at once: Viper searches the working directory and, with a YAML config type, also matches an extension-less file named dnswatcher, so the binary at /app/dnswatcher was parsed as a config file. The binary now lives in /usr/local/bin and the working directory is the data dir. The runtime stage also gains an unprivileged dnswatcher user (uid 10001) that owns /var/lib/dnswatcher, so a fresh named volume inherits writable ownership, and a Docker HEALTHCHECK that probes /.well-known/healthcheck with busybox wget. README gains a "Deploying with upaas" section. Model: opus-4-8
72 lines
2.4 KiB
Docker
72 lines
2.4 KiB
Docker
# Lint stage - fast feedback on lint issues, before the build starts.
|
|
# The linter is invoked directly rather than through `make lint`: that
|
|
# target shells out to `docker build -f Dockerfile.lint`, and there is
|
|
# no docker daemon inside a docker build.
|
|
# golangci/golangci-lint:v2.12.2 (Debian-based), 2026-08-10
|
|
FROM golangci/golangci-lint:v2.12.2@sha256:5cceeef04e53efe1470638d4b4b4f5ceefd574955ab3941b2d9a68a8c9ad5240 AS lint
|
|
|
|
WORKDIR /src
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
COPY . .
|
|
|
|
RUN make fmt-check
|
|
RUN golangci-lint run --config .golangci.yml ./...
|
|
|
|
# Build stage
|
|
# golang 1.25-alpine, 2026-02-28
|
|
FROM golang@sha256:f6751d823c26342f9506c03797d2527668d095b0a15f1862cddb4d927a7a4ced AS builder
|
|
|
|
RUN apk add --no-cache git make gcc musl-dev binutils-gold
|
|
|
|
# Force BuildKit to run the lint stage before proceeding
|
|
COPY --from=lint /src/go.sum /dev/null
|
|
|
|
WORKDIR /src
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
COPY . .
|
|
|
|
# Run the tests - build fails if any test fails
|
|
RUN make test
|
|
|
|
# Build the binary
|
|
RUN make build
|
|
|
|
# Runtime stage
|
|
# alpine 3.21, 2026-02-28
|
|
FROM alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709
|
|
|
|
RUN apk add --no-cache ca-certificates tzdata
|
|
|
|
# The binary lives in /usr/local/bin, not the working directory: config
|
|
# loading searches the working directory, and with a YAML config type Viper
|
|
# also matches an extension-less file named "dnswatcher" there, so a binary
|
|
# named "dnswatcher" in that directory would be parsed as a config file.
|
|
COPY --from=builder /src/bin/dnswatcher /usr/local/bin/dnswatcher
|
|
|
|
# Run as an unprivileged user. The data directory is owned by that user so
|
|
# writes succeed both on a bind mount and when Docker seeds a fresh named
|
|
# volume from the image (a fresh volume inherits this directory's ownership).
|
|
RUN addgroup -S dnswatcher \
|
|
&& adduser -S -G dnswatcher -u 10001 dnswatcher \
|
|
&& mkdir -p /var/lib/dnswatcher \
|
|
&& chown dnswatcher:dnswatcher /var/lib/dnswatcher
|
|
|
|
ENV DNSWATCHER_DATA_DIR=/var/lib/dnswatcher
|
|
|
|
WORKDIR /var/lib/dnswatcher
|
|
|
|
USER dnswatcher
|
|
|
|
EXPOSE 8080
|
|
|
|
# busybox wget (already in alpine) probes the health endpoint. PORT defaults
|
|
# to 8080 and is honoured if the operator overrides it.
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
|
CMD wget -q -O /dev/null "http://127.0.0.1:${PORT:-8080}/.well-known/healthcheck" || exit 1
|
|
|
|
ENTRYPOINT ["/usr/local/bin/dnswatcher"]
|