Docker und IPv6 – es wird endlich besser

Ich habe ja schon einige Berichte und auch einige GitHub-Kommentare zum Thema Docker und IPv6 verfasst. Die meisten davon waren durch die Enttäuschung geprägt, dass eine eigentlich sehr moderne Virtualisierungslösung seit mehr als zehn Jahren in Sachen moderner Netzwerk-Protokolle und Verwaltung nur sehr langsam zu Potte kam. Die Unterstützung von IPv6 war lange Zeit rudimentär bis stiefmütterlich.

Zur kurzen Einordnung: Per default setzt Docker (noch immer) auf das IPv4-Protokoll, dessen Grenzen hinsichtlich der weltweit verfügbaren Adressen mittlerweile erreicht bzw. sogar überschritten sind. Angesichts der Tatsache, dass Docker im Jahr 2013 gegründet wurde und um 2015 herum langsam an Popularität gewonnen hat, war es doch sehr verwunderlich, dass von Haus aus erst einmal nur das alte IPv4 unterstützt wurde. Immerhin automatisierte Docker an dieser Stelle bereits einiges an Firewall und Forwarding-Regeln. Aber auch automatisierte Workarounds sind und bleiben Workarounds: In die Presche hinein gesprungen sind dann unter anderem Reverse Proxies wie z.B. Traefik, um das Problem zu lösen dass man einen Port (für HTTP 80, für HTTPS 443) pro IP-Adresse immer nur einmal verwenden kann. HTTP an dieser Stelle schon seit Jahrzehnten Virtual Hosts, eingesetzt habe ich das bereits zu Schulzeiten für den Schulserver (damals noch ein Apache 2.2.x) – mit SNI kam für HTTPS dann auch ca. 2009 verbreitet auf, mittlerweile ist es erprobt und stabil.

Aber wie gesagt, all die Workarounds sind mit IPv6 nicht mehr notwendig, das neue Protokoll bietet IP-Adressen in einer Fülle die wohl wahrlich bis ins nächste Jahrhundert ausreichen sollte – bis dahin hat man dann hoffentlich aus der schleppenden Umstellung gelernt und es wird mit IPv7 (oder dann doch gleich IPv8) dann einfacher mit der Umstellung. Selbst in der Standard-Ausführung bekommt man in der Regel 64 Bit Adressraum zur freien Verfügung, ggf. auch noch etwas mehr.

Einzig: Die Unterstützung von Docker-Seite war eben nicht gerade rosig – man musste sich um viele Dinge wie das Routing und die Firewallregeln noch selbst kümmern wenn man es einsetzen wollte. Ich habe das lange Zeit tatsächlich auch so gehandhabt für viele meiner Services – einfach weil ich den Nutzen von IPv6 nicht verstreichen lassen wollte und es dann doch ganz gut ging, etwas Routine vorausgesetzt.

Weiterlesen: Docker und IPv6 – es wird endlich besser

Um so erfreulicher ist die Entwicklung die sich seit Jahresbeginn ergeben hat: Mit Docker in der Version 28 sind IPv6 only Netzwerke möglich und ich muss sagen: es macht die Nutzung nochmal erheblich angenehmer. Die ersten Meldungen dazu datieren auf Februar, seitdem habe ich das Ganze beobachtet und auch immer wieder einmal auf Stabilität abgeklopft. Diesen Artikel hier wollte ich denn auch schon länger geschrieben und veröffentlicht haben, aber es gab regelmäßig andere Prioritäten.

Wenn man die manuelle Nutzung und Einrichtung von IPv6 Netzwerken in Docker in alter Form gewohnt ist, so hat die aktuelle Implementierung durchaus einige Vorteile, wenn auch ggf. unerwartete Nebenwirkungen. Im Folgenden gehe ich auf ein paar Punkte ein und gebe auch einige Tipps und Beispiele.

Das für mich allerwichtigste zuerst: Es ist mittlerweile möglich IPv4 für benutzerdefinierte Netzwerke zu deaktivieren – für die Default-Docker-Bridge geht das noch nicht, aber das ist in der Regel kein Problem. Wer in größeren Firmen oder auch öffentlichen Netzwerken (z.B. im WLAN der deutschen Bahn im Zug) arbeitet kennt ggf. noch die negative Auswirkung: Dort sind bereits alle privaten Netzwerk-Ranges in Verwendung – das zusätzliche lokale Docker-Netzwerk mit IPv4 kann da durchaus Chaos im Routing erzeugen. Abhilfe war dann meist, restriktierte IP-Ranges zu verwenden die eigentlich nur für Tests gedacht waren (häufig verwendet: 198.18.0.0/15 – eigentlich nur für Benchmarking vorgesehen). Jetzt wo man IPv4 abschalten kann und auf Unique Local Addresses (ULA) von IPv6 setzen kann, die man sich lokal zufällig erzeugt, ist dieses Problem nicht mehr so gravierend.

Etwas ungewohnt ist die „Einmischung“ von Docker in die IPv6-Welt auf der Maschine dann aber schon, denn wie unter IPv4 auch kümmert sich Docker mittlerweile auch vorbildlich um die Abschirmung der Prozesse bzw. Container. Setzt man mittlerweile auf IPv6 so muss man die freigegeben Ports auch explizit deklarieren – bisher kümmerte sich Docker nur um die Adress-Zuteilung gemäß einiger simpler Regeln. Daher nicht wundern, wenn man ggf. nach einem Upgrade den vorher erreichbaren Service nicht mehr erreicht: Dann hat man schlichtweg vergessen die freizugebenden / exponierenden Ports entsprechend zu deklarieren. Ein erster Workaround ist es dann die Freigaben in die Docker-User-Chain von ip6tables einzutragen, allerdings ist das definitiv nur als erste Maßnahme zu sehen, die korrekt Variante ist es natürlich die Ports die man exponieren möchte auch entsprechend zu deklarieren.

Für alles was über einzelne Container hinaus geht, empfiehlt sich die Nutzung von Docker Compose als Orchestrations-Werkzeug. Das gilt vor allem wenn man sich für kleinere Projekte nicht mit der Komplexität und dem Aufwand von Kubernetes herum schlagen möchte. Docker Compose hat eine etwas bewegte Geschichte mit einigen Irrungen und Wirrungen hinter sich. War es anfänglich ein getrenntes Tool so ist es mittlerweile in Docker gut integriert und auch die Syntax hat sich stabilisiert. Etwas verwirrend waren auch die unterschiedlichen YAML-Definitionen und Versionen die es einmal gab. Mittlerweile lautet die Empfehlung ganz klar: Versionsangaben am Besten weglassen.

Die Netzwerk-Sektion eines docker compose sieht dann wie folgt aus:

networks:
  mynetwork:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.gateway_mode_ipv6: "routed"
    enable_ipv6: true
    enable_ipv4: false
    name: my-example-project-network
    ipam:
      driver: default
      config:
        - subnet: 2001:0DB8::/32  

Das Beispiel ist recht gut verständlich, wichtig sind die Einstellungen für die bridge: der gateway_mode_ipv6 muss auf routed gestellt werden, ansonsten macht Docker wieder lustige Dinge wie Network-Address-Translation, was man ja gerade mit IPv6 loswerden möchte. Die Einstellungen enable_ipv4 und enable_ipv6 sind selbsterklärend. Ich selbst bevorzuge es zumindest aktuell den Netzwerken dezidierte IPv6-Subnetze zuzuweisen, denn in der Regel trage ich diese auch entsprechend im DNS ein. Wenn ich noch etwas Zeit finde mache ich mir da ggf. auch nochmal Gedanken, ob man die Namen nicht auch im Docker Compose file hinterlegt und die Namen dann auch automatisch im DNS registriert werden. Ggf. kann man die Einstellungen zur Wiederverwendung auch in Variablen und .env Dateien auslagern.

Die Konfiguration eines einzelnen Containers in Docker Compose sieht dann wie folgt aus:

services:
  some-service:
    image: httpd
    restart: always
    ports:
      - 80
      - 443
    networks:
      mynetwork:
        ipv6_address: 2001:0DB8::2

Auch das ist eigentlich recht einfach gehalten. Wichtig an dieser Stelle ist die Notation in der Port-Sektion, mit diesen richtet Docker automatisch die Freigabe für die Ports in der Firewall für das eigentlich abgeschottete eigene Netzwerk ein. Natürlich darf man nicht vergessen, dass man ggf. auch auf der Eingangsseite des Hosts (also dem externen Netzwerk-Interface) ggf. Firewall-Regeln gibt – diese fasst Docker korrekterweise nicht an.

Insgesamt sieht man sehr schön: IPv6 ist nicht mehr ganz so exotisch und auch Docker bekommt endlich den passenden Support für reine IPv6 basierte Services. Ein sehr schöner, aber eben auch überfälliger Schritt. Für nächste Weihnachten wünsche ich mir jetzt noch, dass per Default IPv4 mit seinen NAT-Krücken in Docker manuell aktiviert werden muss anstelle es dediziert abzuschalten. Vielleicht hat der Weihnachtsmann ja ein Einsehen. Wenn nicht, ist das auch nicht schlimm: Die Situation ist ja schon deutlich erträglicher geworden.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden.