Normale Ansicht

Toolbx

26. Dezember 2025 um 09:28

Beim Experimentieren mit KI-Sprachmodellen bin ich über das Projekt »Toolbx« gestolpert. Damit können Sie unkompliziert gekapselte Software-Umgebungen erzeugen und ausführen.

Toolbx hat große Ähnlichkeiten mit Container-Tools und nutzt deren Infrastruktur, unter Fedora die von Podman. Es gibt aber einen grundlegenden Unterschied zwischen Docker/Podman auf der einen und Toolbx auf der anderen Seite: Docker, Podman & Co. versuchen die ausgeführten Container sicherheitstechnisch möglichst gut vom Host-System zu isolieren. Genau das macht Toolbx nicht! Im Gegenteil, per Toolbx ausgeführte Programme können auf das Heimatverzeichnis des aktiven Benutzers sowie auf das /dev-Verzeichnis zugreifen, Wayland nutzen, Netzwerkschnittstellen bedienen, im Journal protokollieren, die GPU nutzen usw.

Toolbx wurde ursprünglich als Werkzeug zur Software-Installation in Distributionen auf der Basis von OSTree konzipiert (Fedora CoreOS, Siverblue etc.). Dieser Artikel soll als eine Art Crash-Kurs dienen, wobei ich mit explizit auf Fedora als Host-Betriebssystem beziehe. Grundwissen zu Podman/Docker setze ich voraus.

Mehr Details gibt die Projektdokumentation. Beachten Sie, dass die offizielle Bezeichnung des Projekts »Toolbx« ohne »o« in »box« lautet, auch wenn das zentrale Kommando toolbox heißt und wenn die damit erzeugten Umgebungen üblicherweise Toolboxes genannt werden.

Hello, Toolbx!

Das Kommando toolbox aus dem gleichnamigen Paket wird ohne sudo ausgeführt. In der Minimalvariante erzeugen Sie mit toolbox <name> eine neue Toolbox, die als Basis ein Image Ihrer Host-Distribution verwendet. Wenn Sie also wie ich in diesen Beispielen unter Fedora arbeiten, fragt toolbox beim ersten Aufruf, ob es die Fedora-Toolbox herunterladen soll:

toolbox create test1

  Image required to create Toolbx container.
  Download registry.fedoraproject.org/fedora-toolbox:43 (356.7MB)? [y/N]: y
  Created container: test1

Wenn Sie als Basis eine andere Distribution verwenden möchten, geben Sie den Distributionsnamen und die Versionsnummer in zwei Optionen an:

toolbox create --distro rhel --release 9.7 rhel97

Das Kommando toolbox list gibt einen Überblick, welche Images Sie heruntergeladen haben und welche Toolboxes (in der Podman/Docker-Nomenklatur: welche Container) Sie erzeugt haben:

toolbox list

  IMAGE ID      IMAGE NAME                                    CREATED
  f06fdd638830  registry.access.redhat.com/ubi9/toolbox:9.7   3 days ago
  b1cc6a02cef9  registry.fedoraproject.org/fedora-toolbox:43  About an hour ago

  CONTAINER ID  CONTAINER NAME     CREATED         STATUS   IMAGE NAME
  695e17331b4a  llama-vulkan-radv  2 days ago      exited   docker.io/kyuz0/amd-strix-halo-toolboxes:vulkan-radv
  dc8fd94977a0  rhel97             22 seconds ago  created  registry.access.redhat.com/ubi9/toolbox:9.7
  dd7d51c65852  test1              18 minutes ago  created  registry.fedoraproject.org/fedora-toolbox:43

Um eine Toolbox aktiv zu nutzen, aktivieren Sie diese mit toolbox enter. Damit starten Sie im Terminal eine neue Session. Sie erkennen nur am veränderten Prompt, dass Sie sich nun in einer anderen Umgebung befinden. Sie haben weiterhin vollen Zugriff auf Ihr Heimatverzeichnis; die restlichen Verzeichnisse stammen aber überwiegend von Toolbox-Container. Hinter den Kulissen setzt sich der in der Toolbox sichtbare Verzeichnisbaum aus einer vollkommen unübersichtlichen Ansammlung von Dateisystem-Mounts zusammen. findmnt liefert eine über 350 Zeilen lange Auflistung!

toolbox enter test1

[kofler@toolbx ~]$ cat /etc/os-release 

  NAME="Fedora Linux"
  VERSION="43 (Toolbx Container Image)"
  RELEASE_TYPE=stable
  ID=fedora
  VERSION_ID=43
  ...

[kofler@toolbx ~]$ findmnt | wc -l

  359

Innerhalb einer Fedora-Toolbox können Sie wie üblich mit rpm und dnf Pakete verwalten. Standardmäßig ist nur ein relativ kleines Subset an Paketen installiert.

[kofler@toolbx ~]$ rpm -qa | wc -l

  340

Innerhalb der Toolbox können Sie mit sudo administrative Aufgaben erledigen, z.B. sudo dnf install <pname>. Dabei ist kein Passwort erforderlich.

ps ax listet alle Prozesse auf, sowohl die der Toolbox als auch alle anderen des Hostsystems!

Mit exit oder Strg+D verlassen Sie die Toolbox. Sie können Sie später mit toolbox enter <name> wieder reaktivieren. Alle zuvor durchgeführten Änderungen gelten weiterhin. (Hinter den Kulissen verwendet das Toolbx-Projekt einen Podman-Container und speichert Toolbox-lokalen Änderungen in einem Overlay-Dateisystem.)

Bei ersten Experimenten mit Toolbx ist mitunter schwer nachzuvollziehen, welche Dateien/Einstellungen Toolbox-lokal sind und welche vom Host übernommen werden. Beispielsweise ist /etc/passwd eine Toolbox-lokale Datei. Allerdings wurden beim Erzeugen dieser Datei die Einstellungen Ihres lokalen Accounts von der Host-weiten Datei /etc/passwd übernommen. Wenn Sie also auf Host-Ebene Fish als Shell verwenden, ist /bin/fish auch in der Toolbox-lokalen passwd-Datei enthalten. Das ist insofern problematisch, als im Standard-Image für Fedora und RHEL zwar die Bash enthalten ist, nicht aber die Fish. In diesem Fall erscheint beim Start der Toolbox eine Fehlermeldung, die Bash wird als Fallback verwendet:

toolbox enter test1

  bash: Zeile 1: /bin/fish: Datei oder Verzeichnis nicht gefunden
  Error: command /bin/fish not found in container test1
  Using /bin/bash instead.

Es spricht aber natürlich nichts dagegen, die Fish zu installieren:

[kofler@toolbx ~]$ sudo dnf install fish

Auf Host-Ebene liefern die Kommandos podman ps -a und podman images sowohl herkömmliche Podman-Container und -Images als auch Toolboxes. Aus Podman-Sicht gibt es keinen Unterschied. Der Unterschied zwischen einem Podman-Container und einer Toolbox ergibt sich erst durch die Ausführung (bei Podman mit sehr strenger Isolierung zwischen Container und Host, bei Toolbox hingegen ohne diese Isolierung).

Eigene Toolboxes erzeugen

Eigene Toolboxes richten Sie ein wie eigene Podman-Images. Die Ausgangsbasis ist ein Containerfile, das die gleiche Syntax wie ein Dockerfile hat:

# Datei my-directory/Containerfile
FROM registry.fedoraproject.org/fedora-toolbox:43

# Add metadata labels
ARG NAME=my-toolbox
ARG VERSION=43
LABEL com.github.containers.toolbox="true" \
      name="$NAME" \
      version="$VERSION" \
      usage="This image is meant to be used with the toolbox(1) command" \
      summary="Custom Fedora Toolbx with joe and fish"

# Install your software
RUN dnf --assumeyes install \
    fish \
    joe

# Clean up
RUN dnf clean all

Mit podman build erzeugen Sie das entsprechende lokale Image:

cd my-directory

podman build --squash --tag localhost/my-dev-toolbox:43 .

Jetzt können Sie auf dieser Basis eine eigene Toolbox einrichten:

toolbox create --image localhost/my-toolbox:43 test2

toolbox enter test2

KI-Sprachmodelle mit Toolbx ausführen

Das Toolbx-Projekt bietet eine großartige Basis, um GPU-Bibliotheken und KI-Programme auszuprobieren, ohne die erforderlichen Bibliotheken auf Systemebene zu installieren. Eine ganze Sammlung von KI-Toolboxes zum Test diverser Software-Umgebungen für llama.cpp finden Sie auf GitHub, beispielsweise hier:

https://github.com/kyuz0/amd-strix-halo-toolboxes

toolbox create erzeugt eine Toolbox mit dem Namen llama-vulkan-radv auf Basis des Images vulkan-radv, das der Entwickler kyuz0 im Docker Hub hinterlegt hat. Das alleinstehende Kürzel -- trennt die toolbox-Optionen von denen für Podman/Docker. Die folgenden drei Optionen sind erforderlich, um der Toolbox direkten Zugriff auf das Device der GPU zu geben.

toolbox create llama-vulkan-radv \
  --image docker.io/kyuz0/amd-strix-halo-toolboxes:vulkan-radv \
  -- --device /dev/dri \
     --group-add video \
     --security-opt seccomp=unconfined

Mit toolbox enter starten Sie die Toolbox. Innerhalb der Toolbox steht das Kommando llama-cli zur Verfügung. In einem ersten Schritt können Sie testen, ob diese Bibliothek zur Ausführung von Sprachmodellen eine GPU findet.

toolbox enter llama-vulkan-radv

llama-cli --list-devices

  ggml_vulkan: Found 1 Vulkan devices:
  ggml_vulkan: 0 = Radeon 8060S Graphics (RADV GFX1151) (radv) | 
    uma: 1 | fp16: 1 | bf16: 0 | warp size: 64 | 
    shared memory: 65536 | int dot: 1 | matrix cores: KHR_coopmat
  Available devices:
    Vulkan0: Radeon 8060S Graphics (RADV GFX1151) 
    (107008 MiB, 99195 MiB free)

Wenn Sie auf Ihrem Rechner noch keine Sprachmodelle heruntergeladen haben, finden Sie geeignete Modelle unter https://huggingface.co. Ich habe stattdessen im folgenden Kommando ein Sprachmodell ausgeführt, das ich zuvor in LM Studio heruntergeladen haben. Wie gesagt: In der Toolbox haben Sie vollen Zugriff auf alle Dateien in Ihrem Home-Verzeichnis!

llama-server \
  -m  /home/kofler/.lmstudio/models/lmstudio-community/gpt-oss-20b-GGUF/gpt-oss-20b-MXFP4.gguf \
  -c 32000 -ngl 999 -fa 1 --no-mmap

Dabei gibt -c die maximale Kontextgröße an. -ngl bestimmt die Anzahl der Layer, die von der GPU verarbeitet werden sollen (alle). -fa 1 aktiviert Flash Attention. Das ist eine Grundvoraussetzung für eine effiziente Ausführung moderner Modelle. --no-mmap bewirkt, dass das ganze Modell zuerst in den Arbeitsspeicher geladen wird. (Die Alternative wären ein Memory-Mapping der Datei.) Der Server kann auf der Adresse localhost:8080 über eine Weboberfläche bedient werden.

Weboberfläche zu llama.cpp. Dieses Programm wird in einer Toolbox ausgeführt.

Anstatt erste Experimente in der Weboberfläche durchzuführen, können Sie mit dem folgenden Kommando einen einfachen Benchmarktest ausführen. Die pp-Ergebnisse beziehen sich auf das Prompt Processing, also die Verarbeitung des Prompts zu Input Token. tg bezeichnet die Token Generation, also die Produktion der Antwort.

llama-bench \
  -m /home/kofler/.lmstudio/.../gpt-oss-20b-MXFP4.gguf \
  -ngl 999 -fa 1

  model                       size  params ...  test   t/s
  gpt-oss 20B MXFP4 MoE  11.27 GiB   20.91     pp512  1219
  gpt-oss 20B MXFP4 MoE  11.27 GiB   20.91     tg128    78

Quellen/Links

Dockers nft-Inkompatibilität wird zunehmend zum Ärgernis

10. November 2025 um 12:49

Ca. seit 2020 kommt nftables (Kommando nft) per Default als Firewall-Backend unter Linux zum Einsatz. Manche Distributionen machten den Schritt noch früher, andere folgten ein, zwei Jahre später. Aber mittlerweile verwenden praktisch alle Linux-Distributionen nftables.

Alte Firewall-Scripts mit iptables funktionieren dank einer Kompatibilitätsschicht zum Glück größtenteils weiterhin. Viele wichtige Firewall-Tools und -Anwendungen (von firewalld über fail2ban bis hin zu den libvirt-Bibliotheken) brauchen diese Komaptibilitätsschicht aber nicht mehr, sondern wurden auf nftables umgestellt.

Welches Programm ist säumig? Docker! Und das wird zunehmend zum Problem.

Update 11.11.2025: In naher Zukunft wird mit Engine Version 29.0 nftables als experimentelles Firewall-Backend ausgeliefert. (Aktuell gibt es den rc3, den ich aber nicht getestet habe. Meine lokalen Installationen verwenden die Engine-Version 28.5.1.) Ich habe den Artikel diesbezüglich erweitert/korrigiert. Sobald die Engine 29 ausgeliefert wird, werde ich das neue Backend ausprobieren und einen neuen Artikel verfassen.

Docker versus libvirt/virt-manager

Auf die bisher massivsten Schwierigkeiten bin ich unter Fedora >=42 und openSUSE >= 16 gestoßen: Wird zuerst Docker installiert und ausgeführt, funktioniert in virtuellen Maschinen, die mit libvirt/virt-manager gestartet werden, das NAT-Networking nicht mehr. Und es bedarf wirklich einiger Mühe, den Zusammenhang mit Docker zu erkennen. Die vorgebliche »Lösung« besteht darin, die libvirt-Firewall-Funktionen von nftables zurück auf iptables zu stellen. Eine echte Lösung wäre es, wenn Docker endlich nftables unterstützen würde.

# in der Datei /etc/libvirt/network.conf
firewall_backend = "iptables"

Danach starten Sie den libvirt-Dämon dann neu:

sudo systemctl restart libvirtd

Weitere Infos gibt es hier und hier. Die openSUSE-Release-Notes weisen ebenfalls auf das Problem hin.

Sicherheitsprobleme durch offene Ports

Weil Docker iptables verwendet, ist es mit nftables oder firewalld nicht möglich, Container mit offenen Ports nach außen hin zu blockieren. Wenn Sie also docker run -p 8080:80 machen oder in compose.yaml eine entsprechende Ports-Zeile einbauen, ist der Port 8080 nicht nur auf dem lokalen Rechner sichtbar, sondern für die ganze Welt! nftables- oder firewalld-Regeln können dagegen nichts tun!

Deswegen ist es wichtig, dass Docker-Container möglichst in internen Netzwerken miteinander kommunizieren bzw. dass offene Ports unbedingt auf localhost limitiert werden:

# Port 8080 ist nur für localhost zugänglich.
docker run -p localhost:8080:80 ...

Ihre Optionen in compose.yaml sehen so aus:

```bash
# compose.yaml
# Ziel: myservice soll mit anderem Container
# in compose.yaml über Port 8888 kommunizieren
services:
  myservice:
    image: xxx
    ports:
      # unsicher!
      # - "8888:8888"
      # besser (Port ist für localhost sichtbar)
      # - "127.0.0.1:8888:8888"
      # noch besser (Port ist nur Docker-intern offen)
      - "8888"
  otherservice:
    ...

Die sicherste Lösung besteht darin, die Container ausschließlich über ein Docker-internes Netzwerk miteinander zu verbinden (siehe backend_network im folgenden schablonenhaften Beispiel). Die Verbindung nach außen für die Ports 80 und 443 erfolgt über ein zweites Netzwerk (frontend_network). Die Angabe des drivers ist optional und verdeutlicht hier nur den Default-Netzwerktyp.

# compose.yaml
# am besten: die beiden Services myservice und
# nginx kommunizieren über das interne Netzwerk 
# miteinander
services:
  myservice:
    build: .
    ports:
      - "8888:8888"
    networks:
     - backend_network
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - /etc/mycerts/fullchain.pem:/etc/nginx/ssl/nginx.crt
      - /etc/mycerts/privkey.pem:/etc/nginx/ssl/nginx.key
    depends_on:
      - myservice
    networks:
      - frontend_network
      - backend_network
networks:
  # Verbindung zum Host über eine Bridge
  frontend_network:
    driver:   bridge
  # Docker-interne Kommunikation zwischen den Containern
  backend_network:
    driver:   bridge
    internal: true

Restriktive Empfehlungen

Docker hat es sich zuletzt sehr einfach gemacht. Auf https://docs.docker.com/engine/install/ubuntu/#firewall-limitations steht:

If you use ufw or firewalld to manage firewall settings, be aware that when you expose container ports using Docker, these ports bypass your firewall rules. For more information, refer to Docker and ufw.

Docker is only compatible with iptables-nft and iptables-legacy. Firewall rules created with nft are not supported on a system with Docker installed. Make sure that any firewall rulesets you use are created with iptables or ip6tables, and that you add them to the DOCKER-USER chain, see Packet filtering and firewalls.

Und https://docs.docker.com/engine/security/#docker-daemon-attack-surface gibt diese Zusammenfassung:

Finally, if you run Docker on a server, it is recommended to run exclusively Docker on the server, and move all other services within containers controlled by Docker. Of course, it is fine to keep your favorite admin tools (probably at least an SSH server), as well as existing monitoring/supervision processes, such as NRPE and collectd.

Salopp formuliert: Verwenden Sie für das Docker-Deployment ausschließlich für diesen Zweck dezidierte Server und/oder verwenden Sie bei Bedarf veraltete iptable-Firewalls. Vor fünf Jahren war dieser Standpunkt noch verständlich, aber heute geht das einfach gar nicht mehr. Die Praxis sieht ganz oft so aus, dass auf einem Server diverse »normale« Dienste laufen und zusätzlich ein, zwei Docker-Container Zusatzfunktionen zur Verfügung stellen. Sicherheitstechnisch wird dieser alltägliche Wunsch zum Alptraum.

Land in Sicht?

Bei Docker weiß man natürlich auch, dass iptables keine Zukunft hat. Laut diesem Issue sind 10 von 11 Punkte für die Umstellung von iptables auf nftables erledigt. Aber auch dann ist unklar, wie es weiter gehen soll: Natürlich ist das ein massiver Eingriff in grundlegende Docker-Funktionen. Die sollten vor einem Release ordentlich getestet werden. Einen (offiziellen) Zeitplan für den Umstieg auf nftables habe ich vergeblich gesucht.

Docker ist als Plattform-überschreitende Containerlösung für Software-Entwickler fast konkurrenzlos. Aber sobald man den Sichtwinkel auf Linux reduziert und sich womöglich auf Red-Hat-ähnliche Distributionen fokussiert, sieht die Lage anders aus: Podman ist vielleicht nicht hundertprozentig kompatibel, aber es ist mittlerweile ein sehr ausgereiftes Container-System, das mit Docker in vielerlei Hinsicht mithalten kann. Installationsprobleme entfallen, weil Podman per Default installiert ist. Firewall-Probleme entfallen auch. Und der root-less-Ansatz von Podman ist sicherheitstechnis sowieso ein großer Vorteil (auch wenn er oft zu Netzwerkeinschränkungen und Kompatibilitätsproblemen führt, vor allem bei compose-Setups).

Für mich persönlich war Docker immer die Referenz und Podman die nicht ganz perfekte Alternative. Aber die anhaltenden Firewall-Probleme lassen mich an diesem Standpunkt zweifeln. Die Firewall-Inkompatibilität ist definitiv ein gewichtiger Grund, der gegen den Einsatz der Docker Engine auf Server-Installationen spricht. Docker wäre gut beraten, iptables ENDLICH hinter sich zu lassen!

Update 11.11.2025: Als ich diesen Artikel im Oktober 2025 verfasst und im November veröffentlicht habe, ist mir entgangen, dass die Docker-Engine in der noch nicht ausgelieferten Version 29 tatsächlich bereits ein experimentelles nftables-Backend enthält!

Version 29 liegt aktuell als Release Candidate 3 vor. Ich warte mit meinen Tests, bis die Version tatsächlich ausgeliefert wird. Hier sind die Release Notes, hier die neue Dokumentationsseite. Vermutlich wird es ein, zwei weitere Releases brauchen, bis das nftables-Backend den Sprung von »experimentell« bis »stabil« schafft, aber immerhin ist jetzt ganz konkret ein Ende der Firewall-Misere in Sicht.

Quellen / Links

Das neue nftables-Backend für Docker

❌