Files
Flaro/server/Dockerfile
T
ScarriffleandClaude Opus 5 bcbe5557d7 Der Kern des Vorspann-Abgleichs — ohne Anschluss, aber geprüft
Ein Vorspann ist das, was in jeder Folge einer Staffel gleich klingt.
Sonst ist an einer Folge nichts, woran er sich erkennen liesse: er sieht
aus wie Handlung und klingt wie Handlung, er wiederholt sich nur.

`Tonabgleich` sucht das längste Stück, das zwei Abdruckreihen teilen —
reine Rechnung, ohne Datei und ohne ffmpeg, deshalb mit sieben Prüfungen
belegt. Darunter die wichtigere Richtung: zwei Folgen ohne Gemeinsamkeit
ergeben nichts. Ein nicht gefundener Vorspann kostet einen Knopf, ein
erfundener schneidet dem Zuschauer eine halbe Minute Handlung weg.

Die Abdrücke holt `fpcalc` aus Chromaprint, nicht selbstgeschriebene
Signalverarbeitung. Dasselbe tut Jellyfins Intro Skipper, aus demselben
Grund. Das Programk liegt ab jetzt im Abbild; fehlt es, gibt es eben
keine Marken — sie sind eine Zugabe, kein Teil der Wiedergabe.

Noch ruft das niemand auf. Tabelle, Lauf und Knöpfe kommen als Nächstes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-12 20:56:37 +02:00

118 lines
5.0 KiB
Docker

# syntax=docker/dockerfile:1
# Die Oberfläche zuerst, in einem eigenen Abschnitt: sie braucht Node, der
# Server nicht. So landet Node nie im fertigen Image.
FROM --platform=$BUILDPLATFORM node:22-alpine AS web
WORKDIR /web
COPY web/app/package.json web/app/package-lock.json ./
RUN npm ci
COPY web/app/ ./
RUN npm run build
# Gebaut wird auf der Architektur des Bauwirts, übersetzt wird für die des
# Ziels — `dotnet publish -a` kann das. Ohne diese Trennung liefe der Bau für
# arm64 unter Emulation und dauerte ein Vielfaches.
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0 AS build
ARG TARGETARCH
WORKDIR /src
# Erst die Projektdateien, dann wiederherstellen: so bleibt die
# Paket-Wiederherstellung in der Ebenenzwischenablage, solange sich keine
# Abhängigkeit ändert. Ohne diesen Schritt lädt jeder Bau alles neu.
# `--parents` behält die Verzeichnisse bei. **Ein Muster statt einer Liste**,
# weil eine Liste bei jedem neuen Projekt vergessen wird — und dann scheitert
# erst der Bau im Container, nicht der auf dem Arbeitsrechner.
COPY --parents server/src/*/*.csproj ./
RUN dotnet restore server/src/Flaro.Api/Flaro.Api.csproj -a $TARGETARCH
COPY server/ ./server/
RUN dotnet publish server/src/Flaro.Api/Flaro.Api.csproj -a $TARGETARCH -c Release -o /app --no-restore
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
# ffmpeg und die Treiber für Hardware-Beschleunigung.
#
# **Als eigenes Programm, nicht als Bibliothek.** Flaro ruft es als Prozess
# auf; damit bleiben die Lizenzen getrennt (ffmpeg steht unter GPL) und ein
# Absturz dort nimmt den Server nicht mit.
#
# `mesa-va-drivers` bedient AMD und ältere Intel, `intel-media-va-driver` die
# neueren Intel — beide über VAAPI an `/dev/dri`. Welcher greift, entscheidet
# sich zur Laufzeit danach, was durchgereicht wurde.
#
# **Die Intel-Treiber nur auf amd64.** Es gibt sie für arm64 nicht, und ein
# unbedingtes `apt-get install` liess den Bau dort mit Code 100 abbrechen —
# eine Meldung, die nicht verrät, welches der sechs Pakete fehlt.
ARG TARGETARCH
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ffmpeg libva2 libva-drm2 mesa-va-drivers curl \
libchromaprint-tools \
&& if [ "$TARGETARCH" = "amd64" ]; then \
apt-get install -y --no-install-recommends intel-media-va-driver i965-va-driver; \
fi \
&& rm -rf /var/lib/apt/lists/*
# **Die Verzeichnisse müssen hier angelegt werden, nicht erst beim Start.**
# Docker legt den Einhängepunkt eines frischen benannten Volumes sonst als
# `root` an und übernimmt für ein leeres Volume die Rechte aus dem Image —
# gibt es das Verzeichnis im Image nicht, erbt es `root:root`, und der erste
# Start scheitert für jeden, der kein Bind Mount benutzt.
RUN mkdir -p /config /cache /transcode && chown -R 1000:1000 /config /cache /transcode
# **Kein root.** Die Kennung 1000 ist die des ersten Benutzers auf fast jedem
# Linux und auf den üblichen NAS-Geräten — wessen Dateien anders gehören, setzt
# in der Compose-Datei `user: "<uid>:<gid>"`. Das ist Docker-Bordmittel und
# braucht weder ein Startskript noch root im Container.
USER 1000:1000
# **Kein eigenes ASPNETCORE_URLS.** Das Basisimage setzt seit .NET 8 selbst
# ASPNETCORE_HTTP_PORTS=8080; beides zusammen ergab bei jedem Start die
# Warnung „Overriding HTTP_PORTS '8080'". Zwei Wege zum selben Port sind
# einer zu viel.
ENV FLARO_DATA=/config \
FLARO_CACHE=/cache \
FLARO_TRANSCODE=/transcode \
DOTNET_gcServer=0
# **Welches Abbild das hier ist.**
#
# Sechs Zeichen, bei jedem Bau neu gewürfelt — auch dann, wenn am Quelltext
# nichts anders ist. Die Version sagt, welcher Stand gemeint ist; diese
# Kennung sagt, welches Abbild wirklich läuft.
#
# Das ist keine Spielerei: zwei Funktionen standen nachweislich im Quelltext
# und waren auf dem Server trotzdem nicht zu sehen. Ob dort ein älteres
# Abbild lief, war nicht feststellbar, und die Fehlersuche lief einen halben
# Tag ins Leere. Seitdem beantwortet ein Blick die erste aller Fragen.
#
# Ganz unten, weil jede Änderung daran alle folgenden Schichten neu baut —
# und das sind hier nur noch die beiden COPY-Zeilen.
ARG FLARO_BUILD=DEV
ENV FLARO_BUILD=${FLARO_BUILD}
WORKDIR /app
COPY --from=build /app .
COPY --from=web /web/dist ./wwwroot
EXPOSE 8080
# **Eine Gesundheitsprüfung, die den Server fragt — nicht die Laufzeit.**
#
# Ohne sie weiss Docker nur, dass ein Prozess läuft. Die Oberfläche eines NAS
# zeigt dann minutenlang „wird bereitgestellt", während der Server längst
# antwortet, und niemand kann unterscheiden, ob er noch wandert oder hängt.
#
# `/health` und nicht `dotnet --info`: letzteres sagt nur, dass die Laufzeit
# da ist, und das war sie auch, als der Server noch migrierte.
#
# 60 Sekunden Anlaufzeit, weil die Migrationen beim ersten Start einer
# gefüllten Datenbank länger brauchen als ein Startvorgang sonst.
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
CMD curl -fsS http://localhost:8080/health || exit 1
VOLUME ["/config", "/cache", "/transcode"]
ENTRYPOINT ["dotnet", "Flaro.Api.dll"]