רשתות עם מחסנית כפולה של IPv4/‏IPv6

‫Google Distributed Cloud תומך ברשתות עם מחסנית כפולה של IPv4/IPv6. המשמעות היא שאפשר לקבל באשכול תנועה ממכשירים חיצוניים שמשתמשים בגרסה 4 של פרוטוקול האינטרנט (IPv4) או בגרסה 6 של פרוטוקול האינטרנט (IPv6).

רשתות עם תמיכה כפולה מקצות כתובות IPv4 ו-IPv6 גם ל-Pods וגם לצמתים. לשירות Kubernetes יכולה להיות כתובת IPv4, כתובת IPv6 או שתיהן.

כל האשכולות עם תמיכה כפולה ב-IPv4 וב-IPv6 משתמשים במצב שטוח עבור IPv6. כברירת מחדל, באשכול עם תמיכה כפולה ב-IPv4 נעשה שימוש במצב איים, אבל אפשר להגדיר אותו לשימוש במצב שטוח ב-IPv4.

כדי ליצור אשכול עם תמיכה ב-dual-stack, הרשת הבסיסית צריכה לתמוך ב-dual-stack. אם הרשת הבסיסית היא רשת IPv4 או IPv6 חד-שכבתית, אי אפשר להפעיל אשכול דו-שכבתי.

לפני שמתחילים

אם הצמתים באשכול מריצים RedHat Enterprise Linux ו-SELinux מופעל בהם, צריך לבצע את הפעולות הבאות בכל צומת:

  • ב/etc/firewalld/firewalld.conf, מגדירים את IPv6_rpfilter=no.

  • מריצים את systemctl restart firewalld.

סקירה כללית של יצירת אשכול עם תמיכה כפולה בפרוטוקולי אינטרנט

אפשר להפעיל רשתות עם פרוטוקול כפול כשיוצרים אשכול חדש, אבל אי אפשר להפעיל רשתות עם פרוטוקול כפול באשכול קיים.

פועלים לפי ההוראות באחד ממסמכי יצירת האשכול.

בקובץ התצורה, כוללים מניפסטים של הרכיבים הבאים:

  • משאב Namespace
  • משאב של אשכול
  • משאב NodePool אחד או יותר
  • משאב אחד או יותר של ClusterCIDRConfig

ממלאים את מניפסט מרחב השמות ואת מניפסט NodePool כמו במקרה של אשכול עם סוג אחד של כתובות IP.

במניפסט של האשכול, בקטע clusterNetwork.services.cidrBlocks, מציינים טווח CIDR של IPv4 וטווח CIDR של IPv6. זהו הקריטריון להפעלת אשכול עם תמיכה כפולה ב-IPv4 וב-IPv6. כלומר, אם תספקו טווחי CIDR של שירותים גם ל-IPv4 וגם ל-IPv6, לאשכול שלכם תהיה רשת עם תמיכה כפולה.

במניפסט של האשכול, בקטע clusterNetwork.pods.cidrBlocks, מציינים טווח CIDR של IPv4, אבל לא מציינים טווח CIDR של IPv6. טווחים של CIDR IPv6 עבור Pods מצוינים במניפסטים של ClusterCIDRConfig.

אם אתם משתמשים באיזון עומסים בחבילה, צריך לספק גם כתובות IPv4 וגם כתובות IPv6 בקטע loadBalancer.addressPools של מניפסט האשכול.

משאבי ClusterCIDRConfig מיועדים לציון טווחי CIDR של IPv4 ו-IPv6 עבור Pods. אפשר להשתמש במשאב ClusterCIDRConfig יחיד כדי לציין טווחי CIDR שרלוונטיים לכל האשכול. כלומר, כתובות ה-Pod של IPv4 לכל הצמתים נלקחות מטווח CIDR יחיד, וכתובות ה-Pod של IPv6 לכל הצמתים נלקחות מטווח CIDR יחיד. אפשר גם להשתמש בכמה משאבי ClusterCIDRConfig כדי לציין טווחי CIDR שחלים על מאגר צמתים מסוים או על צומת מסוים.

נגישות לכתובות IP של Pod

ב-cluster עם תמיכה כפולה בפרוטוקולים נעשה שימוש במצב שטוח לרשת IPv6. הדוגמה שמופיעה במסמך הזה היא עבור אשכול שמשתמש ברשת סטטית במצב שטוח עבור IPv6. כלומר, האשכול לא מוגדר לשימוש ב-Border Gateway Protocol‏ (BGP).

באשכול שמשתמש ברשת סטטית במצב שטוח, צריך לציין כתובות IP של צמתים ושל Pod, שכולן חלק מאותה רשת משנה. ההגדרה הזו מאפשרת ללקוחות מחוץ לאשכול, אבל באותו דומיין של שכבה 2 כמו צמתי האשכול, לשלוח חבילות ישירות לכתובות IP של Pod.

לדוגמה, נניח שצמתי האשכול ומכונות אחרות נמצאים כולם באותו דומיין Layer 2. כך אפשר לציין טווחי כתובות:

מטרהטווחמספר הכתובות
כל הדומיין ברמה 2fd12::/108220
קבוצת Podfd12::1:0/112216
צמתיםfd12::2:0/112216
מכונות אחרותfd12::3:0/112216
אח"מיםfd12::4:0/112216

בדוגמה שלמעלה, אלה הנקודות החשובות שכדאי להבין:

  • כל הכתובות של הצמתים, ה-Pods והמכונות נמצאות בטווח הגדול: fd12::/108.

  • כתובות ה-IP של ה-Pod הן קבוצת משנה של הטווח הגדול.

  • כתובות ה-IP של הצמתים נמצאות בקבוצת משנה אחרת של הטווח הגדול.

  • כתובות ה-IP של מכונות אחרות נמצאות בקבוצת משנה אחרת של הטווח הגדול.

  • כל טווחי קבוצות המשנה נבדלים זה מזה.

בדוגמה הקודמת, לכל מכונה בדומיין של שכבה 2, כולל צמתי האשכול, צריך להיות כלל העברה לטווח הגדול. לדוגמה:

inet fd12::/108 scope global eth0

דוגמה: יצירת אשכול עם תמיכה ב-IPv4 ו-IPv6

כשיוצרים אשכול עם תמיכה ב-IPv4 ו-IPv6, יש כמה אפשרויות. לדוגמה, יכול להיות שיש לכם טווחי CIDR בכל האשכול, או טווחי CIDR שחלים על מאגרי צמתים מסוימים. אפשר לשלב בין רשת שטוחה של IPv6 לבין רשת במצב איים של IPv4. או שרשתות ה-IPv4 וה-IPv6 שלכם יכולות להיות שטוחות. אפשר להשתמש באיזון עומסים בחבילה או באיזון עומסים ידני.

בקטע הזה מופיעה דוגמה אחת ליצירה של אשכול עם תמיכה כפולה ב-IPv4 וב-IPv6. לדוגמה, המאפיינים של האשכול:

  • רשת IPv4 במצב איים
  • רשת IPv6 במצב שטוח
  • טווח CIDR של IPv4 ברמת האשכול עבור Pods
  • טווח CIDR של IPv6 ברמת האשכול עבור Pods
  • טווח CIDR של IPv4 לכל האשכול בשביל שירותים
  • טווח CIDR של IPv6 לכל האשכול בשביל שירותים
  • מאגר כתובות IPv4 לשימוש בשירותים מסוג LoadBalancer
  • מאגר כתובות IPv6 לשימוש בשירותים מסוג LoadBalancer
  • איזון עומסים בחבילה

דוגמאות נוספות להגדרות זמינות במאמר וריאציות של שימוש ב-ClusterCIDRConfig.

מילוי קובץ תצורה

פועלים לפי ההוראות באחד ממסמכי יצירת האשכול.

בקובץ התצורה, במניפסט Cluster:

  • בשדה clusterNetwork.pods.cidrBlocks, מציינים טווח CIDR אחד של IPv4.

  • בשביל clusterNetwork.services.cidrBlocks, מציינים שני טווחי CIDR: אחד ל-IPv4 ואחד ל-IPv6.

  • בשדה loadBalancer.addressPools, מציינים שני טווחי כתובות: אחד ל-IPv4 ואחד ל-IPv6. כשיוצרים שירות מסוג LoadBalancer, כתובות ה-IP החיצוניות של השירות נבחרות מתוך הטווחים האלה.

זוהי דוגמה שמציגה את החלקים הרלוונטיים במניפסט של אשכול:

apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: "dual-stack"
  namespace: "cluster-dual-stack"

spec:
  clusterNetwork:
    pods:
      cidrBlocks:
      - "192.168.0.0/16"
    services
      cidrBlocks:
       - "172.16.0.0/20"
       - "fd12::5:0/116"
...
  loadBalancer:
    mode: "bundled"
    ...
    addressPools:
    - name: "pool-1"
      addresses:
       - "10.2.0.212-10.2.0.221"
       - "fd12::4:101-fd12::4:110"

באותו קובץ תצורה, כוללים מניפסט ל-ClusterCIDRConfig.

  • מגדירים את ipv4.cidr לאותו טווח CIDR שסיפקתם במניפסט Cluster. הדבר נדרש אם IPv4 נמצא במצב איים.

  • מגדירים את namespace לאותו ערך שסיפקתם במניפסט Cluster.

  • מגדירים את ipv6.cidr לטווח CIDR של IPv6 עבור Pods.

  • לכל טווח CIDR, צריך לספק ערך ל-perNodeMaskSize כדי לציין כמה כתובות של Pod יוקצו לכל צומת. מספר כתובות ה-IPv4 שהוקצו לכל צומת צריך להיות זהה למספר כתובות ה-IPv6 שהוקצו לכל צומת. אתם צריכים להגדיר את הערכים של perNodeMaskSize בהתאם. לדוגמה, אם רוצים 28 כתובות לכל צומת, מגדירים את הערכים של perNodeMaskSize באופן הבא:

    • ipv4.perNodeMaskSize: 24 # (32 - 8 = 24)
    • ipv6.perNodeMaskSize: 120 # (128 - 8 = 120)

דוגמה לקובץ מניפסט ClusterCIDRConfig:

apiVersion: baremetal.cluster.gke.io/v1alpha1
kind: ClusterCIDRConfig
metadata:
  name: "cluster-wide-ranges"
  namespace: "cluster-dual-stack"  # Must be the same as the Cluster namespace.
spec:
  ipv4:
    cidr: "192.168.0.0/16"  #  For island mode, must be the same as the Cluster CIDR.
    perNodeMaskSize: 24
  ipv6:
    cidr: "fd12::1:0/112"
    perNodeMaskSize: 120

בדוגמה הקודמת:

  • טווח ה-CIDR של ה-Pod ב-IPv4 כולל ‎2(32-16) = 216 כתובות. גודל המסכה לכל צומת הוא 24, ולכן מספר הכתובות שמוקצות לכל צומת הוא 2(32-24) = 28.

  • טווח ה-CIDR של ה-Pod ב-IPv6 הוא 2(128-112) = 216 כתובות. גודל המסכה לכל צומת הוא 120, ולכן מספר הכתובות שהוקצו לכל צומת הוא 2(128-120) = 28.

קובץ תצורה לדוגמה

סיום יצירת האשכול

משלימים את יצירת האשכול לפי ההוראות במסמך ליצירת אשכול.

הצגת צמתים ו-Pods באשכול

מציגים את הצמתים של האשכול:

kubectl --kubeconfig CLUSTER_KUBECONFIG get nodes --output yaml

מחליפים את CLUSTER_KUBECONFIG בנתיב של קובץ ה-kubeconfig של האשכול.

בפלט אפשר לראות את כתובות ה-IPv4 וה-IPv6 של כל צומת. אפשר גם לראות את טווחי הכתובות של IPv4 ו-IPv6 עבור Pods בצומת. לדוגמה:

- apiVersion: v1
  kind: Node
  ...
  spec:
    podCIDR: 192.168.1.0/24
    podCIDRs:
    - 192.168.1.0/24
    - fd12::1:100/120
    providerID: baremetal://10.2.0.5
  status:
    addresses:
    - address: 10.2.0.5
      type: InternalIP
    - address: fd12::2:5
      type: InternalIP

מציגים ברשימה את ה-Pods באשכול:

kubectl --kubeconfig CLUSTER_KUBECONFIG get pods --all-namespaces

בוחרים פוד אחד ומפרטים את הפרטים שלו. לדוגמה:

kubectl --kubeconfig CLUSTER_KUBECONFIG get pod gke-metrics-agent-b9qrv \
  --namespace kube-system \
  -- output yaml

בפלט אפשר לראות את כתובות ה-IPv4 וה-IPv6 של ה-Pod. לדוגמה:

apiVersion: v1
kind: Pod
metadata:
  ...
  name: gke-metrics-agent-b9qrv
  namespace: kube-system
...
status:
  ...
  podIPs:
  - ip: 192.168.1.146
  - ip: fd12::1:11a

וריאציות של שימוש ב-ClusterCIDRConfig

בדוגמה הקודמת השתמשנו באובייקט ClusterCIDRConfig כדי לציין טווחי CIDR של Pod בכל האשכול. כלומר, טווח CIDR יחיד של IPv4 משמש את כל ה-Pods באשכול. בנוסף, טווח CIDR יחיד של IPv6 משמש את כל ה-Pods באשכול.

במצבים מסוימים, יכול להיות שלא תרצו להשתמש בטווח CIDR יחיד לכל הפודים באשכול. לדוגמה, יכול להיות שתרצו לציין טווח CIDR נפרד לכל מאגר צמתים, או טווח CIDR נפרד לכל צומת. מידע נוסף על ClusterCIDRConfig ודוגמאות לשימוש בו זמינים במאמר הסבר על משאב מותאם אישית ClusterCIDRConfig.

לדוגמה, הפקודה ClusterCIDRConfig הבאה מציינת טווח CIDR למאגר צמתים בשם "workers".

apiVersion: baremetal.cluster.gke.io/v1alpha1
kind: ClusterCIDRConfig
metadata:
  name: "worker-pool-ccc"
  namespace: "cluster-dual-stack"
spec:
  ipv4:
    cidr: "192.168.0.0/16"
    perNodeMaskSize: 24
  ipv6:
    cidr: "fd12::1:0/112"
    perNodeMaskSize: 120
  nodeSelector:
    matchLabels:
      baremetal.cluster.gke.io/node-pool: "workers"

בדוגמה הבאה, ClusterCIDRConfig מציין טווח CIDR לצומת יחיד עם כתובת ה-IP 10.2.0.5:

apiVersion: baremetal.cluster.gke.io/v1alpha1
kind: ClusterCIDRConfig
metadata:
  name: "range-node1"
  namespace: "cluster-dual-stack"
spec:
  ipv4:
    cidr: "192.168.1.0/24"
    perNodeMaskSize: 24
  ipv6:
    cidr: "fd12::1:0/120"
    perNodeMaskSize: 120
  nodeSelector:
    matchLabels:
      baremetal.cluster.gke.io/k8s-ip: "10.2.0.5"

יצירת שירות עם מחסנית כפולה מסוג ClusterIP

זוהי דוגמה למניפסט של פריסה:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: "my-deployment"
spec:
  selector:
    matchLabels:
      app: "try-dual-stack"
  replicas: 3
  template:
    metadata:
      labels:
        app: "try-dual-stack"
    spec:
      containers:
      - name: "hello"
        image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"

שומרים את קובץ המניפסט בקובץ בשם my-deployment.yaml ויוצרים את הפריסה:

kubectl --kubeconfig CLUSTER_KUBECONFIG apply -f my-deployment.yaml

מחליפים את CLUSTER_KUBECONFIG בנתיב של קובץ ה-kubeconfig של האשכול.

זוהי דוגמה למניפסט של שירות מסוג ClusterIP:

apiVersion: v1
kind: Service
metadata:
  name: "my-service"
spec:
  selector:
    app: "try-dual-stack"
  type: "ClusterIP"
  ipFamilyPolicy: "RequireDualStack"
  ipFamilies:
  - "IPv6"
  - "IPv4"
  ports:
  - port: 80
    targetPort: 8080

במסגרת התרגיל הזה, אלה הנקודות העיקריות שחשוב להבין לגבי מניפסט השירות שמוצג למעלה:

  • השדה ipFamilyPolicy מוגדר לערך RequireDualStack. המשמעות היא שגם כתובות IPv6 וגם כתובות IPv4 ClusterIP מוקצות לשירות.

  • בשדה ipFamilies מצוינת קודם משפחת IPv6 ואחר כך משפחת IPv4. כלומר, spec.ClusterIP עבור השירות תהיה כתובת IPv6 שנבחרה מתוך clusterNetwork.services.cidrBlocks במניפסט של האשכול.

שומרים את המניפסט בקובץ בשם my-cip-service.yaml ויוצרים את השירות:

kubectl --kubeconfig CLUSTER_KUBECONFIG apply -f my-cip-service.yaml

פרטים על השירות:

kubectl --kubeconfig CLUSTER_KUBECONFIG get service my-service --output yaml

בפלט, אפשר לראות את כתובות ה-IP של האשכול בשביל השירות. לדוגמה:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  …
spec:
  clusterIP: fd12::5:9af
  clusterIPs:
  - fd12::5:9af
  - 172.16.12.197

בצומת של אשכול, קוראים לשירות:

curl IPV4_CLUSTER_IP
curl IPV6_CLUSTER_IP

הפלט יציג את ההודעה Hello world:

Hello, world!
Version: 2.0.0
Hostname: my-deployment-xxx

יצירת שירות עם מחסנית כפולה מסוג LoadBalancer

זוהי דוגמה למניפסט של שירות מסוג LoadBalancer:

apiVersion: v1
kind: Service
metadata:
  name: "my-lb-service"
spec:
  selector:
    app: "try-dual-stack"
  type: "LoadBalancer"
  ipFamilyPolicy: "RequireDualStack"
  ipFamilies:
  - "IPv6"
  - "IPv4"
  ports:
  - port: 80
    targetPort: 8080

שומרים את המניפסט בקובץ בשם my-lb-service.yaml ויוצרים את השירות:

kubectl --kubeconfig CLUSTER_KUBECONFIG apply -f my-lb-service.yaml

כזכור, במניפסט של האשכול ציינתם טווח של כתובות IPv6 וטווח של כתובות IPv4 לשימוש בשירותים מסוג LoadBalancer:

  loadBalancer:
    mode: "bundled"
    ...
    addressPools:
    - name: "pool-1"
      addresses:
      - "10.2.0.112-10.2.0.221"
      - "fd12::4:101-fd12::4:110"

לשירות שלכם תוקצה כתובת IPv4 חיצונית שנבחרה מתוך טווח ה-IPv4 וכתובת IPv6 חיצונית שנבחרה מתוך טווח ה-IPv6.

מפרטים את הפרטים של השירות:

kubectl --kubeconfig CLUSTER_KUBECONFIG get service my-lb-service --output yaml

בפלט, אפשר לראות את הכתובות החיצוניות של השירות. לדוגמה:

apiVersion: v1
kind: Service
metadata:
  name: my-lb-service
...
status:
  loadBalancer:
    ingress:
    - ip: 10.2.0.213
    - ip: fd12::4:101

ערכים אפשריים של ipFamilyPolicy

כשיוצרים שירות עם תמיכה כפולה במצבי כתובות, אפשר להגדיר את ipFamilyPolicy לאחד מהערכים הבאים:

  • SingleStack: בקר המערכת מקצה כתובת IP של אשכול לשירות, שנבחרת מתוך הטווח הראשון שצוין במניפסט של האשכול בקטע clusterNetwork.services.cidrBlocks.

  • PreferDualStack: בקר המערכת מקצה כתובות IP של IPv4 ו-IPv6 לאשכול עבור השירות, שנבחרו מתוך הטווחים שצוינו במניפסט של האשכול בקטע clusterNetwork.services.cidrBlocks. אם האשכול הוא לא אשכול עם תמיכה כפולה, ההתנהגות זהה לזו של SingleStack.

  • RequireDualStack: בקר המערכת מקצה כתובות IP של אשכולות בפורמט IPv4 ו-IPv6 לשירות, שנבחרו מתוך הטווחים שצוינו במניפסט של האשכול בקטע clusterNetwork.services.cidrBlocks. הוא מגדיר את הערך של spec.clusterIP על סמך משפחת הכתובות הראשונה שצוינה במניפסט השירות בקטע ipFamilies.

מידע נוסף

מידע נוסף על יצירת שירותים עם תמיכה ב-IPv4 ו-IPv6 זמין במאמר אפשרויות של שירותים חדשים עם תמיכה ב-IPv4 ו-IPv6.