ping6.net

IPv6 في Docker و Kubernetes: دليل شبكات الحاويات

تكوين IPv6 للتطبيقات المحوّاة. يغطي إعدادات daemon في Docker، ومضاعف المكدس في Kubernetes، وإضافات CNI، وعرض الخدمات.

ping6.net14 ديسمبر 202410 min read
IPv6DockerKubernetescontainersnetworkingDevOps

شبكات الحاويات تفترض IPv4 افتراضيًا. هذه مشكلة إذا كنت تُشغل أحمال عمل في الإنتاج في 2024.

TL;DR - ملخص سريع

النقاط الرئيسية:

  • Docker و Kubernetes يستخدمان IPv4 فقط افتراضياً؛ يتطلب IPv6 تكويناً صريحاً
  • يحتاج Docker إلى تغييرات daemon.json وشبكات مخصصة مع علامة --ipv6
  • Kubernetes 1.23+ يدعم المكدس المزدوج المستقر مع IPv6 للـ pod والخدمة
  • إضافات CNI (Calico، Cilium، Flannel) تتعامل مع المكدس المزدوج بشكل مختلف

انتقل إلى: تكوين Docker | المكدس المزدوج في Kubernetes | إضافات CNI | الاختبار


لماذا IPv6 في الحاويات#

قد تكون حاوياتك فقط IPv4 بينما ينتقل بقية الإنترنت إلى IPv6. الشبكات المحمولة ومزودي خدمة الإنترنت ومزودي السحابة يعطون الأولوية لـ IPv6. إذا لم تدعم خدماتك المحوّاة IPv6، فأنت تضيف زمن استجابة من خلال بوابات NAT64 أو أسوأ — تفقد العملاء تمامًا.

منصات تنسيق الحاويات (Docker، Kubernetes، ECS، Nomad) تم بناؤها خلال عصر IPv4. جاء دعم IPv6 لاحقًا كفكرة لاحقة. لا تزال الإعدادات الافتراضية تفترض شبكات IPv4 فقط.

تمكين IPv6 ليس صعبًا، ولكنه يتطلب تكوينًا صريحًا على طبقات متعددة: daemon، شبكة، حاوية، وخدمة. افتقد طبقة واحدة وسيكون لديك اتصال جزئي ينكسر بشكل غامض.

تكوين Docker IPv6#

لا يُمكن Docker daemon IPv6 افتراضيًا. تحتاج إلى تكوينه في /etc/docker/daemon.json.

تكوين Daemon#

أنشئ أو عدّل /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+)

للإنتاج مع عناوين قابلة للتوجيه عالميًا، استخدم البادئة المعينة من مزودك:

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

أعد تشغيل Docker لتطبيق التغييرات:

sudo systemctl restart docker

تحقق من تمكين IPv6:

docker network inspect bridge | grep IPv6

يجب أن ترى "EnableIPv6": true.

شبكة الجسر الافتراضية#

لا تحصل شبكة الجسر الافتراضية تلقائيًا على IPv6 حتى بعد تكوين daemon. أنشئ شبكة مخصصة:

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

قم بتشغيل الحاويات على هذه الشبكة:

docker run -d --network mynetwork nginx

تحصل الحاويات الآن على عناوين IPv4 و IPv6.

الشبكات المعرّفة من قبل المستخدم#

تدعم شبكات الجسر المعرّفة من قبل المستخدم مضاعف المكدس:

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:

# Terminal 1
docker run -it --rm --network appnetwork --name container1 alpine sh
 
# Terminal 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"  # Bind IPv6 explicitly
 
  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) الشبكات الفرعية لكل من IPv4 و IPv6.

بناء جملة ربط المنفذ لـ IPv6:

ports:
  - "80:80"              # IPv4 and IPv6
  - "0.0.0.0:8080:80"    # IPv4 only
  - "[::]:8081:80"       # IPv6 only
  - "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 show

Kubernetes مضاعف المكدس#

يدعم Kubernetes شبكات مضاعف المكدس بدءًا من الإصدار 1.21 (بيتا) و 1.23 (مستقر).

المتطلبات الأساسية#

  1. Kubernetes 1.23 أو أحدث
  2. إضافة CNI تدعم مضاعف المكدس (Calico، Cilium، Flannel، Weave)
  3. kube-proxy مع وضع مضاعف المكدس
  4. دعم مزود السحابة (لخدمات LoadBalancer)

تمكين مضاعف المكدس#

للعناقيد الجديدة، مكّن مضاعف المكدس أثناء التهيئة. مع 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)، مكّن مضاعف المكدس أثناء إنشاء العنقود:

# 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

تحقق من تمكين مضاعف المكدس:

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

يجب أن ترى CIDRs لكل من IPv4 و IPv6.

شبكات Pod#

تتلقى Pods عناوين من كلا العائلتين تلقائيًا. لا حاجة لتكوين خاص في معظم الحالات.

مثال pod:

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"}]

يجب أن تربط التطبيقات داخل pods إلى :: (جميع العناوين) أو 0.0.0.0 على وجه التحديد:

# Python example - bind to both IPv4 and 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 فقط، أو مضاعف المكدس. تحكم في هذا باستخدام حقول ipFamilyPolicy و ipFamilies.

خدمة مضاعف المكدس (الافتراضي في عناقيد مضاعف المكدس):

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

تحقق من IPs الخدمة:

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

الإخراج:

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

خدمات LoadBalancer#

توفر خدمات LoadBalancer موازنات تحميل سحابية مع واجهات أمامية مضاعفة المكدس (إذا كان مزود السحابة يدعمها).

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

تحقق من IPs الخارجية:

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

ليس كل مزودي السحابة يدعمون موازنات تحميل مضاعفة المكدس بعد. تحقق من الدعم لمنصتك.

متحكمات Ingress#

يعتمد دعم Ingress لـ IPv6 على تطبيق المتحكم.

المتحكمات الشائعة مع دعم IPv6:

  • nginx-ingress: يدعم مضاعف المكدس، يستمع على كل من IPv4 و IPv6
  • Traefik: دعم كامل لمضاعف المكدس
  • HAProxy Ingress: يدعم IPv6
  • Contour: قادر على مضاعف المكدس

تكوين nginx-ingress لمضاعف المكدس:

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 كتل CIDR لـ IPv6:

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  # Block ULA

يمكن أن تتعايش قواعد IPv4 و IPv6 في نفس السياسة.

اعتبارات إضافة CNI#

تتعامل إضافات CNI المختلفة مع مضاعف المكدس بشكل مختلف.

Calico#

يدعم Calico مضاعف المكدس مع مجموعات 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=true

Cilium#

لدى Cilium دعم أصلي لمضاعف المكدس. مكّن أثناء التثبيت:

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

Flannel#

يتطلب Flannel وضع مضاعف المكدس في تكوين 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 مضاعف المكدس مع كلا وضعي 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 only

صحيح:

server.bind(("::", 8080))  # IPv6 (and IPv4 if IPV6_V6ONLY=0)

العديد من اللغات تفترض IPv4 فقط افتراضيًا. تحقق من وثائق إطار عملك.

حل DNS#

تُرجع استعلامات DNS في بيئات مضاعف المكدس سجلات A و AAAA. يجب أن تحاول التطبيقات كليهما، مع تفضيل IPv6.

تستعلم بعض المكتبات القديمة فقط عن سجلات A. حدّث التبعيات أو قم بتكوين حل DNS بشكل صريح.

قواعد جدار الحماية#

تحتاج جدران حماية الحاويات (iptables/ip6tables) إلى قواعد لكلا العائلتين. يتعامل Docker و Kubernetes مع هذا تلقائيًا إذا تم تكوينه بشكل صحيح، ولكن القواعد المخصصة قد تحظر IPv6.

تحقق من قواعد جدار حماية IPv6:

sudo ip6tables -L -n -v

الاتصال الخارجي#

تحتاج الحاويات بـ IPv6 إلى توجيه مناسب إلى الشبكات الخارجية. إذا لم يكن لدى مضيفك اتصال IPv6، فلن يكون للحاويات أيضًا.

اختبر IPv6 للمضيف أولاً:

ping6 google.com

إذا فشل ذلك، أصلح شبكات المضيف قبل استكشاف أخطاء الحاويات.

خدمات StatefulSet Headless#

تُرجع StatefulSets مع خدمات headless عناوين IPv4 و IPv6 لأسماء DNS للـ pod:

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

يجب أن تتعامل التطبيقات التي تتصل بـ pods من StatefulSet مع عناوين متعددة برشاقة.

اختبار نشر مضاعف المكدس#

نشر تطبيق اختبار:

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
 
# احصل على IPs الخدمة
kubectl get svc test-svc
 
# اختبر IPv4
curl http://<ipv4-external-ip>
 
# اختبر IPv6
curl -6 http://[<ipv6-external-ip>]

من داخل pod، اختبر اتصال مضاعف المكدس:

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

اعتبارات الإنتاج#

  1. راقب كلا عائلتي العناوين في أدوات المراقبة
  2. اختبر سلوك التعطل عندما تكون عائلة واحدة غير متاحة
  3. قم بتكوين فحوصات الصحة لكل من IPv4 و IPv6
  4. وثق طوبولوجيا الشبكة بما في ذلك بادئات IPv6
  5. خطط لتخصيص عنوان IP لتجنب التعارضات
  6. مكّن IPv6 في خطوط CI/CD للاختبار
  7. درّب الفريق على استكشاف أخطاء مضاعف المكدس وإصلاحها

مقالات ذات صلة#

تحقق من اتصال الحاوية

استخدم أداة Ping و مدقق IPv6 لاختبار أن خدماتك المحوّاة يمكن الوصول إليها عبر IPv6.

موارد إضافية#