IPv6 в Docker и Kubernetes: Руководство по сетям контейнеров
Настройка IPv6 для контейнерных приложений. Рассматриваются параметры демона Docker, dual-stack в Kubernetes, плагины CNI и публикация сервисов.
Сети контейнеров по умолчанию используют IPv4. Это проблема, если вы эксплуатируете production-нагрузки в 2024 году.
TL;DR - Краткое резюме
Ключевые моменты:
- Docker и Kubernetes по умолчанию используют только IPv4; IPv6 требует явной настройки
- Docker требует изменений daemon.json и пользовательских сетей с флагом
--ipv6 - Kubernetes 1.23+ поддерживает стабильный dual-stack с IPv6 для pod и сервисов
- CNI-плагины (Calico, Cilium, Flannel) обрабатывают dual-stack по-разному
Перейти к: Настройка Docker | Dual-Stack Kubernetes | CNI-плагины | Тестирование
Зачем IPv6 в контейнерах#
Ваши контейнеры могут использовать только IPv4, в то время как остальной интернет переходит на IPv6. Мобильные сети, провайдеры и облачные платформы приоритизируют IPv6. Если ваши контейнерные сервисы не поддерживают IPv6, вы добавляете задержку через шлюзы NAT64 или, что еще хуже — теряете клиентов.
Платформы оркестрации контейнеров (Docker, Kubernetes, ECS, Nomad) были созданы в эпоху IPv4. Поддержка IPv6 появилась позже как дополнение. Настройки по умолчанию все еще предполагают использование только IPv4.
Включение IPv6 не сложно, но требует явной настройки на нескольких уровнях: демон, сеть, контейнер и сервис. Пропустите один уровень — и получите частичную связь, которая ломается непредсказуемо.
Настройка IPv6 в Docker#
Демон Docker не включает IPv6 по умолчанию. Нужно настроить его в /etc/docker/daemon.json.
Настройка демона#
Создайте или измените /etc/docker/daemon.json:
{
"ipv6": true,
"fixed-cidr-v6": "fd00::/80",
"experimental": false,
"ip6tables": true
}Разберем это:
"ipv6": trueвключает поддержку IPv6"fixed-cidr-v6"задает подсеть для контейнеров (используйте префикс ULA или GUA)"ip6tables": trueвключает правила IPv6-файрвола (Docker 20.10+)
Для production с глобально маршрутизируемыми адресами используйте префикс вашего провайдера:
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8:1234::/64"
}Перезапустите Docker для применения изменений:
sudo systemctl restart dockerПроверьте, что IPv6 включен:
docker network inspect bridge | grep IPv6Вы должны увидеть "EnableIPv6": true.
Сеть bridge по умолчанию#
Сеть bridge по умолчанию не получает IPv6 автоматически даже после настройки демона. Создайте пользовательскую сеть:
docker network create --ipv6 \
--subnet=172.20.0.0/16 \
--subnet=fd00:dead:beef::/48 \
mynetworkЗапустите контейнеры в этой сети:
docker run -d --network mynetwork nginxКонтейнеры теперь получают как IPv4, так и IPv6 адреса.
Пользовательские сети#
Пользовательские bridge-сети поддерживают 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Контейнеры в этой сети могут общаться через IPv6:
# Терминал 1
docker run -it --rm --network appnetwork --name container1 alpine sh
# Терминал 2
docker run -it --rm --network appnetwork alpine sh
ping6 container1Встроенный DNS-резолвер Docker возвращает записи AAAA для имен контейнеров, когда включен IPv6.
NAT и маршрутизация IPv6#
По умолчанию Docker использует NAT для IPv4, но может не использовать NAT для IPv6. Это зависит от вашей конфигурации fixed-cidr-v6.
С префиксами ULA (fd00::/8) вам нужен NAT для доступа в интернет:
# Включите переадресацию IPv6
sudo sysctl -w net.ipv6.conf.all.forwarding=1
# Добавьте правило masquerade
sudo ip6tables -t nat -A POSTROUTING -s fd00::/80 ! -o docker0 -j MASQUERADEС префиксами GUA (глобально маршрутизируемыми) маршрутизируйте напрямую без NAT:
# Добавьте маршрут для подсети контейнеров
sudo ip -6 route add 2001:db8:1234::/64 via <docker-host-ipv6>Настройте вышестоящий роутер для маршрутизации вашей подсети контейнеров к хосту Docker.
Docker Compose с IPv6#
Docker Compose требует явной настройки IPv6 в определении сети.
Пример docker-compose.yml:
version: '3.8'
services:
web:
image: nginx
networks:
- frontend
ports:
- "80:80"
- "[::]:8080:80" # Явная привязка IPv6
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Флаг enable_ipv6: true требуется для каждой сети. Конфигурация IPAM (IP Address Management) назначает как IPv4, так и IPv6 подсети.
Синтаксис привязки портов для IPv6:
ports:
- "80:80" # IPv4 и IPv6
- "0.0.0.0:8080:80" # Только IPv4
- "[::]:8081:80" # Только IPv6
- "127.0.0.1:8082:80" # IPv4 localhost
- "[::1]:8083:80" # IPv6 localhostЗапустите сервисы:
docker-compose up -dПроверьте, что контейнеры имеют IPv6:
docker-compose exec web ip -6 addr showDual-Stack в Kubernetes#
Kubernetes поддерживает dual-stack сети начиная с версии 1.21 (beta) и 1.23 (stable).
Предварительные требования#
- Kubernetes 1.23 или новее
- Плагин CNI с поддержкой dual-stack (Calico, Cilium, Flannel, Weave)
- kube-proxy в режиме dual-stack
- Поддержка облачного провайдера (для сервисов LoadBalancer)
Включение Dual-Stack#
Для новых кластеров включите dual-stack при инициализации. С 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"Инициализируйте кластер:
kubeadm init --config kubeadm-config.yamlДля управляемого Kubernetes (EKS, GKE, AKS) включите dual-stack при создании кластера:
# 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 включен:
kubectl get nodes -o jsonpath='{.items[*].spec.podCIDRs}'Вы должны увидеть как IPv4, так и IPv6 CIDR.
Сети подов#
Поды автоматически получают адреса из обоих семейств. В большинстве случаев специальная настройка не требуется.
Пример пода:
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: nginx
image: nginxРазверните и проверьте адреса:
kubectl apply -f pod.yaml
kubectl get pod test-pod -o jsonpath='{.status.podIPs}'Вывод показывает как IPv4, так и IPv6:
[{"ip":"10.244.1.5"},{"ip":"fd00:10:244:1::5"}]Приложения внутри подов должны привязываться к :: (все адреса) или конкретно 0.0.0.0:
# Пример Python — привязка к IPv4 и IPv6
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)Или привязывайтесь к 0.0.0.0 для IPv4 и :: для IPv6 отдельно.
Настройка сервисов#
Сервисы могут быть только IPv4, только IPv6 или dual-stack. Управляйте этим с помощью полей ipFamilyPolicy и ipFamilies.
Dual-stack сервис (по умолчанию в dual-stack кластерах):
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ipFamilyPolicy: RequireDualStack
ipFamilies:
- IPv4
- IPv6
selector:
app: myapp
ports:
- port: 80
targetPort: 8080Сервис только IPv4:
apiVersion: v1
kind: Service
metadata:
name: myservice-v4
spec:
ipFamilyPolicy: SingleStack
ipFamilies:
- IPv4
selector:
app: myapp
ports:
- port: 80Сервис только IPv6:
apiVersion: v1
kind: Service
metadata:
name: myservice-v6
spec:
ipFamilyPolicy: SingleStack
ipFamilies:
- IPv6
selector:
app: myapp
ports:
- port: 80Проверьте IP сервисов:
kubectl get svc myservice -o jsonpath='{.spec.clusterIPs}'Вывод:
["10.96.100.5","fd00:10:96::a5"]Сервисы LoadBalancer#
Сервисы LoadBalancer создают облачные балансировщики с dual-stack интерфейсами (если облачный провайдер поддерживает).
apiVersion: v1
kind: Service
metadata:
name: web-lb
spec:
type: LoadBalancer
ipFamilyPolicy: RequireDualStack
ipFamilies:
- IPv4
- IPv6
selector:
app: web
ports:
- port: 80
targetPort: 8080Проверьте внешние IP:
kubectl get svc web-lbВывод:
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Не все облачные провайдеры пока поддерживают dual-stack балансировщики. Проверьте поддержку для вашей платформы.
Ingress-контроллеры#
Поддержка IPv6 в Ingress зависит от реализации контроллера.
Популярные контроллеры с поддержкой IPv6:
- nginx-ingress: Поддерживает dual-stack, слушает на IPv4 и IPv6
- Traefik: Полная поддержка dual-stack
- HAProxy Ingress: Поддерживает IPv6
- Contour: Поддерживает dual-stack
Настройка nginx-ingress для dual-stack:
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 не требуют специальной настройки IPv6 — они работают автоматически, если контроллер поддерживает его.
Сетевые политики#
Ресурсы NetworkPolicy поддерживают IPv6 CIDR-блоки:
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Правила IPv4 и IPv6 могут сосуществовать в одной политике.
Особенности плагинов CNI#
Разные плагины CNI обрабатывают dual-stack по-разному.
Calico#
Calico поддерживает dual-stack с 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()Включите IPv6 в Calico:
kubectl set env daemonset/calico-node -n kube-system IP6=autodetect
kubectl set env daemonset/calico-node -n kube-system FELIX_IPV6SUPPORT=trueCilium#
Cilium имеет нативную поддержку dual-stack. Включите при установке:
helm install cilium cilium/cilium \
--namespace kube-system \
--set ipv4.enabled=true \
--set ipv6.enabled=true \
--set tunnel=disabled \
--set autoDirectNodeRoutes=trueFlannel#
Flannel требует режим dual-stack в конфигурации DaemonSet:
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 поддерживает dual-stack с обоими режимами IPAM:
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"Распространенные ошибки#
Привязка приложений#
Приложения должны явно слушать на IPv6-адресах. Привязка к 0.0.0.0 слушает только IPv4.
Неправильно:
server.bind(("0.0.0.0", 8080)) # Только IPv4Правильно:
server.bind(("::", 8080)) # IPv6 (и IPv4 если IPV6_V6ONLY=0)Многие языки по умолчанию используют только IPv4. Проверьте документацию вашего фреймворка.
DNS-резолвинг#
DNS-запросы в dual-stack окружениях возвращают как A, так и AAAA записи. Приложения должны пробовать оба, предпочитая IPv6.
Некоторые старые библиотеки запрашивают только A-записи. Обновите зависимости или явно настройте DNS-резолвинг.
Правила файрвола#
Файрволы контейнеров (iptables/ip6tables) требуют правил для обоих семейств. Docker и Kubernetes обрабатывают это автоматически при правильной настройке, но пользовательские правила могут блокировать IPv6.
Проверьте правила IPv6-файрвола:
sudo ip6tables -L -n -vВнешняя связь#
Контейнерам с IPv6 нужна правильная маршрутизация к внешним сетям. Если у вашего хоста нет IPv6-связи, контейнеры тоже ее не получат.
Сначала проверьте IPv6 хоста:
ping6 google.comЕсли это не работает, исправьте сеть хоста перед диагностикой контейнеров.
Headless-сервисы StatefulSet#
StatefulSet с headless-сервисами возвращают как IPv4, так и IPv6 адреса для DNS-имен подов:
nslookup web-0.myservice.default.svc.cluster.localПриложения, подключающиеся к подам StatefulSet, должны корректно обрабатывать множественные адреса.
Тестирование Dual-Stack развертываний#
Разверните тестовое приложение:
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Примените и протестируйте:
kubectl apply -f test-app.yaml
# Получите IP сервисов
kubectl get svc test-svc
# Тест IPv4
curl http://<ipv4-external-ip>
# Тест IPv6
curl -6 http://[<ipv6-external-ip>]Изнутри пода проверьте dual-stack связь:
kubectl run -it --rm debug --image=alpine --restart=Never -- sh
# Внутри пода
apk add curl bind-tools
nslookup test-svc
curl -4 http://test-svc # IPv4
curl -6 http://test-svc # IPv6Рекомендации для production#
- Мониторьте оба семейства адресов в инструментах наблюдения
- Тестируйте поведение failover когда одно семейство недоступно
- Настройте health checks для IPv4 и IPv6
- Документируйте топологию сети включая IPv6-префиксы
- Планируйте выделение IP-адресов чтобы избежать конфликтов
- Включите IPv6 в CI/CD пайплайнах для тестирования
- Обучите команду диагностике dual-stack
Связанные статьи#
- IPv6 для разработчиков — Реализация IPv6 на уровне приложений
- IPv6 в AWS, Azure и GCP — Настройка IPv6 на облачных платформах
- Включение IPv6 в вашей сети — Развертывание IPv6 на уровне инфраструктуры
Проверьте связь с контейнерами
Используйте наш Ping-инструмент и Валидатор IPv6 для проверки доступности ваших контейнерных сервисов через IPv6.