ping6.net

IPv6 in Docker und Kubernetes: Leitfaden für Container-Netzwerke

IPv6 für containerisierte Anwendungen konfigurieren. Behandelt Docker-Daemon-Einstellungen, Kubernetes Dual-Stack, CNI-Plugins und Service-Exposition.

ping6.net14. Dezember 20249 min read
IPv6DockerKubernetesContainerNetzwerkDevOps

Container-Netzwerke verwenden standardmäßig IPv4. Das ist ein Problem, wenn Sie produktive Workloads im Jahr 2024 betreiben.

TL;DR - Kurzübersicht

Wichtige Punkte:

  • Docker und Kubernetes verwenden standardmäßig nur IPv4; IPv6 erfordert explizite Konfiguration
  • Docker benötigt daemon.json-Änderungen und benutzerdefinierte Netzwerke mit --ipv6-Flag
  • Kubernetes 1.23+ unterstützt stabilen Dual-Stack mit Pod- und Service-IPv6
  • CNI-Plugins (Calico, Cilium, Flannel) handhaben Dual-Stack unterschiedlich

Direkt zu: Docker-Konfiguration | Kubernetes Dual-Stack | CNI-Plugins | Testen

Warum IPv6 in Containern#

Ihre Container könnten IPv4-only sein, während der Rest des Internets zu IPv6 wechselt. Mobilfunknetze, ISPs und Cloud-Provider sind IPv6-first. Wenn Ihre containerisierten Dienste IPv6 nicht unterstützen, fügen Sie Latenz durch NAT64-Gateways hinzu oder schlimmer – verpassen Kunden vollständig.

Container-Orchestrierungsplattformen (Docker, Kubernetes, ECS, Nomad) wurden während der IPv4-Ära entwickelt. IPv6-Unterstützung kam später als nachträglicher Einfall. Die Standardeinstellungen gehen weiterhin von IPv4-only-Netzwerken aus.

IPv6 zu aktivieren ist nicht schwer, erfordert aber explizite Konfiguration auf mehreren Ebenen: Daemon, Netzwerk, Container und Service. Verpassen Sie eine Ebene und Sie haben partielle Konnektivität, die mysteriös bricht.

Docker IPv6-Konfiguration#

Der Docker-Daemon aktiviert IPv6 nicht standardmäßig. Sie müssen es in /etc/docker/daemon.json konfigurieren.

Daemon-Konfiguration#

/etc/docker/daemon.json erstellen oder ändern:

{
  "ipv6": true,
  "fixed-cidr-v6": "fd00::/80",
  "experimental": false,
  "ip6tables": true
}

Aufschlüsselung:

  • "ipv6": true aktiviert IPv6-Unterstützung
  • "fixed-cidr-v6" setzt das Subnetz für Container (ULA- oder GUA-Präfix verwenden)
  • "ip6tables": true aktiviert IPv6-Firewall-Regeln (Docker 20.10+)

Für Produktion mit global routbaren Adressen verwenden Sie das zugewiesene Präfix Ihres Providers:

{
  "ipv6": true,
  "fixed-cidr-v6": "2001:db8:1234::/64"
}

Docker neu starten, um Änderungen anzuwenden:

sudo systemctl restart docker

IPv6 ist aktiviert überprüfen:

docker network inspect bridge | grep IPv6

Sie sollten "EnableIPv6": true sehen.

Standard-Bridge-Netzwerk#

Das Standard-Bridge-Netzwerk erhält nicht automatisch IPv6, selbst nach Daemon-Konfiguration. Erstellen Sie ein benutzerdefiniertes Netzwerk:

docker network create --ipv6 \
  --subnet=172.20.0.0/16 \
  --subnet=fd00:dead:beef::/48 \
  mynetwork

Container auf diesem Netzwerk ausführen:

docker run -d --network mynetwork nginx

Container erhalten jetzt sowohl IPv4- als auch IPv6-Adressen.

Benutzerdefinierte Netzwerke#

Benutzerdefinierte Bridge-Netzwerke unterstützen Dual-Stack:

docker network create --ipv6 \
  --subnet=10.1.0.0/24 \
  --gateway=10.1.0.1 \
  --subnet=fd00:cafe::/64 \
  --gateway=fd00:cafe::1 \
  appnetwork

Container in diesem Netzwerk können über IPv6 kommunizieren:

# Terminal 1
docker run -it --rm --network appnetwork --name container1 alpine sh
 
# Terminal 2
docker run -it --rm --network appnetwork alpine sh
ping6 container1

Dockers eingebetteter DNS-Resolver gibt AAAA-Records für Container-Namen zurück, wenn IPv6 aktiviert ist.

IPv6-NAT und Routing#

Standardmäßig verwendet Docker NAT für IPv4, kann aber IPv6 nicht NATen. Dies hängt von Ihrer fixed-cidr-v6-Konfiguration ab.

Mit ULA-Präfixen (fd00::/8) benötigen Sie NAT für Internetzugang:

# IPv6-Forwarding aktivieren
sudo sysctl -w net.ipv6.conf.all.forwarding=1
 
# Masquerade-Regel hinzufügen
sudo ip6tables -t nat -A POSTROUTING -s fd00::/80 ! -o docker0 -j MASQUERADE

Mit GUA-Präfixen (global routbar) direkt routen ohne NAT:

# Route für Container-Subnetz hinzufügen
sudo ip -6 route add 2001:db8:1234::/64 via <docker-host-ipv6>

Upstream-Router konfigurieren, um Ihr Container-Subnetz zum Docker-Host zu routen.

Docker Compose IPv6#

Docker Compose erfordert explizite IPv6-Konfiguration in der Netzwerkdefinition.

Beispiel docker-compose.yml:

version: '3.8'
 
services:
  web:
    image: nginx
    networks:
      - frontend
    ports:
      - "80:80"
      - "[::]:8080:80"  # IPv6 explizit binden
 
  app:
    image: myapp:latest
    networks:
      - frontend
      - backend
 
  db:
    image: postgres:14
    networks:
      - backend
    environment:
      POSTGRES_HOST_AUTH_METHOD: trust
 
networks:
  frontend:
    enable_ipv6: true
    ipam:
      config:
        - subnet: 172.20.0.0/16
          gateway: 172.20.0.1
        - subnet: fd00:1::/64
          gateway: fd00:1::1
 
  backend:
    enable_ipv6: true
    ipam:
      config:
        - subnet: 172.21.0.0/16
        - subnet: fd00:2::/64

Das enable_ipv6: true-Flag ist pro Netzwerk erforderlich. IPAM (IP Address Management)-Konfiguration weist sowohl IPv4- als auch IPv6-Subnetze zu.

Port-Binding-Syntax für IPv6:

ports:
  - "80:80"              # IPv4 und IPv6
  - "0.0.0.0:8080:80"    # Nur IPv4
  - "[::]:8081:80"       # Nur IPv6
  - "127.0.0.1:8082:80"  # IPv4-Localhost
  - "[::1]:8083:80"      # IPv6-Localhost

Services starten:

docker-compose up -d

Container haben IPv6 überprüfen:

docker-compose exec web ip -6 addr show

Kubernetes Dual-Stack#

Kubernetes unterstützt Dual-Stack-Netzwerke ab Version 1.21 (Beta) und 1.23 (Stabil).

Voraussetzungen#

  1. Kubernetes 1.23 oder später
  2. CNI-Plugin, das Dual-Stack unterstützt (Calico, Cilium, Flannel, Weave)
  3. kube-proxy mit Dual-Stack-Modus
  4. Cloud-Provider-Unterstützung (für LoadBalancer-Services)

Dual-Stack aktivieren#

Für neue Cluster Dual-Stack während der Initialisierung aktivieren. Mit kubeadm:

# kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
networking:
  podSubnet: "10.244.0.0/16,fd00:10:244::/56"
  serviceSubnet: "10.96.0.0/16,fd00:10:96::/112"

Cluster initialisieren:

kubeadm init --config kubeadm-config.yaml

Für verwaltetes Kubernetes (EKS, GKE, AKS) Dual-Stack während Cluster-Erstellung aktivieren:

# EKS
eksctl create cluster \
  --name mycluster \
  --ip-family ipv4,ipv6
 
# GKE
gcloud container clusters create mycluster \
  --enable-ip-alias \
  --stack-type=IPV4_IPV6
 
# AKS
az aks create \
  --resource-group myResourceGroup \
  --name mycluster \
  --network-plugin azure \
  --ip-families IPv4,IPv6

Dual-Stack ist aktiviert überprüfen:

kubectl get nodes -o jsonpath='{.items[*].spec.podCIDRs}'

Sie sollten sowohl IPv4- als auch IPv6-CIDRs sehen.

Pod-Netzwerk#

Pods erhalten automatisch Adressen aus beiden Familien. In den meisten Fällen keine spezielle Konfiguration erforderlich.

Beispiel-Pod:

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - name: nginx
    image: nginx

Bereitstellen und Adressen prüfen:

kubectl apply -f pod.yaml
kubectl get pod test-pod -o jsonpath='{.status.podIPs}'

Ausgabe zeigt sowohl IPv4 als auch IPv6:

[{"ip":"10.244.1.5"},{"ip":"fd00:10:244:1::5"}]

Anwendungen innerhalb von Pods sollten auf :: (alle Adressen) oder spezifisch 0.0.0.0 binden:

# Python-Beispiel - auf IPv4 und IPv6 binden
import socket
 
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
sock.bind(("::", 8080))
sock.listen(5)

Oder separat auf 0.0.0.0 für IPv4 und :: für IPv6 binden.

Service-Konfiguration#

Services können IPv4-only, IPv6-only oder Dual-Stack sein. Steuern Sie dies mit ipFamilyPolicy- und ipFamilies-Feldern.

Dual-Stack-Service (Standard in Dual-Stack-Clustern):

apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ipFamilyPolicy: RequireDualStack
  ipFamilies:
    - IPv4
    - IPv6
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 8080

IPv4-only-Service:

apiVersion: v1
kind: Service
metadata:
  name: myservice-v4
spec:
  ipFamilyPolicy: SingleStack
  ipFamilies:
    - IPv4
  selector:
    app: myapp
  ports:
    - port: 80

IPv6-only-Service:

apiVersion: v1
kind: Service
metadata:
  name: myservice-v6
spec:
  ipFamilyPolicy: SingleStack
  ipFamilies:
    - IPv6
  selector:
    app: myapp
  ports:
    - port: 80

Service-IPs prüfen:

kubectl get svc myservice -o jsonpath='{.spec.clusterIPs}'

Ausgabe:

["10.96.100.5","fd00:10:96::a5"]

LoadBalancer-Services#

LoadBalancer-Services stellen Cloud-Load-Balancer mit Dual-Stack-Frontends bereit (wenn Cloud-Provider unterstützt).

apiVersion: v1
kind: Service
metadata:
  name: web-lb
spec:
  type: LoadBalancer
  ipFamilyPolicy: RequireDualStack
  ipFamilies:
    - IPv4
    - IPv6
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080

Externe IPs prüfen:

kubectl get svc web-lb

Ausgabe:

NAME     TYPE           CLUSTER-IP      EXTERNAL-IP                        PORT(S)
web-lb   LoadBalancer   10.96.100.10    203.0.113.10,2001:db8:1234::10    80:30123/TCP

Nicht alle Cloud-Provider unterstützen Dual-Stack-Load-Balancer noch. Unterstützung für Ihre Plattform überprüfen.

Ingress-Controller#

Ingress-Unterstützung für IPv6 hängt von der Controller-Implementierung ab.

Beliebte Controller mit IPv6-Unterstützung:

  • nginx-ingress: Unterstützt Dual-Stack, hört auf IPv4 und IPv6
  • Traefik: Volle Dual-Stack-Unterstützung
  • HAProxy Ingress: Unterstützt IPv6
  • Contour: Dual-Stack-fähig

nginx-ingress für Dual-Stack konfigurieren:

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  type: LoadBalancer
  ipFamilyPolicy: RequireDualStack
  ipFamilies:
    - IPv4
    - IPv6
  selector:
    app.kubernetes.io/name: ingress-nginx
  ports:
    - name: http
      port: 80
      targetPort: http
    - name: https
      port: 443
      targetPort: https

Ingress-Ressourcen benötigen keine spezielle IPv6-Konfiguration – sie funktionieren automatisch, wenn der Controller sie unterstützt.

Network Policies#

NetworkPolicy-Ressourcen unterstützen IPv6-CIDR-Blöcke:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ipv6
spec:
  podSelector:
    matchLabels:
      app: myapp
  ingress:
    - from:
      - ipBlock:
          cidr: 2001:db8::/32
      - ipBlock:
          cidr: fd00::/8
  egress:
    - to:
      - ipBlock:
          cidr: ::/0
          except:
            - fc00::/7  # ULA blockieren

Sowohl IPv4- als auch IPv6-Regeln können in derselben Policy koexistieren.

CNI-Plugin-Überlegungen#

Verschiedene CNI-Plugins handhaben Dual-Stack unterschiedlich.

Calico#

Calico unterstützt Dual-Stack mit IP-Pools:

apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: ipv4-pool
spec:
  cidr: 10.244.0.0/16
  ipipMode: Never
  natOutgoing: true
  nodeSelector: all()
 
---
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: ipv6-pool
spec:
  cidr: fd00:10:244::/56
  natOutgoing: false
  nodeSelector: all()

IPv6 in Calico aktivieren:

kubectl set env daemonset/calico-node -n kube-system IP6=autodetect
kubectl set env daemonset/calico-node -n kube-system FELIX_IPV6SUPPORT=true

Cilium#

Cilium hat native Dual-Stack-Unterstützung. Während Installation aktivieren:

helm install cilium cilium/cilium \
  --namespace kube-system \
  --set ipv4.enabled=true \
  --set ipv6.enabled=true \
  --set tunnel=disabled \
  --set autoDirectNodeRoutes=true

Flannel#

Flannel erfordert Dual-Stack-Modus in der DaemonSet-Konfiguration:

apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-flannel-cfg
  namespace: kube-system
data:
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "IPv6Network": "fd00:10:244::/56",
      "Backend": {
        "Type": "vxlan"
      }
    }

Weave#

Weave unterstützt Dual-Stack mit beiden IPAM-Modi:

kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')&env.IPALLOC_RANGE=10.244.0.0/16&env.IPALLOC_RANGE=fd00:10:244::/56"

Häufige Fallstricke#

Anwendungs-Binding#

Anwendungen müssen explizit auf IPv6-Adressen hören. Bindung an 0.0.0.0 hört nur auf IPv4.

Falsch:

server.bind(("0.0.0.0", 8080))  # Nur IPv4

Richtig:

server.bind(("::", 8080))  # IPv6 (und IPv4 wenn IPV6_V6ONLY=0)

Viele Sprachen verwenden standardmäßig IPv4-only. Prüfen Sie die Dokumentation Ihres Frameworks.

DNS-Auflösung#

DNS-Abfragen in Dual-Stack-Umgebungen geben sowohl A- als auch AAAA-Records zurück. Anwendungen sollten beide versuchen und IPv6 bevorzugen.

Einige ältere Bibliotheken fragen nur A-Records ab. Abhängigkeiten aktualisieren oder DNS-Auflösung explizit konfigurieren.

Firewall-Regeln#

Container-Firewalls (iptables/ip6tables) benötigen Regeln für beide Familien. Docker und Kubernetes handhaben dies automatisch, wenn korrekt konfiguriert, aber benutzerdefinierte Regeln können IPv6 blockieren.

IPv6-Firewall-Regeln überprüfen:

sudo ip6tables -L -n -v

Externe Konnektivität#

Container mit IPv6 benötigen ordnungsgemäßes Routing zu externen Netzwerken. Wenn Ihr Host keine IPv6-Konnektivität hat, haben Container sie auch nicht.

Zuerst Host-IPv6 testen:

ping6 google.com

Wenn das fehlschlägt, Host-Netzwerk reparieren, bevor Container-Fehlerbehebung.

StatefulSet Headless Services#

StatefulSets mit Headless Services geben sowohl IPv4- als auch IPv6-Adressen für Pod-DNS-Namen zurück:

nslookup web-0.myservice.default.svc.cluster.local

Anwendungen, die sich mit StatefulSet-Pods verbinden, müssen mehrere Adressen elegant handhaben.

Dual-Stack-Bereitstellungen testen#

Test-Anwendung bereitstellen:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
 
---
apiVersion: v1
kind: Service
metadata:
  name: test-svc
spec:
  type: LoadBalancer
  ipFamilyPolicy: RequireDualStack
  ipFamilies:
    - IPv4
    - IPv6
  selector:
    app: test
  ports:
    - port: 80

Anwenden und testen:

kubectl apply -f test-app.yaml
 
# Service-IPs abrufen
kubectl get svc test-svc
 
# IPv4 testen
curl http://<ipv4-external-ip>
 
# IPv6 testen
curl -6 http://[<ipv6-external-ip>]

Von innerhalb eines Pods Dual-Stack-Konnektivität testen:

kubectl run -it --rm debug --image=alpine --restart=Never -- sh
 
# Innerhalb des Pods
apk add curl bind-tools
nslookup test-svc
curl -4 http://test-svc  # IPv4
curl -6 http://test-svc  # IPv6

Produktionsüberlegungen#

  1. Beide Adressfamilien in Observability-Tools überwachen
  2. Failover-Verhalten testen, wenn eine Familie nicht verfügbar ist
  3. Health-Checks für IPv4 und IPv6 konfigurieren
  4. Netzwerktopologie dokumentieren, einschließlich IPv6-Präfixe
  5. IP-Adresszuweisung planen, um Konflikte zu vermeiden
  6. IPv6 in CI/CD-Pipelines aktivieren zum Testen
  7. Team in Dual-Stack-Fehlerbehebung schulen

Verwandte Artikel#

Container-Konnektivität überprüfen

Verwenden Sie unser Ping-Tool und IPv6-Validator, um zu testen, ob Ihre containerisierten Dienste über IPv6 erreichbar sind.

Zusätzliche Ressourcen#