# ── Stufe 1: Bauen ──────────────────────────────────────────────────────────── # Das offizielle Go-Image bringt Compiler und Werkzeuge mit. Es ist groß (~800 MB), # landet aber NICHT im fertigen Abbild — dafür sorgt der zweistufige Aufbau. FROM golang:1.26-alpine AS builder WORKDIR /app # Zuerst nur die Abhängigkeitsdateien kopieren und laden. # Docker legt jeden Schritt im Zwischenspeicher ab: Ändert sich nur der Code, # aber nicht go.mod/go.sum, müssen die Abhängigkeiten nicht erneut geladen werden. COPY go.mod go.sum ./ RUN go mod download COPY . . # CGO_ENABLED=0 → reines Go ohne C-Anteile, ergibt ein statisches Binary. # Möglich ist das nur, weil der SQLite-Treiber (modernc.org/sqlite) # selbst in Go geschrieben ist — die verbreitete Alternative # mattn/go-sqlite3 bindet C ein und würde das hier verhindern. # -trimpath → entfernt lokale Pfade aus dem Binary; sie stünden sonst in # Fehlerausgaben und verrieten Details der Baumaschine. # -ldflags="-s -w" → lässt Debug-Symbole weg, das Binary wird kleiner. RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o munin . # ── Stufe 2: Laufzeit ───────────────────────────────────────────────────────── # Alpine ist ein minimales Linux (~5 MB). Kein Compiler, keine Quelldateien. FROM alpine:3.21 WORKDIR /app # Nur das fertige Binary übernehmen. Templates und statische Dateien stecken # darin eingebettet (//go:embed in main.go), sie brauchen keinen eigenen Ordner. COPY --from=builder /app/munin . # wget wird für den Healthcheck weiter unten gebraucht; in Alpine steckt es in # busybox und ist bereits vorhanden. EXPOSE 8080 ENV DATA_DIR=/data ENV PORT=8080 # Im Container steht praktisch immer ein Reverse-Proxy mit HTTPS davor. ENV COOKIE_SECURE=true # ADMIN_TOKEN und SESSION_SECRET haben bewusst keinen Vorgabewert — ohne sie # startet der Server nicht. Ein erratbarer Standardwert wäre eine Hintertür. # Als gewöhnlicher Benutzer laufen statt als root: Bricht jemand über eine Lücke # aus der Anwendung aus, hat er sonst sofort volle Rechte im Container. # Der Datenordner gehört diesem Benutzer, damit die Datenbank beschreibbar bleibt. RUN adduser -D -u 10001 munin && mkdir -p /data && chown -R munin:munin /data /app USER munin # Die Datenbank gehört in ein Volume — sonst ist sie beim nächsten # "docker run" verschwunden. VOLUME ["/data"] HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD wget --quiet --tries=1 --spider http://127.0.0.1:8080/healthz || exit 1 CMD ["./munin"]