Installation
Bereitstellung als Container
Section titled “Bereitstellung als Container”Castmux wird als Container-Image ausgeliefert, und das ist die unterstützte Betriebsart. Das Image enthält das Go-Binary und beide Streaming-Engines sowie eine kleine Auswahl an Kommandozeilenwerkzeugen, die der Prozess aufruft.
sudo mkdir -p /opt/castmux/config
sudo docker run -d --name castmux --restart unless-stopped \ --network host \ --cap-add NET_RAW \ --cap-add NET_ADMIN \ -v /opt/castmux/config:/config \ -e CASTMUX_WEB_USERNAME=admin \ -e CASTMUX_WEB_PASSWORD=choose-something-better \ castmux/castmux:latestOder als Compose-Datei:
services: castmux: image: castmux/castmux:latest container_name: castmux restart: unless-stopped # Multicast must be emitted onto the real LAN, not a bridge. network_mode: host cap_add: - NET_RAW # libpcap capture: viewer detection, wire bitrate - NET_ADMIN # multicast route inspection and management volumes: # A host directory, not a named volume — see below. - /opt/castmux/config:/config environment: CASTMUX_WEB_USERNAME: admin CASTMUX_WEB_PASSWORD: choose-something-betterWarum Host-Networking
Section titled “Warum Host-Networking”Ein Docker-Bridge-Netzwerk ist ein anderes Layer-2-Segment als das, in dem die Fernseher hängen. Dorthin gesendeter Multicast wird innerhalb der Bridge zugestellt und nirgendwo sonst. Das Fehlerbild ist ungewöhnlich wenig hilfreich: Der Sendeaufruf gelingt, die Engine meldet, dass sie streamt, die Paketzähler steigen, und kein Fernseher empfängt jemals etwas. Es gibt keinen Fehler zu finden, weil keiner aufgetreten ist.
Host-Networking ist deshalb keine Bequemlichkeit, sondern eine funktionale Voraussetzung. Es bedeutet außerdem, dass die Weboberfläche direkt an Port 8080 des Hosts gebunden wird; ein Port-Mapping ist weder nötig noch möglich.
Warum NET_RAW
Section titled “Warum NET_RAW”Castmux schneidet Pakete mit libpcap im Promiscuous Mode mit. Das dient zwei Zwecken, die sich auf keinem anderen Weg erreichen lassen:
- Zuschauererkennung. IGMP-Membership-Reports anderer Hosts sind an Gruppen adressiert, denen dieser Rechner nicht beigetreten ist, und der Kernel verwirft Multicast nicht beigetretener Gruppen, bevor ein gewöhnlicher Socket ihn sehen kann. Mitschneiden im Promiscuous Mode ist der einzige Weg zu beobachten, welche Fernseher welcher Gruppe beigetreten sind.
- Bitrate auf der Leitung. Gezählt wird, was die Schnittstelle tatsächlich verlassen hat, statt dem zu glauben, was die Engine gesendet haben will. Das ist das einzige Lebenszeichen, das für beide Engines identisch funktioniert, und das einzige, das eine verwirrte Engine nicht vortäuschen kann.
Ohne NET_RAW hat On-Demand-Streaming keine Grundlage, und die Kacheln für die UDP-Bitrate bleiben leer. Ob die Sender dann dauerhaft oder gar nicht laufen, hängt von der Fail-open-Einstellung ab, die unter On-Demand-Streaming beschrieben ist.
Warum NET_ADMIN
Section titled “Warum NET_ADMIN”Verwaltung und Prüfung der Multicast-Route. Castmux prüft die Routing-Tabelle des Hosts von außerhalb des Streaming-Pfads, weil — wie der nächste Abschnitt erklärt — ein nicht routbares Ziel aus dem Inneren eines Prozesses, der dorthin sendet, völlig unsichtbar ist.
Konfigurationsverzeichnis
Section titled “Konfigurationsverzeichnis”Der gesamte Zustand liegt in einer Datei: /config/config.yaml im Container, also dort, wo Sie das Verzeichnis auf dem Host eingebunden haben.
Binden Sie ein Host-Verzeichnis ein, statt ein benanntes Volume zu verwenden. Das ist eine bewusste Empfehlung, kein Versehen. Am dringendsten brauchen Sie die Konfiguration genau dann, wenn die Weboberfläche nicht antwortet — und in diesem Moment ist ein benanntes Volume ein Verzeichnis tief im Speicherbereich der Container-Laufzeit, mit einem Namen, den sich niemand merken kann. Ein einfacher Pfad bedeutet, dass sich die Konfiguration mit einem Editor lesen, mit der von letzter Woche vergleichen, mit cp sichern und bei Bedarf für eine Änderungshistorie versionieren lässt.
Beim ersten Start wird die Datei mit Standardwerten angelegt. Danach gilt:
- Fehlende Schlüssel werden automatisch ergänzt, sodass eine von einer älteren Version geschriebene Konfiguration nach einem Upgrade weiter funktioniert und die neuen Schlüssel mit ihren Standardwerten erhält.
- Vor jeder Migration, die die Struktur der Datei ändert, wird daneben eine Kopie
.pre-migrationgeschrieben. Interpretiert ein Upgrade etwas anders als von Ihnen beabsichtigt, ist das Original noch vorhanden.
Die Datei von Hand zu bearbeiten wird unterstützt. Der Prozess liest sie beim Start ein; starten Sie den Container nach einer Bearbeitung außerhalb der Oberfläche also neu. Beachten Sie, dass Änderungen, die während Ihrer Bearbeitung in der Weboberfläche vorgenommen werden, von dem Schreibvorgang überschrieben werden, der zuletzt eintrifft.
Multicast-Routing
Section titled “Multicast-Routing”Das ist der Teil, bei dem Installationen danebengehen, und er verdient mehr Aufmerksamkeit als der Rest dieser Seite zusammen.
Über welche Schnittstelle ein Multicast-Paket hinausgeht, entscheidet der Kernel anhand der Routing-Tabelle. Das Binden der Quelladresse des UDP-Sockets wählt die ausgehende Schnittstelle nicht aus — eine verbreitete und nachvollziehbare Annahme, aber eine falsche. Entscheidend ist, wohin 224.0.0.0/4 zeigt.
Auf vielen Geräten zeigt die Route auf die Schnittstelle, die der Installateur zufällig zuerst konfiguriert hat — häufig eine, an der kein Kabel steckt. Die Streams werden dann korrekt erzeugt und gehen stillschweigend ins Leere.
Den Bereich korrigieren, nicht die Gruppe
Section titled “Den Bereich korrigieren, nicht die Gruppe”Routen Sie den gesamten Multicast-Bereich auf die Schnittstelle, die zu den Fernsehern zeigt:
# Point the entire multicast range at the TV-facing NICsudo ip route replace 224.0.0.0/4 dev eth1
# Verify — this must name the TV-facing interfaceip route get 239.10.0.1Routen überstehen keinen Neustart
Section titled “Routen überstehen keinen Neustart”Ein ip route-Befehl ist nicht dauerhaft. Installieren Sie stattdessen die mitgelieferte systemd-Unit und den zugehörigen Timer. Die Unit:
- wählt die erste verbundene Kandidaten-Schnittstelle, bevorzugt dabei die zu den Fernsehern zeigende Netzwerkkarte und weicht auf die Management-Netzwerkkarte aus, wenn die bevorzugte keinen Link hat;
- wird vom Timer jede Minute neu ausgewertet, sodass die Route dem Kabel folgt, wenn jemand es umsteckt, statt dass es erst nach einem Neustart bemerkt wird.
Eine tote Route ist von innen unsichtbar
Section titled “Eine tote Route ist von innen unsichtbar”sendto() an ein nicht routbares Multicast-Ziel meldet Erfolg. Keine Streaming-Engine kann diesen Zustand erkennen, denn aus ihrer Sicht ist nichts schiefgegangen. Daraus folgt:
- Der Fehler muss von außerhalb des Streaming-Pfads anhand der Routing-Tabelle geprüft werden — genau das tut Castmux, und deshalb braucht es NET_ADMIN;
- ein Neustart behebt ihn nie. Anwendung und Watchdog verweigern deshalb beide den Neustart eines Senders wegen eines Routing-Fehlers und lösen stattdessen einen Alarm aus. Eine Neustartschleife gegen eine defekte Route ist bloßer Leerlauf, der die eigentliche Ursache verdeckt.
Healthcheck und Watchdog
Section titled “Healthcheck und Watchdog”Das Image deklariert einen Container-Healthcheck. Seien Sie sich im Klaren, was er leistet und was nicht: Reines Docker protokolliert den Gesundheitsstatus und unternimmt nichts daraufhin. Ein Container kann unbegrenzt als „unhealthy“ markiert bleiben, während die Restart-Policy, die nur auf das Beenden des Prozesses reagiert, nichts tut. Orchestrierer handeln auf Basis des Status; docker run --restart tut es nicht.
Das Handeln übernimmt deshalb eine externe Watchdog-Unit. Sie wertet zwei unabhängige Signale aus:
| Signal | Bedeutung und Reaktion |
|---|---|
| Container-Status | Der Prozess als Ganzes antwortet nicht. Die Reaktion ist ein Neustart des Containers. |
| UDP-Stille eines einzelnen Senders | Ein Sender hat aufgehört, Pakete auf die Leitung zu legen, während die übrigen einwandfrei laufen. Die Reaktion ist ein Neustart nur dieses Senders. |
Zwei Signale statt einem, weil sie Fehler mit sehr unterschiedlicher Tragweite unterscheiden. Den ganzen Container neu zu starten, um einen hängenden Sender zu reparieren, nimmt für die Dauer des Neustarts und des anschließenden gestaffelten Starts jeden anderen Sender vom Netz — bei zwanzig Sendern rund eine Minute schwarzer Bildschirme, um ein Problem zu beheben, das einen betrifft.
Wegen eines Routing-Fehlers startet der Watchdog aus dem oben genannten Grund nichts neu: Ein Neustart kann keine Route reparieren, er erzeugt also eine Schleife statt einer Behebung.
Niemals zwei Instanzen betreiben
Section titled “Niemals zwei Instanzen betreiben”Zwei Situationen erzeugen eine zweite Instanz, ohne dass es jemand beabsichtigt:
- Eine übrig gebliebene systemd-Unit aus einer früheren Installation ohne Container. Das Deaktivieren einer Unit verhindert ihren Start beim Booten; es hindert nichts anderes daran, sie zu starten. Verwenden Sie
systemctl mask, damit sie sich überhaupt nicht mehr starten lässt. - Ein nächtlicher Neustart in der crontab von root. Prüfen Sie das, wenn Sie ein Gerät von einer Paketinstallation auf den Container umstellen. Ein Cron-Eintrag, der
systemctl restartauf die alte Unit ausführt, startet eine deaktivierte Unit um drei Uhr morgens anstandslos und beschert Ihnen ein Split Brain, das über Nacht auftaucht und verschwunden ist, bis jemand nachsieht. Noch einmal: maskieren, nicht nur deaktivieren.
Upgrade
Section titled “Upgrade”Laden Sie das neue Image und erstellen Sie den Container neu. Die Konfiguration wird automatisch vorwärts migriert, fehlende Schlüssel werden ergänzt, und vor jeder strukturellen Änderung wird eine Sicherung .pre-migration geschrieben.
sudo docker pull castmux/castmux:latestsudo docker stop castmux && sudo docker rm castmux# then re-run the same docker run command, or, in /opt/castmux:sudo docker compose up -dDie Sender sind für die Dauer des Neustarts und des anschließenden gestaffelten Starts nicht verfügbar — etwa drei Sekunden pro Sender. Planen Sie das Wartungsfenster bei einer großen Installation entsprechend.
Die Migration funktioniert nur vorwärts. Müssen Sie auf ein älteres Image zurück, stellen Sie zusätzlich die Kopie .pre-migration der Konfiguration wieder her; ein älteres Binary, das eine neuere Datei liest, versteht keine Schlüssel, die es bei seiner Erstellung noch nicht gab.
Sicherung
Section titled “Sicherung”Kopieren Sie das Konfigurationsverzeichnis. Das ist das gesamte Verfahren, und es ist mit Absicht so kurz:
sudo cp -a /opt/castmux/config /backup/castmux-$(date +%F)Das Verzeichnis enthält alles, was erhaltenswert ist: die Konfiguration, die Lizenzidentität des Geräts und den gespeicherten Programmführer. Kopieren Sie das Verzeichnis und nicht nur config.yaml, sonst meldet sich ein wiederhergestelltes Gerät als neues, nicht freigegebenes Gerät. Die Wiederherstellung ist derselbe Vorgang in umgekehrter Richtung bei gestopptem Container — siehe Sichern und Wiederherstellen. Sender-Logs sind nicht enthalten, weil sie ein Ringpuffer im Arbeitsspeicher sind und einen Neustart ohnehin nicht überdauern — siehe Die Weboberfläche → Logs.