ping6.net

IPv6 en Docker y Kubernetes: Guía de Redes de Contenedores

Configura IPv6 para aplicaciones contenedorizadas. Cubre configuración del daemon Docker, dual-stack de Kubernetes, plugins CNI y exposición de servicios.

ping6.net14 de diciembre de 20247 min read
IPv6DockerKubernetescontenedoresredesDevOps

Las redes de contenedores usan IPv4 por defecto. Eso es un problema si estás ejecutando cargas de trabajo de producción en 2024.

TL;DR - Resumen rápido

Puntos clave:

  • Docker y Kubernetes usan IPv4 por defecto; IPv6 requiere configuración explícita
  • Docker necesita cambios en daemon.json y redes personalizadas con flag --ipv6
  • Kubernetes 1.23+ soporta dual-stack estable con pods y servicios IPv6
  • Los plugins CNI (Calico, Cilium, Flannel) manejan dual-stack de manera diferente

Ir a: Configuración Docker | Dual-Stack Kubernetes | Plugins CNI | Pruebas


Por Qué IPv6 en Contenedores#

Tus contenedores podrían ser solo IPv4 mientras el resto de Internet se mueve a IPv6. Las redes móviles, ISPs y proveedores cloud son IPv6-first. Si tus servicios contenedorizados no soportan IPv6, estás añadiendo latencia a través de gateways NAT64 o peor: perdiendo clientes por completo.

Las plataformas de orquestación de contenedores (Docker, Kubernetes, ECS, Nomad) fueron construidas durante la era IPv4. El soporte IPv6 llegó después como una idea tardía. Los valores predeterminados todavía asumen redes solo IPv4.

Habilitar IPv6 no es difícil, pero requiere configuración explícita en múltiples capas: daemon, red, contenedor y servicio. Falla una capa y tendrás conectividad parcial que se rompe misteriosamente.

Configuración IPv6 de Docker#

El daemon de Docker no habilita IPv6 por defecto. Necesitas configurarlo en /etc/docker/daemon.json.

Configuración del Daemon#

Crea o modifica /etc/docker/daemon.json:

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

Desglosando esto:

  • "ipv6": true habilita soporte IPv6
  • "fixed-cidr-v6" establece la subred para contenedores (usar prefijo ULA o GUA)
  • "ip6tables": true habilita reglas de firewall IPv6 (Docker 20.10+)

Para producción con direcciones globalmente enrutables, usa el prefijo asignado por tu proveedor:

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

Reinicia Docker para aplicar cambios:

sudo systemctl restart docker

Verifica que IPv6 esté habilitado:

docker network inspect bridge | grep IPv6

Deberías ver "EnableIPv6": true.

Red Bridge Predeterminada#

La red bridge predeterminada no obtiene IPv6 automáticamente incluso después de la configuración del daemon. Crea una red personalizada:

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

Ejecuta contenedores en esta red:

docker run -d --network mynetwork nginx

Los contenedores ahora reciben direcciones tanto IPv4 como IPv6.

Docker Compose IPv6#

Docker Compose requiere configuración IPv6 explícita en la definición de red.

Ejemplo docker-compose.yml:

version: '3.8'
 
services:
  web:
    image: nginx
    networks:
      - frontend
    ports:
      - "80:80"
      - "[::]:8080:80"  # Enlazar IPv6 explícitamente
 
  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

La bandera enable_ipv6: true es requerida por red. La configuración IPAM (IP Address Management) asigna subredes tanto IPv4 como IPv6.

Sintaxis de enlace de puertos para IPv6:

ports:
  - "80:80"              # IPv4 e IPv6
  - "0.0.0.0:8080:80"    # Solo IPv4
  - "[::]:8081:80"       # Solo IPv6
  - "127.0.0.1:8082:80"  # IPv4 localhost
  - "[::1]:8083:80"      # IPv6 localhost

Dual-Stack de Kubernetes#

Kubernetes soporta redes dual-stack comenzando con la versión 1.21 (beta) y 1.23 (estable).

Prerrequisitos#

  1. Kubernetes 1.23 o posterior
  2. Plugin CNI que soporte dual-stack (Calico, Cilium, Flannel, Weave)
  3. kube-proxy con modo dual-stack
  4. Soporte del proveedor cloud (para servicios LoadBalancer)

Habilitar Dual-Stack#

Para clusters nuevos, habilita dual-stack durante la inicialización. Con 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"

Inicializa el cluster:

kubeadm init --config kubeadm-config.yaml

Redes de Pods#

Los pods reciben direcciones de ambas familias automáticamente. No se necesita configuración especial en la mayoría de casos.

Ejemplo de pod:

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

Desplegar y verificar direcciones:

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

La salida muestra tanto IPv4 como IPv6:

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

Configuración de Servicios#

Los servicios pueden ser solo IPv4, solo IPv6 o dual-stack. Controla esto con los campos ipFamilyPolicy e ipFamilies.

Servicio dual-stack (predeterminado en clusters dual-stack):

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

Servicio solo IPv4:

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

Verificar IPs de servicio:

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

Salida:

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

Consideraciones de Plugin CNI#

Diferentes plugins CNI manejan dual-stack de manera diferente.

Calico#

Calico soporta dual-stack con pools IP:

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()

Habilitar IPv6 en Calico:

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 tiene soporte nativo dual-stack. Habilitar durante instalación:

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

Trampas Comunes#

Enlace de Aplicaciones#

Las aplicaciones deben enlazar explícitamente a direcciones IPv6. Enlazar a 0.0.0.0 solo escucha en IPv4.

Incorrecto:

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

Correcto:

server.bind(("::", 8080))  # IPv6 (e IPv4 si IPV6_V6ONLY=0)

Muchos lenguajes usan IPv4 por defecto. Verifica la documentación de tu framework.

Resolución DNS#

Las consultas DNS en entornos dual-stack devuelven tanto registros A como AAAA. Las aplicaciones deben intentar ambos, prefiriendo IPv6.

Algunas bibliotecas antiguas solo consultan registros A. Actualiza dependencias o configura resolución DNS explícitamente.

Reglas de Firewall#

Los firewalls de contenedores (iptables/ip6tables) necesitan reglas para ambas familias. Docker y Kubernetes lo manejan automáticamente si se configura correctamente, pero las reglas personalizadas pueden bloquear IPv6.

Verificar reglas de firewall IPv6:

sudo ip6tables -L -n -v

Conectividad Externa#

Los contenedores con IPv6 necesitan enrutamiento apropiado a redes externas. Si tu host no tiene conectividad IPv6, los contenedores tampoco.

Probar IPv6 del host primero:

ping6 google.com

Si eso falla, corrige las redes del host antes de resolver problemas de contenedores.

Probar Despliegues Dual-Stack#

Desplegar una aplicación de prueba:

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

Aplicar y probar:

kubectl apply -f test-app.yaml
 
# Obtener IPs de servicio
kubectl get svc test-svc
 
# Probar IPv4
curl http://<ipv4-external-ip>
 
# Probar IPv6
curl -6 http://[<ipv6-external-ip>]

Desde dentro de un pod, probar conectividad dual-stack:

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

Consideraciones de Producción#

  1. Monitorear ambas familias de direcciones en herramientas de observabilidad
  2. Probar comportamiento de failover cuando una familia no está disponible
  3. Configurar health checks para IPv4 e IPv6
  4. Documentar topología de red incluyendo prefijos IPv6
  5. Planificar asignación de direcciones IP para evitar conflictos
  6. Habilitar IPv6 en pipelines CI/CD para pruebas
  7. Entrenar al equipo en resolución de problemas dual-stack

Artículos Relacionados#

Verificar Conectividad de Contenedores

Usa nuestra Herramienta Ping y Validador IPv6 para probar que tus servicios contenedorizados son alcanzables sobre IPv6.

Recursos Adicionales#