Durch die Migration der Apps von Kubernetes weg zu "nativem" Docker unter TrueNAS Scale war ich gezwungen, meine Container umzuziehen.
Ich habe allerdings mehrere VLANs, in welchen die Container mit einer von mir definierten IP-Adresse erreichbar sein sollen, das typische Docker-Netzwerk mittels NAT und dann den Workload durchzureichen ist da etwas unschön.
Um einen Container unter TrueNAS Scale mit einem "externen" Netzwerk zu verbinden, machen wir uns den Netzwerktyp "macvlan" zu nutze und benötigen folgende Voraussetzungen auf dem System:
- Ein Netzwerkinterface, an welches wir das Netz binden möchten
- Ein eindeutiger IP-Adressbereich (IP-Adresse sowie Subnetzmaske und Gateway, IPv4 und/oder IPv6)
- Ein Docker-Image (hier exemplarisch Librespeed)
- Ein eingerichteter App-Service unter TrueNAS Scale
Leider bietet TrueNAS Scale selbst (noch) keine schöne Möglichkeit, Docker-Netzwerke in der GUI direkt anzulegen. Deshalb müssen wir unser gewünschtes Netzwerk in der Konsole anlegen. Hierzu mit root-Rechten folgenden Befehl ausführen:
docker network create -d macvlan --subnet=<Netzadresse IPv4>/<Prefix> --gateway=<Gateway IPv4> --ipv6 --subnet=<Netzadresse IPv6>/<Prefix IPv6> --gateway=<Gateway IPv6> -o parent=<Interface> <Name des Netzes>
Beispielweise würde ein Befehl so aussehen:
docker network create -d macvlan --subnet=10.25.0.0/16 --gateway=10.25.0.1 --ipv6 --subnet=fdf8:f53b:83e4::/64 --gateway=fdf8:f53b:83e4::53 -o parent=br0000 NET_MANAGEMENT
Somit ist das Netzwerk angelegt und kann nun in einer Docker Compose YAML referenziert werden.
Die Anlage des Netzwerks ist nur einmalig notwendig, der Docker-Dienst speichert das Netzwerk persistent, d.h. auch bei einem Neustart des Systems wird das Netzwerk automatisch wieder angelegt.
Nun können wir über "Apps" > "Discover Apps" > "..." > "Install via YAML" eine neue benutzerdefinierte Compose-Datei erstellen und der App einen Namen geben.
Ich verwende in diesem Beispiel Librespeed, da der Container relativ einfach zu beschreiben ist:
networks:
<Netzwerkname>:
external: True
services:
librespeed01:
container_name: librespeed01
environment:
- TZ=Europe/Berlin
- PUID=1000
- PGID=1000
- PASSWORD=PASSWORD
hostname: librespeed01
image: lscr.io/linuxserver/librespeed:latest
networks:
<Netzwerkname>:
ipv4_address: <IP-Adresse>
restart: unless-stopped
Hier ein funktionales Beispiel analog dem oben angelegten Netzwerk:
networks:
NET_MANAGEMENT:
external: True
services:
librespeed01:
container_name: librespeed01
environment:
- TZ=Europe/Berlin
- PUID=1000
- PGID=1000
- PASSWORD=PASSWORD
hostname: librespeed01
image: lscr.io/linuxserver/librespeed:latest
networks:
NET_MANAGEMENT:
ipv4_address: 10.25.1.4
restart: unless-stopped
Nachdem der Container gestartet ist, stehen alle Ports des Containers unter der definierten IP-Adresse zur Verfügung.
Achtung: Falls einzelne Ports nicht im Netzwerk verfügbar sein sollen, ist dies nun über eine Firewall zwischen verschiedenen Netzwerken bzw. VLANs zu lösen. Die Firewall kann entweder physisch oder auch virtualisiert auf dem Hostsystem betrieben werden.
Auch hier gilt:
- Workloads niemals direkt ohne einen Reverse Proxy über das Internet erreichbar machen
- Container immer mit einem eingeschränkten Benutzer ausführen, niemals root!
- Einem Container Ressourcen-Begrenzungen (CPU/RAM) einräumen, damit ein fehlerhafter Container nicht das ganze Host-System lahmlegen kann
- Persistente Daten in Volumes mittels Host Path ablegen