הגדרת הכוונת שירותים

בדף הזה מוסבר איך להגדיר את התכונה 'הפניית תנועה לשירותים' עבור ה-Pods.

כדי להבין איך פועל ניהול התעבורה בין שירותים, אפשר לעיין במאמר איך פועל ניהול התעבורה בין שירותים.

דרישות

  • GKE בגרסה 1.30 ואילך.

מגבלות

  • ל-ServiceFunctionChain יכולה להיות פונקציית שירות אחת לכל היותר.
  • מומלץ להשתמש במקסימום 100 צמתים בתוספת 10 זוגות של ServiceFunctionChain ו-TrafficSelector.
  • התכונה 'הפניית תנועה בשירות GKE' זמינה רק בצמתים שפועלת בהם תמונת הצומת של מערכת הפעלה שמותאמת לקונטיינרים.
  • התכונה 'הפניית תנועה בשירות GKE' תומכת רק בכתובות IP של יציאה ושל יעד.
  • התכונה 'הפניית תנועה לשירותים' לא מטפלת בקונפליקטים שמתעוררים כשמחילים על אותו נושא כמה TrafficSelector עם אורך קידומת זהה. כדי למנוע התנגשויות, מומלץ לתכנן מראש את בוררי התנועה עם טווחי כתובות IP שלא חופפים ועם קריטריונים ברורים לבחירה.

הטמעה של ניהול תעבורה בין שירותים

התכונה GKE Service Steering מאפשרת לכם להתאים אישית את זרימת תעבורת הרשת באשכול ולשלוט בה. בקטע הזה נסביר איך להטמיע את התכונה 'הפניית תנועה לשירותים' באמצעות דוגמה של שער אינטרנט.

נניח שאתם רוצים ליצור שער אינטרנט שמאבטח את התנועה ממכשירי לקוח של משתמשי קצה לאינטרנט. מסיים VPN מושך תנועה אל השער המנוהל באמצעות מנהרה מאובטחת. תנועת המשתמשים הסופיים מנותבת מחדש לחומת האש ואז לשרת הפרוקסי. הפרוקסי מבצע תרגום של כתובת הרשת של המקור (SNAT) בתעבורת הנתונים, מסווה את כתובת המקור המקורית ושולח אותה לאינטרנט.

כדי להטמיע את התכונה 'הפניית תנועה לשירותים' ב-GKE, צריך לבצע את הפעולות הבאות:

  1. יוצרים VPC עם MTU של 8896.
  2. יוצרים אשכול GKE.
  3. יוצרים את ה-Pods של פונקציית השירות ואת השירות.
  4. יוצרים את ServiceFunctionChain.
  5. יוצרים את המשאב TrafficSelector שמפנה אל ServiceFunctionChain.

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

לפני שמתחילים, חשוב לוודא שביצעתם את הפעולות הבאות:

  • מפעילים את ממשק ה-API של Google Kubernetes Engine.
  • הפעלת Google Kubernetes Engine API
  • אם רוצים להשתמש ב-CLI של Google Cloud למשימה הזו, צריך להתקין ואז להפעיל את ה-CLI של gcloud. אם התקנתם בעבר את ה-CLI של gcloud, מריצים את הפקודה gcloud components update כדי לקבל את הגרסה העדכנית. יכול להיות שגרסאות קודמות של ה-CLI של gcloud לא יתמכו בהרצת הפקודות שמופיעות במסמך הזה.

הכנת VPC

מכינים VPC. התכונה Service Steering משתמשת באנקפסולציה כדי להפנות את התנועה לפונקציות השירות המתאימות. אנקפסולציה כוללת הוספה של כותרות נוספות לכל מנה, מה שמגדיל את גודל המנה. לא נדרשת הגדרה מיוחדת ב-VPC כדי להשתמש בהפניית תנועה לשירותים. במהלך ההכנה של VPC, מומלץ לקחת בחשבון את התקורה של האנקפסולציה כשקובעים את גודל MTU. מידע נוסף זמין במאמר רשת VPC עם MTU מוגדר.

הפקודה הבאה מגדירה את גודל ה-MTU ב-VPC:

gcloud compute networks create VPC_NETWORK_NAME --mtu=8896

מחליפים את VPC_NETWORK_NAME בשם של רשת ה-VPC שמכילה את רשת המשנה.

יצירת אשכול GKE

כדי להפעיל את היכולות המתקדמות של ניהול כתובות IP וניתוב רשת שנדרשות להטמעה של Service Steering ב-GKE, צריך ליצור אשכול GKE עם GKE Dataplane V2 באופן הבא:

gcloud container clusters create CLUSTER_NAME \
    --network VPC_NAME \
    --release-channel RELEASE_CHANNEL \
    --cluster-version CLUSTER_VERSION \
    --enable-dataplane-v2 \
    --enable-ip-alias

מחליפים את מה שכתוב בשדות הבאים:

  • CLUSTER_NAME: שם האשכול.
  • VPC_NAME: השם של ה-VPC שאליו רוצים לשייך את האשכול.
  • RELEASE_CHANNEL: שם ערוץ ההפצה.
  • VERSION: גרסת GKE, שצריכה להיות 1.30 ואילך. אפשר גם להשתמש בדגל --release-channel כדי לבחור ערוץ הפצה. לגרסת הערוץ צריכה להיות גרסת ברירת מחדל 1.30 ומעלה.

יצירת ServiceFunction תרמילים

כדי ליצור את שרשרת השירותים, צריך לפרוס את ה-Pod של ה-VPN terminator ואת ה-Pods של פונקציות השירות הנדרשות בתוך האשכול. ‫Pods מכילים את האפליקציות בקונטיינרים שמבצעות את הפונקציות של הרשת.

ה-Pod של VPN terminator הוא לרוב פונקציית השירות הראשונה בשרשרת, שמסיימת את התנועה שנכנסת לאשכול דרך ה-VPN. לאחר מכן, הוא מכוון את פונקציות השירות האחרות, כמו חומות אש ואיזון עומסים, לעיבוד נוסף לפני ההגעה ליעד הסופי.

בקובץ התצורה לדוגמה הבא מוגדרים שלושת הרכיבים הבאים, שחיוניים לניהול תנועה ברשת באשכול:

  • VPN Pod: יוצר נקודת קצה של רשת וירטואלית פרטית (VPN) בתוך האשכול, שמאפשרת תקשורת מאובטחת ומוצפנת בין האשכול לבין רשתות חיצוניות.
  • פריסת חומת אש: פריסה של כמה עותקים של Pod של חומת אש, שמספקים אבטחה ואיזון עומסים.
  • Proxy DaemonSet: פורס Pod של proxy בכל צומת של האשכול, כדי להבטיח שאפשר לעבד את תעבורת הרשת באופן מקומי לפני שהיא מועברת לשירותים אחרים כמו חומת אש.

שומרים את קובץ המניפסט לדוגמה הבא בשם service_function.yaml:

apiVersion: v1
kind: Pod
  name: vpn
  namespace: vpn
  labels:
    app: vpn
spec:
  containers:
  -   name: vpn
    image: openvpn
    ports:
    -   containerPort: 51820
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: firewall
  namespace: firewall
spec:
  replicas: 3
  selector:
    matchLabels:
      app: firewall
  template:
    metadata:
      labels:
        app: firewall
    spec:
      containers:
      -   name: firewall
        image: firewall
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: proxy
  namespace: proxy
spec:
  selector:
    matchLabels:
      app: proxy
  template:
    metadata:
      labels:
        app: proxy
    spec:
      containers:
      -   name: proxy
        image: proxy

החלת המניפסט:

kubectl apply -f service_function.yaml

יצירת ServiceFunctionChains

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

שומרים את קובץ המניפסט לדוגמה הבא בשם ServiceFunctionChain.yaml:

apiVersion: networking.gke.io/v1
kind: ServiceFunctionChain
metadata:
  name: firewall
spec:
  sessionAffinity:
    clientIpNoDestination:
      timeoutSeconds: 3600 # 1hr
  serviceFunctions:
  -   name: firewall
    namespace: firewall
    podSelector:
      matchLabels:
        app: firewall
---
apiVersion: networking.gke.io/v1
kind: ServiceFunctionChain
metadata:
  name: proxy
spec:
  sessionAffinity:
    clientIpNoDestination: {}
  serviceFunctions:
  -   name: proxy
    namespace: proxy
    podSelector:
      matchLabels:
        app: proxy

החלת המניפסט:

kubectl apply -f ServiceFunctionChain.yaml

פונקציות השירות מוגדרות בשורה בתוך ServiceFunctionChain באמצעות השדה serviceFunctions. פונקציית שירות היא בורר נקודות קצה.

יצירת משאב TrafficSelector

כדי להגדיר איפה ואיזו תנועה נבחרת לניתוב תנועה לשירותים, יוצרים את המשאב TrafficSelector שמפנה אל ServiceFunctionChains כדי להחיל אותו על התנועה שנבחרה.

שומרים את קובץ המניפסט לדוגמה הבא בשם TrafficSelector.yaml:

apiVersion: networking.gke.io/v1
kind: TrafficSelector
metadata:
  name: vpn-to-firewall
spec:
  serviceFunctionChain: firewall
  subject:
    pods:
      namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: vpn
      podSelector:
        matchLabels:
          app: vpn
  egress:
    to:
      ipBlock:
        cidr: 0.0.0.0/0
    ports:
    -   allPorts:
        protocol: UDP
    -   allPorts:
        protocol: TCP
---
apiVersion: networking.gke.io/v1
kind: TrafficSelector
metadata:
  name: firewall-to-proxy
spec:
  serviceFunctionChain: proxy
  subject:
    pods:
      namespaceSelector:
        kubernetes.io/metadata.name: firewall
      podSelector:
        app: firewall
  egress:
    to:
      ipBlock:
        cidr: 0.0.0.0/0
    ports:
    -   allPorts:
        protocol: UDP
    -   allPorts:
        protocol: TCP

החלת המניפסט:

kubectl apply -f TrafficSelector.yaml

פתרון בעיות שקשורות לניתוב שירותים

בקטע הזה מוסבר איך לפתור בעיות שקשורות ל-GKE Service Steering.

התנועה ברשת לא זורמת

כדי לנפות את הבעיה, אפשר לבצע את הפעולות הבאות:

שלב 1: מוודאים שההגדרה servicePathId מוגדרת ב-ServiceFunctionChain

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

apiVersion: networking.gke.io/v1
kind: ServiceFunctionChain
metadata:
  name: firewall
spec:
  serviceFunctions:
  - name: firewall
    namespace: firewall
    podSelector:
      matchLabels:
        app: firewal
status:
  servicePathId: 1

שלב 2: מוודאים שנוצר שירות Kubernetes לכל פונקציית שירות

שירות ClusterIP נוצר באופן אוטומטי לכל פונקציית שירות. אפשר לראות את רשימת השירותים באמצעות kubectl:

kubectl get svc -A -l networking.gke.io/managed-by=service-steering-controller.gke.io

שלב 3: מוודאים שנוצרת רשומת מיפוי של bpf בכל צומת כדי לאחסן את כתובת ה-IP של הפונקציה של כל שירות

לכל פונקציית שירות נוצרת רשומה במפת ה-BPF בכל צומת כדי לאחסן את כתובת ה-IP של השירות.

כדי לקבל את השם של anetd ה-Pod:

kubectl get pods -n kube-system -o wide -l k8s-app=cilium

רושמים את השם של ה-Pod, למשל anetd.

מריצים את הפקודה הבאה:

kubectl -n kube-system exec -it ANETD-POD-NAME -- cilium bpf sfcpath list

מחליפים את ANETD-POD-NAME בשם של ה-Pod‏ anetd.

הפלט אמור להיראות כך:

PATH     SERVICE FUNCTION ADDRESS
(1, 1)   10.4.10.124

שלב 4: מוודאים שנוצרו רשומות של מיפוי bpf במפה sfcselect

בצומת, אם יש פודים שנבחרו על ידי TrafficSelector, נוצרות רשומות של מפת bpf במפה sfcselect. בדוגמה הבאה אפשר לראות שתנועת TCP/UDP מכל יציאה של נקודת הקצה (Pod) 3783 לכתובת ה-IP של היעד 10.0.2.12 מנותבת אל ServiceFunctionChain.

מריצים את הפקודה הבאה:

kubectl -n kube-system exec -it ANETD-POD-NAME -- cilium bpf sfcselect list

מחליפים את ANETD-POD-NAME בשם בפועל של ה-Pod של anetd באשכול.

הפלט אמור להיראות כך:

SELECTOR                            PATH
3783, egress, 0/TCP, 10.0.2.12/32   /32 (1, 1)
3783, egress, 0/UDP, 10.0.2.12/32   /32 (1, 1)

שלב 5: שימוש ב-tcpdump ביציאה 7081 כדי ללכוד ולנתח את תעבורת הרשת

התכונה 'ניתוב שירותים' מבצעת אנקפסולציה של Geneve ביציאת UDP‏ 7081. אפשר להשתמש ב-tcpdump בצמתים הרלוונטיים כדי לנתח את זרימת התנועה ולזהות את המקום שבו הבעיה מתרחשת.

המאמרים הבאים