70 lines
3.4 KiB
Docker
70 lines
3.4 KiB
Docker
# syntax=docker/dockerfile:1
|
|
|
|
# ── build ───────────────────────────────────────────────────────────────────
|
|
# templ output (*_templ.go) and the vendored htmx asset are committed, so a
|
|
# plain `go build` produces a self-contained binary — no codegen, no CDN.
|
|
FROM golang:1.26 AS build
|
|
|
|
WORKDIR /src
|
|
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
COPY . .
|
|
|
|
# CGO off + static linking so the binary runs in a distroless/scratch image with
|
|
# no libc. Trim symbols/DWARF to shrink the layer.
|
|
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags='-s -w' -o /out/tapir ./cmd/tapir
|
|
|
|
# ── ffmpeg ──────────────────────────────────────────────────────────────────
|
|
# Audio upload probes files with ffprobe and converts them with ffmpeg (ADR-033,
|
|
# #34 option A). Static builds, so they run in the distroless image below.
|
|
#
|
|
# Pinned by version AND sha256: a changed upstream file fails the build instead of
|
|
# shipping. The checksum proves these are the bytes that were reviewed (2026-10-02;
|
|
# the publisher's md5 matched too). It does NOT prove authenticity: the publisher
|
|
# signs nothing we can check. amd64 only (the cluster is one amd64 node).
|
|
#
|
|
# These builds are GPLv3 (--enable-gpl --enable-version3). The service is private and
|
|
# the image is not distributed; the licence text is copied into the image anyway.
|
|
#
|
|
# The release URL moves on when upstream releases a newer version, so the pinned
|
|
# version is tried in releases/ and then old-releases/. If neither has it the build
|
|
# fails; vendoring the verified tarball is the durable fix.
|
|
FROM golang:1.26 AS ffmpeg
|
|
|
|
ARG FFMPEG_VERSION=7.0.2
|
|
ARG FFMPEG_SHA256=abda8d77ce8309141f83ab8edf0596834087c52467f6badf376a6a2a4c87cf67
|
|
|
|
# xz is not in the golang image (found by building it: `tar: xz: Cannot exec`).
|
|
RUN set -eu; \
|
|
apt-get update; \
|
|
apt-get install -y --no-install-recommends xz-utils; \
|
|
rm -rf /var/lib/apt/lists/*; \
|
|
mkdir -p /out; \
|
|
for dir in releases old-releases; do \
|
|
curl -fsSL -o /out/ffmpeg.tar.xz "https://johnvansickle.com/ffmpeg/${dir}/ffmpeg-${FFMPEG_VERSION}-amd64-static.tar.xz" && break; \
|
|
done; \
|
|
echo "${FFMPEG_SHA256} /out/ffmpeg.tar.xz" | sha256sum -c -; \
|
|
tar -xJf /out/ffmpeg.tar.xz -C /out --strip-components=1 --wildcards '*/ffmpeg' '*/ffprobe' '*/GPLv3.txt'; \
|
|
rm /out/ffmpeg.tar.xz
|
|
|
|
# ── runtime ─────────────────────────────────────────────────────────────────
|
|
# distroless static + nonroot: no shell, no package manager, runs as uid 65532.
|
|
# ca-certificates are bundled, which the OIDC/HTTPS clients need.
|
|
FROM gcr.io/distroless/static-debian12:nonroot
|
|
|
|
COPY --from=build /out/tapir /tapir
|
|
COPY --from=ffmpeg /out/ffmpeg /out/ffprobe /usr/local/bin/
|
|
COPY --from=ffmpeg /out/GPLv3.txt /usr/share/doc/ffmpeg/GPLv3.txt
|
|
|
|
# Where the service finds them. Uploads stay OFF until TAPIR_UPLOADS_ENABLED is set
|
|
# (a deployment decision, not an image one).
|
|
ENV TAPIR_FFMPEG_BIN=/usr/local/bin/ffmpeg \
|
|
TAPIR_FFPROBE_BIN=/usr/local/bin/ffprobe
|
|
|
|
EXPOSE 8080
|
|
USER nonroot:nonroot
|
|
ENTRYPOINT ["/tapir"]
|
|
CMD ["serve"]
|