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

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

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

יוצרים חיבור SSH לתחנת העבודה של האדמין:

יצירת פריסה

קובץ מניפסט לפריסה:

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 על ידי עיון בקוד המקור של hello-app.

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

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

USER_CLUSTER_KUBECONFIG הוא הנתיב של קובץ ה-kubeconfig עבור אשכול המשתמשים.

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

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

זוהי מניפסט של Service שחושף את הפריסה ללקוחות בתוך האשכול:

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

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

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

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

kubectl --kubeconfig USER_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 הוא מערך של אובייקטים של Kubernetes ServicePort: אחד בשם world-port ואחד בשם kubernetes-port.

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

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

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

רכיבי Ingress

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

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

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

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

יצירת Ingress

הנה מניפסט של 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

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

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

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

כשלקוח שולח בקשה לכתובת ה-VIP של Ingress אשכול המשתמשים, הבקשה מנותבת למאזן העומסים (LB). מאזן העומסים משתמש בשירות istio-ingress כדי להעביר את הבקשה ל-ingress proxy, שפועל באשכול המשתמשים. ה-ingress 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

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

curl USER_CLUSTER_INGRESS_VIP/greet-the-world

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

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

Hello, world!
Version: 2.0.0
Hostname: ...

בודקים את ה-Ingress באמצעות הנתיב /greet-kubernetes:

curl USER_CLUSTER_INGRESS_VIP/greet-kubernetes

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

Hello Kubernetes!

הגדרת HTTPS ל-Ingress

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

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

  • Ingress proxy: משתתף בלחיצת היד של HTTPS, ואז מעביר חבילות ל-Pods של חברים בשירות hello-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 בחלק ה-HTTP, מחקו את ה-Ingress הזה לפני שתמשיכו.

מחיקת ה-Ingress:

kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete ingress my-ingress

כדי לטפל בתנועה של השירות שיצרתם קודם, צריך ליצור Ingress חדש עם קטע tls. הפעולה הזו תפעיל HTTPS בין הלקוחות לבין שרת ה-proxy של הכניסה.

הנה מניפסט של Ingress:

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

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

kubectl apply --kubeconfig USER_CLUSTER_KUBECONFIG -f my-ingress-2.yaml

כדאי לבדוק את זה.

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

    curl -v --resolve altostrat.com:443:USER_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:USER_CLUSTER_INGRESS_VIP https://altostrat.com/greet-kubernetes --cacert root-ca.crt
    

    פלט:

    Hello Kubernetes!
    

סידור וארגון

מחיקת ה-Ingress:

kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete ingress INGRESS_NAME

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

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

kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete service hello-service

מחיקת הפריסה:

kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete deployment hello-deployment