יצירת שירות ו-Ingress

במאמר הזה מוסבר איך ליצור אובייקט Ingress של Kubernetes באשכול משתמש, באשכול היברידי או באשכול עצמאי ב-Google Distributed Cloud. ‫Ingress משויך לשירותים אחדים או יותר, וכל אחד מהם משויך לקבוצה של Pods.

יצירת פריסה

כדי ליצור פריסה:

  1. יוצרים מניפסט פריסה:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-deployment
    spec:
      selector:
        matchLabels:
          greeting: hello
      replicas: 3
      template:
        metadata:
          labels:
            greeting: hello
        spec:
          containers:
          - name: hello-world
            image: "gcr.io/google-samples/hello-app:2.0"
            env:
            - name: "PORT"
              value: "50000"
          - name: hello-kubernetes
            image: "gcr.io/google-samples/node-hello:1.0"
            env:
            - name: "PORT"
              value: "8080"
    

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

    • לכל Pod ששייך לפריסה יש את התווית greeting: hello.

    • לכל Pod יש שני קונטיינרים.

    • השדות env מציינים שהקונטיינרים hello-app מאזינים ליציאת TCP ‏50000, והקונטיינרים node-hello מאזינים ליציאת TCP ‏8080. ב-hello-app, אפשר לראות את ההשפעה של משתנה הסביבה PORT על ידי עיון בקוד המקור.

  2. מעתיקים את המניפסט לקובץ בשם hello-deployment.yaml.

  3. יוצרים את הפריסה:

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

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

חשיפת הפריסה באמצעות שירות

כדי לספק ללקוחות דרך יציבה לשליחת בקשות ל-Pods של הפריסה, צריך ליצור Service:

  1. יוצרים מניפסט של שירות שחושף את הפריסה ללקוחות בתוך האשכול:

    apiVersion: v1
    kind: Service
    metadata:
      name: hello-service
    spec:
      type: ClusterIP
      selector:
        greeting: hello
      ports:
      - name: world-port
        protocol: TCP
        port: 60000
        targetPort: 50000
      - name: kubernetes-port
        protocol: TCP
        port: 60001
        targetPort: 8080
    
  2. מעתיקים את המניפסט לקובץ בשם hello-service.yaml.

  3. יוצרים את השירות:

    kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f hello-service.yaml
    

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

  4. צפייה בשירות:

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

    בפלט מוצג הערך של clusterIP שניתן לשירות. לדוגמה:

    apiVersion: v1
    kind: Service
    metadata:
      annotations:
        ...
    spec:
      clusterIP: 10.96.14.249
      clusterIPs:
      - 10.96.14.249
      ipFamilies:
      - IPv4
      ipFamilyPolicy: SingleStack
      ports:
      - name: world-port
        port: 60000
        protocol: TCP
        targetPort: 50000
      - name: kubernetes-port
        port: 60001
        protocol: TCP
        targetPort: 8080
      selector:
        greeting: hello
      sessionAffinity: None
      type: ClusterIP
    status:
      loadBalancer: {}
    

    בפלט שלמעלה, השדה ports הוא מערך של אובייקטים מסוג ServicePort: אחד שנקרא world-port ואחד שנקרא kubernetes-port. למידע נוסף על שדות השירות, אפשר לעיין במאמר ServiceSpec במסמכי העזרה של Kubernetes.

    אלה הדרכים שבהן לקוח יכול להתקשר לשירות:

    • שימוש ב-world-port: לקוח שפועל באחד מצמתי האשכול שולח בקשה ל-clusterIP ב-port (לדוגמה, 10.96.14.249:60000). בקר ה-Ingress מעביר את הבקשה ל-Pod של חבר ב-targetPort (לדוגמה, POD_IP_ADDRESS:50000, כאשר POD_IP_ADDRESS היא כתובת ה-IP של Pod של חבר).

    • שימוש ב-kubernetes-port: לקוח שפועל באחד מצמתי האשכול שולח בקשה אל clusterIP ב-port (10.96.14.249:60001). בקר ה-Ingress מעביר את הבקשה אל Pod חבר ב-targetPort (POD_IP_ADDRESS:8080).

רכיבי Ingress

אלה כמה מרכיבים של האשכול שקשורים ל-ingress:

אפשר לקרוא מידע על הגדרה של רשת שירותים שפועלת באופן מלא.
  • istio-ingress פריסה. זהו שרת ה-proxy של הכניסה. שרת ה-proxy של Ingress מעביר את התנועה לשירותים פנימיים בהתאם לכללים שצוינו באובייקט Ingress.

  • השירות istio-ingress. השירות הזה חושף את הפריסה של istio-ingress.

  • istiod פריסה. זהו בקר הכניסה. בקר הכניסה עוקב אחרי יצירת אובייקטים של Ingress ומגדיר את פרוקסי הכניסה בהתאם.

כל הרכיבים האלה של Istio בתוך האשכול מותקנים במרחב השמות gke-system. מרחב השמות הזה לא מתנגש עם התקנה מלאה של Istio או Cloud Service Mesh.

יצירת Ingress

כדי ליצור Ingress:

  1. יוצרים מניפסט של Ingress:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-ingress
    spec:
      rules:
      - http:
          paths:
          - path: /greet-the-world
            pathType: Exact
            backend:
              service:
                name: hello-service
                port:
                  number: 60000
          - path: /greet-kubernetes
            pathType: Exact
            backend:
              service:
                name: hello-service
                port:
                  number: 60001
    
  2. מעתיקים את המניפסט לקובץ בשם my-ingress.yaml.

  3. יוצרים את ה-Ingress:

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

כשיוצרים אשכול משתמשים, מציינים ערך ל-loadbalancer.ingressVIP בקובץ התצורה של האשכול. כתובת ה-IP הזו מוגדרת במאזן העומסים של האשכול. כשיוצרים Ingress, כתובת ה-IP החיצונית שלו היא אותה כתובת VIP.

כשלקוח שולח בקשה לכתובת ה-VIP של Ingress אשכול המשתמשים, הבקשה מנותבת למאזן העומסים (LB). מאזן העומסים משתמש בשירות istio-ingress כדי להעביר את הבקשה ל-ingress proxy, שפועל באשכול המשתמשים. ה-proxy של הכניסה מעביר את הבקשה לקצה העורפי אחר בהתאם לנתיב בכתובת ה-URL של הבקשה.

הנתיב /greet-the-world

במניפסט של Ingress, אפשר לראות כלל שאומר שהנתיב /greet-the-world משויך ל-serviceName: hello-service ול-servicePort: 60000. תזכורת: 60000 הוא הערך של port בworld-port בקטע hello-service Service.

- name: world-port
    port: 60000
    protocol: TCP
    targetPort: 50000

שירות הכניסה מעביר את הבקשה אל clusterIP:50000. הבקשה מועברת לאחד מה-Pods של חברי שירות hello-service. המכל, באותו Pod, שמקשיב ליציאה 50000, מציג הודעה Hello World!.

הנתיב /greet-kubernetes

במניפסט של Ingress, אפשר לראות כלל שאומר שהנתיב /greet-kubernetes משויך ל-serviceName: hello-service ול-servicePort: 60001. תזכורת: 60001 הוא הערך של port בקטע kubernetes-port של hello-service Service.

- name: kubernetes-port
    port: 60001
    protocol: TCP
    targetPort: 8080

שירות הכניסה מעביר את הבקשה אל clusterIP: 8080. הבקשה מועברת לאחד מה-Pods של חברי שירות hello-service. המכל ב-Pod הזה, שמקשיב ליציאה 8080, מציג הודעה Hello Kubernetes!.

בדיקת ה-Ingress

  1. בודקים את ה-Ingress באמצעות הנתיב /greet-the-world:

    curl CLUSTER_INGRESS_VIP/greet-the-world
    

    מחליפים את CLUSTER_INGRESS_VIP בכתובת ה-IP החיצונית של ה-Ingress.

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

    Hello, world!
    Version: 2.0.0
    Hostname: ...
    
  2. בודקים את ה-Ingress באמצעות הנתיב /greet-kubernetes:

    curl CLUSTER_INGRESS_VIP/greet-kubernetes
    

    הפלט יציג את ההודעה Hello, Kubernetes!:

    Hello Kubernetes!
    

השבתת חבילת Ingress

יכולת ה-Ingress שכלולה ב-Google Distributed Cloud תומכת רק ביכולות Ingress. אפשר לבחור לשלב עם Istio או עם Cloud Service Mesh. המוצרים האלה מציעים יתרונות נוספים של Service mesh פונקציונלית לחלוטין, כמו Transport Layer Security ‏(mTLS) הדדית, יכולת לנהל אימות בין שירותים וניראות (observability) של עומסי עבודה. אם אתם משלבים עם Istio או עם Cloud Service Mesh, מומלץ להשבית את יכולת ה-Ingress שכלולה בחבילה.

אפשר להפעיל או להשבית את חבילת ה-Ingress באמצעות השדה spec.clusterNetwork.bundledIngress בקובץ התצורה של האשכול. השדה הזה זמין רק באשכולות מגרסה 1.13.0 ואילך. ערך ברירת המחדל של השדה bundledIngress הוא true, והוא לא מופיע בקובץ התצורה של האשכול שנוצר. השדה הזה ניתן לשינוי, ואפשר לשנות אותו כשיוצרים או מעדכנים אשכול בגרסה 1.13.0 ומעלה.

  • כדי להשבית את יכולת ה-Ingress שכלולה בחבילה, מוסיפים את השדה bundledIngress לקטע clusterNetwork בקובץ התצורה של האשכול ומגדירים את הערך שלו כ-false, כמו בדוגמה הבאה:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: cluster-hybrid-basic
    ---
    apiVersion: baremetal.cluster.gke.io/v1
    kind: Cluster
    metadata:
      name: hybrid-basic
      namespace: cluster-hybrid-basic
    spec:
      type: hybrid
      profile: default
      anthosBareMetalVersion: 1.13.0
      gkeConnect:
        projectID: project-fleet
      controlPlane:
        nodePoolSpec:
          nodes:
          - address: 10.200.0.2
      clusterNetwork:
        bundledIngress: false
        pods:
          cidrBlocks:
          - 192.168.0.0/16
        services:
          cidrBlocks:
          - 10.96.0.0/20
    ...
    

הגדרת HTTPS ל-Ingress

אם רוצים לאשר בקשות HTTPS מהלקוחות, לשרת ה-proxy של הכניסה צריך להיות אישור כדי שיוכל להוכיח את הזהות שלו ללקוחות. לפרוקסי הזה צריך להיות גם מפתח פרטי כדי להשלים את לחיצת היד של HTTPS.

בדוגמה הבאה נעשה שימוש בישויות האלה:

  • Ingress proxy: Participates in the HTTPS handshake, and then forwards packets to member Pods of the hello-service Service.

  • הדומיין של שירות hello-service: altostrat.com בארגון לדוגמה

איך לעשות את זה?

  1. יוצרים אישור בסיס ומפתח פרטי. בדוגמה הזו נעשה שימוש ברשות אישורים בסיסית של root.ca.example.com ב-Root CA Example Org.

    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj \
        '/O=Root CA Example Inc./CN=root.ca.example.com' -keyout root-ca.key \
        -out root-ca.crt
    
  2. יוצרים בקשת חתימה על אישור:

     openssl req -out server.csr -newkey rsa:2048 -nodes -keyout server.key -subj \
         "/CN=altostrat.com/O=Example Org"
    
  3. יוצרים אישור להצגת תוכן עבור שרת ה-proxy של ה-ingress.

    openssl x509 -req -days 365 -CA root-ca.crt -CAkey root-ca.key -set_serial 0 \
        -in server.csr -out server.crt
    

    יצרתם עכשיו את האישורים והמפתחות הבאים:

    • root-ca.crt: אישור עבור ה-CA הבסיסי
    • ‫root-ca.key: מפתח פרטי עבור CA הבסיסי
    • server.crt: אישור שרת עבור פרוקסי Ingress
    • ‫server.key: מפתח פרטי לשרת ה-proxy של הכניסה
  4. יוצרים סוד של Kubernetes שמכיל את האישור ואת המפתח של השרת.

    kubectl create secret tls example-server-creds --key=server.key --cert=server.crt \
        --namespace gke-system
    

    הסוד שנוצר נקרא example-server-creds.

יצירת פריסה ושירות

אם יצרתם פריסה ושירות בחלק ה-HTTP של המדריך הזה, אל תסירו אותם. אם לא, צריך ליצור אותם עכשיו לפי השלבים שמתוארים לגבי HTTP.

יצירת Ingress

יצירת Ingress ל-HTTPS דומה ליצירת Ingress ל-HTTP, אבל מפרט ה-Ingress ל-HTTPS כולל קטע tls שמציין את המארח ואת הסוד. הערכים של hosts בקטע tls צריכים להיות זהים לערכים של host בקטע rules.

אם שירות ה-Backend נמצא במרחב שמות נפרד, צריך ליצור שירות מסוג ExternalName באותו מרחב שמות כמו Ingress, כדי לנתב את התנועה לשירות ה-Backend.

השלבים הכלליים ליצירת Ingress ל-HTTPS או ל-HTTP זהים, למעט מה שמגדירים בקובץ המניפסט:

  1. אם יצרתם בעבר Ingress בחלק ה-HTTP של המסמך הזה, מחקו את ה-Ingress הזה לפני שתמשיכו.

    kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress my-ingress
    
  2. כדי לנהל את התנועה לשירות שיצרתם קודם, יוצרים מניפסט חדש של Ingress עם קטע tls:

    ההגדרה tls מאפשרת HTTPS בין לקוחות לבין שרת ה-proxy של הכניסה.

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-ingress-2
    spec:
      tls:
      - hosts:
        - altostrat.com
        secretName: example-server-creds
      rules:
      - host: altostrat.com
        http:
          paths:
          - path: /greet-the-world
            pathType: Exact
            backend:
              service:
                name: hello-service
                port:
                  number: 60000
          - path: /greet-kubernetes
            pathType: Exact
            backend:
              service:
                name: hello-service
                port:
                  number: 60001
    
  3. שומרים את המניפסט בקובץ בשם my-ingress-2.yaml ויוצרים את ה-Ingress:

    kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f my-ingress-2.yaml
    
  4. כדי לוודא ש-Ingress נוצר ופועל כמו שצריך, מבצעים את הבדיקה הבאה:

    • בודקים את הנתיב /greet-the-world:

      curl -v --resolve altostrat.com:443:CLUSTER_INGRESS_VIP \
          https://altostrat.com/greet-the-world \
          --cacert root-ca.crt
      

      פלט:

      Hello, world!
      Version: 2.0.0
      Hostname: hello-deployment-5ff7f68854-wqzp7
      
    • בודקים את הנתיב /greet-kubernetes:

      curl -v --resolve altostrat.com:443:CLUSTER_INGRESS_VIP \
          https://altostrat.com/greet-kubernetes --cacert root-ca.crt
      

      פלט:

      Hello Kubernetes!
      

יצירת שירות LoadBalancer

שירות מסוג LoadBalancer הוא דרך נוספת לחשוף את עומסי העבודה מחוץ לאשכול. הוראות ודוגמה ליצירת שירות מסוג LoadBalancer זמינות במאמר יצירת שירות מסוג LoadBalancer בפריסת אפליקציה.

סידור וארגון

  1. מחיקת ה-Ingress:

    kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress INGRESS_NAME
    

    מחליפים את INGRESS_NAME בשם של Ingress, כמו my-ingress או my-ingress-2.

  2. מחיקת השירות:

    kubectl --kubeconfig CLUSTER_KUBECONFIG delete service hello-service
    
  3. מחיקת הפריסה:

    kubectl --kubeconfig CLUSTER_KUBECONFIG delete deployment hello-deployment
    
  4. מוחקים את שירות איזון העומסים:

    kubectl --kubeconfig CLUSTER_KUBECONFIG delete service service-does-not-use-nodeports