העברת Ingress ל-Gateway API

בדף הזה מוסבר איך להעביר את ניהול התעבורה ב-Google Kubernetes Engine ‏ (GKE) מ-Ingress API ל-Gateway API. ‫Gateway API הוא פתרון מנוהל מלא Google Cloud לטיפול בתנועת הנתונים של האפליקציה.

כדי לצמצם את זמן ההשבתה ולהפחית את הסיכון, הדרך הכי יעילה להעביר ל-Gateway API היא להריץ בו-זמנית את ההגדרות הקיימות של Ingress API ושל Gateway API החדש. השיטה הזו מאפשרת לבצע בדיקה יסודית של הגדרת השער החדשה בסביבה פעילה בלי להשפיע על השירותים הנוכחיים. אחרי שמאמתים את ההגדרה החדשה של Gateway, אפשר לבצע מעבר מהיר של DNS כדי להפנות את התנועה ל-Gateway API, וכך להבטיח מעבר חלק עם סיכון נמוך.

ככלל, אסטרטגיית ההעברה כוללת את השלבים הבאים:

  1. מגדירים את מאזן העומסים החדש.
  2. הגדרת כללים לטיפול בתנועה נכנסת.
  3. פורסים את ההגדרה החדשה ובודקים את זרימת התנועה לכתובת ה-IP החדשה של השער.
  4. מעבירים את תנועת הגולשים בסביבת הייצור אל Gateway API.
  5. מחיקת משאבי Ingress שנותרו.

הגדרת מאזן העומסים החדש

בשלב הזה פורסים משאב Kubernetes Gateway כדי לאזן עומסים באשכול GKE. כשפורסים משאב Gateway, ‏GKE מגדיר מאזן עומסים של אפליקציות (ALB) בשכבה 7 כדי לחשוף תנועת HTTP(S) לאפליקציות שפועלות באשכול. פורסים משאב Gateway אחד לכל אשכול או לכל מאזן עומסים שצריך.

בדוגמה הבאה מוגדר מאזן עומסים גלובלי חיצוני של אפליקציות (ALB). כדי ליצור שער, שומרים את המניפסט הבא בתור gateway.yaml:

kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
  name: external-http-gateway
spec:
  gatewayClassName: gke-l7-global-external-managed # GKE's managed external Application Load Balancer
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: Same # Only allow HTTPRoutes from the same namespace

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

  • ‫gatewayClassName: gke-l7-global-external-managed: מציין את GatewayClass של השער הזה. במחלקה הזו של Gateway נעשה שימוש במאזן עומסים גלובלי חיצוני של אפליקציות (ALB).
  • ‫protocol: HTTP ו-port: 80: מציינים ששער הגישה חושף את יציאה 80 לתעבורת HTTP.

הגדרת כללי תנועה לתנועה נכנסת

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

בשלב הזה, מתרגמים את מניפסט ה-Ingress למשאב HTTPRoute. כדי להמיר את המניפסט של Ingress, פועלים לפי השלבים בכלי ingress2gateway.

בדוגמה הזו אנחנו מניחים שיש לכם את משאב ה-Ingress הבא:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: cafe-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: cafe.example.com
    http:
      paths:
      - path: /tea
        pathType: Prefix
        backend:
          service:
            name: tea-svc
            port:
              number: 80
      - path: /coffee
        pathType: Prefix
        backend:
          service:
            name: coffee-svc
            port:
              number: 80

אחרי שממירים את המניפסט באמצעות הכלי ingress2gateway, הפלט הוא המניפסט המתורגם של HTTPRoute.

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

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: cafe-route
spec:
  # This route attaches to our new Gateway
  parentRefs:
  - name: external-http-gateway
  # The hostname is the same as before
  hostnames:
  - "cafe.example.com"
  # The routing rules are now more explicit
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /tea
    backendRefs:
    - name: tea-svc
      port: 80
  - matches:
    - path:
        type: PathPrefix
        value: /coffee
    backendRefs:
    - name: coffee-svc
      port: 80

שימו לב: השדה rules במניפסט של HTTPRoute תואם ישירות לכללי מסלול שהוגדרו במניפסט המקורי של Ingress.

פריסה ובדיקה של ההגדרה החדשה

בשלב הזה, מחילים את המניפסטים של Gateway ו-HTTPRoute שיצרתם בשני השלבים הקודמים, ובודקים שהתנועה זורמת לכתובת ה-IP החדשה של Gateway.

  1. מחילים את המניפסטים של Gateway ו-HTTPRoute:

    kubectl apply -f gateway.yaml
    kubectl apply -f httproute.yaml
    
  2. משיגים את כתובת ה-IP של השער. יכול להיות שיעברו כמה דקות עד שהקצאת כתובת ה-IP תושלם:

    kubectl get gateway external-http-gateway -o=jsonpath="{.status.addresses[0].value}" --watch
    

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

  3. בודקים את כתובת ה-IP החדשה של השער. משתמשים בפקודה curl הבאה כדי לשלוח בקשה לכתובת ה-IP ולציין את שם המארח cafe.example.com. לדוגמה:

    curl --resolve cafe.example.com:80:203.0.113.90 http://cafe.example.com/tea
    curl --resolve cafe.example.com:80:203.0.113.90 http://cafe.example.com/coffee
    

    מחליפים את 203.0.113.90 בכתובת ה-IP החיצונית שקיבלתם בשלב הקודם. הפלט מאשר שכתובת ה-IP החדשה של השער מנתבת בצורה נכונה את התנועה אל cafe.example.com בלי לבצע חיפוש DNS.

הפניית תנועה לכתובת ה-IP החדשה של השער

בשלב הזה, מעבירים את תעבורת הנתונים בזמן אמת מה-Ingress הקודם אל ה-Gateway החדש. כדי לעשות את זה, מעדכנים את רשומות ה-DNS כך שיפנו לכתובת ה-IP של ה-Gateway החדש. השלבים המדויקים לעדכון רשומות DNS משתנים בהתאם לספק ה-DNS.

לדוגמה, אם הגדרתם cafe.example.com ב-Ingress, צריך לאתר את רשומת A של cafe.example.com אצל ספק ה-DNS ולשנות את הערך של כתובת ה-IP הישנה של Ingress ל-203.0.113.90, שהיא כתובת ה-IP החדשה של שער הכניסה.

אחרי שמעדכנים את רשומת ה-DNS, התנועה מתחילה לעבור מ-Ingress ל-Gateway, אבל המעבר לא מתרחש באופן מיידי אצל כל הלקוחות. מפענחי DNS ששמרו במטמון את הרשומה הקודמת ממתינים עד שיפוג ערך משך החיים (TTL) של הרשומה, לפני שהם שולחים שוב שאילתה לגבי הרשומה ומקבלים את כתובת ה-IP המעודכנת. לכן, כדאי להמשיך להריץ את ה-Ingress הקיים ואת ה-Gateway החדש במקביל עד שמוודאים שהתנועה ל-Ingress פסקה, מה שמצביע על כך שהפצת ה-DNS הושלמה והלקוחות כבר לא מופנים לכתובת ה-IP הישנה. כדי לוודא זאת, אפשר לעקוב אחרי התנועה במאזן העומסים או בבקר Ingress. מידע נוסף מופיע במאמר בנושא בדיקת ההפצה של DNS.

אם אתם משתמשים ב-Cloud DNS, אתם יכולים להשתמש במשקלים של יעדים כדי להעביר את תעבורת הנתונים בהדרגה מכתובת ה-IP הישנה לכתובת ה-IP החדשה. מידע נוסף זמין במאמר בנושא הגדרה של מדיניות ניתוב DNS ובדיקות תקינות.

מחיקת משאבי Ingress שנותרו

אחרי שמוודאים שהשער החדש פועל בצורה תקינה, מנקים את משאבי ה-Ingress הישנים.

  1. מוחקים את משאב ה-Ingress:

    kubectl delete ingress cafe-ingress
    
  2. מסירים את הבקר ingress-nginx. לדוגמה, אם השתמשתם ב-Helm כדי להתקין את בקר, מריצים את הפקודה הבאה:

    helm uninstall ingress-nginx -n ingress-nginx
    

השוואת תכונות בין Ingress NGINX לבין GKE Gateway

‫Gateway API מספק דרך סטנדרטית יותר להגדרת תעבורת נכנסת, ויש לו תכונות מקבילות לרוב התכונות הנפוצות כמו ניתוב, כותרות ופיצול תעבורה.

בטבלה הבאה מוצגת השוואה בין ההגדרות שמשמשות לתכונות נפוצות ב-Ingress controller וב-Gateway API.

תכונה הערה ב-Ingress הגדרה ב-GKE Gateway זוגיות
ניתוב מבוסס-מארח השדה spec.rules.host באובייקט Ingress. השדה hostnames באובייקט HTTPRoute. שוויון מלא.
ניתוב מבוסס-נתיב השדה spec.rules.http.paths באובייקט Ingress. השדה rules.matches.path באובייקט HTTPRoute. שוויון מלא.
חלוקת התנועה nginx.ingress.kubernetes.io/canary הערות. ‫HTTPRoute עם השדה המשוקלל backendRefs. שוויון מלא. בנוסף, אפשר לפצל את התנועה עם בקרה מדויקת.
זיקה לסשן (session affinity) ‫nginx.ingress.kubernetes.io/affinity ו-nginx.ingress.kubernetes.io/affinity-mode הערות. ‫GCPTrafficDistributionPolicy עם השדה sessionAffinity. שוויון מלא. ‫GKE Gateway תומך בכמה סוגים של זיקה לסשן (session affinity), כולל סוגים של זיקה מבוססת-קובץ Cookie ‏(HTTP_COOKIE,‏ GENERATED_COOKIE ו-עם שמירת מצב‏ STRONG_COOKIE_AFFINITY), זיקה מבוססת-כותרת (HEADER_FIELD) וזיקה מבוססת-כתובת IP של לקוח (CLIENT_IP).
CORS (שיתוף משאבים בין מקורות) nginx.ingress.kubernetes.io/enable-cors ‫HTTPRoute עם מסנן CORS. שוויון מלא. הערה: ל-GKE Gateway יש מגבלות על מספר התבניות של תווים כלליים שאפשר להגדיר לכל מאזין או שם מארח
שכתוב של כתובות URL nginx.ingress.kubernetes.io/rewrite-target ‫HTTPRoute עם מסנן urlRewrite. שוויון חלקי. שער GKE תומך רק בהחלפות של קידומות.
מניפולציה של כותרות nginx.ingress.kubernetes.io/proxy-set-headers או add-headers ‫HTTPRoute עם משנה requestHeaderModifier או מסנן responseHeaderModifier. שוויון מלא.
אימות ‫nginx.ingress.kubernetes.io/auth-url לאימות חיצוני.
  • שרת proxy לאימות זהויות (IAP): משאב בהתאמה אישית של GCPBackendPolicy.
  • אחר: נדרשת גישה מותאמת אישית יותר, אולי עם Service mesh או מסננים בהתאמה אישית.
שוויון חלקי. שרת proxy לאימות זהויות (IAP) הוא הדרך המומלצת לאבטח את השער, והוא מוגדר בקצה העורפי.

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