פריסת אפליקציה

במאמר הזה מוסבר איך לפרוס אפליקציה ב-Google Distributed Cloud.

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

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

יצירת פריסה

השלבים הבאים יוצרים פריסה באשכול:

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

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-deployment
    spec:
      selector:
        matchLabels:
          app: metrics
          department: sales
      replicas: 3
      template:
        metadata:
          labels:
            app: metrics
            department: sales
        spec:
          containers:
          - name: hello
            image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"
    
  2. משתמשים ב-kubectl apply כדי ליצור את הפריסה:

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

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

  3. כדי לוודא שהפריסה נוצרה בהצלחה, אפשר לקבל מידע בסיסי על הפריסה:

    kubectl get deployment my-deployment --kubeconfig CLUSTER_KUBECONFIG
    

    הפלט מראה שלפריסת ה-Deployment יש שלושה Pods שכולם זמינים:

    NAME            READY   UP-TO-DATE   AVAILABLE   AGE
    my-deployment   3/3     3            3           27s
    
  4. מציגים ברשימה את ה-Pods בפריסה:

    kubectl get pods --kubeconfig CLUSTER_KUBECONFIG
    

    הפלט מראה שלפריסת ה-Deployment יש שלושה פודים פעילים:

    NAME                             READY   STATUS    RESTARTS   AGE
    my-deployment-869f65669b-5259x   1/1     Running   0          34s
    my-deployment-869f65669b-9xfrs   1/1     Running   0          34s
    my-deployment-869f65669b-wn4ft   1/1     Running   0          34s
    
  5. קבלת מידע מפורט על הפריסה:

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

    בפלט מוצגים פרטים על מפרט הפריסה והסטטוס:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      ...
      generation: 1
      name: my-deployment
      namespace: default
      ...
    spec:
      ...
      replicas: 3
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: metrics
          department: sales
      ...
        spec:
          containers:
          - image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0
            imagePullPolicy: IfNotPresent
            name: hello
            resources: {}
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
    status:
      availableReplicas: 3
      conditions:
      - lastTransitionTime: "2023-06-29T16:17:17Z"
        lastUpdateTime: "2023-06-29T16:17:17Z"
        message: Deployment has minimum availability.
        reason: MinimumReplicasAvailable
        status: "True"
        type: Available
      - lastTransitionTime: "2023-06-29T16:17:12Z"
        lastUpdateTime: "2023-06-29T16:17:17Z"
        message: ReplicaSet "my-deployment-869f65669b" has successfully progressed.
        reason: NewReplicaSetAvailable
        status: "True"
        type: Progressing
      observedGeneration: 1
      readyReplicas: 3
      replicas: 3
      updatedReplicas: 3
    
  6. תארו את הפריסה:

    kubectl describe deployment my-deployment --kubeconfig CLUSTER_KUBECONFIG
    

    הפלט מציג פרטים בפורמט נוח לקריאה על הפריסה, כולל ReplicaSet המשויך:

    Name:                   my-deployment
    Namespace:              default
    CreationTimestamp:      Thu, 29 Jun 2023 16:17:12 +0000
    Labels:                 <none>
    Annotations:            deployment.kubernetes.io/revision: 1
    Selector:               app=metrics,department=sales
    Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=metrics
              department=sales
      Containers:
      hello:
        Image:        us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0
        Port:         <none>
        Host Port:    <none>
        Environment:  <none>
        Mounts:       <none>
      Volumes:        <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    NewReplicaSetAvailable
    OldReplicaSets:  <none>
    NewReplicaSet:   my-deployment-869f65669b (3/3 replicas created)
    Events:
      Type    Reason             Age    From                   Message
      ----    ------             ----   ----                   -------
      Normal  ScalingReplicaSet  6m50s  deployment-controller  Scaled up replica set my-deployment-869f65669b to 3
    

יצירת שירות מהסוג LoadBalancer

אחת הדרכים לחשוף את ה-Deployment ללקוחות מחוץ לאשכול היא ליצור שירות Kubernetes מסוג LoadBalancer.

כדי ליצור שירות מסוג LoadBalancer:

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

    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
    spec:
      selector:
        app: metrics
        department: sales
      type: LoadBalancer
      ports:
      - port: 80
        targetPort: 8080
    

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

    • כל Pod עם התווית app: metrics והתווית department: sales הוא חבר בשירות. ל-Pods ב-my-deployment יש את התוויות האלה.

    • כשלקוח שולח בקשה לשירות ביציאת TCP‏ 80, הבקשה מועברת אל Pod חבר ביציאת TCP‏ 8080.

    • לכל Pod של חבר חייב להיות מאגר שמקשיב ליציאת TCP‏ 8080.

    כברירת מחדל, ה-container‏ hello-app מאזין ליציאת TCP‏ 8080. אפשר לראות את הגדרת היציאה הזו בקובץ ה-Dockerfile ובקוד המקור של האפליקציה.

  2. משתמשים ב-kubectl apply כדי ליצור את השירות באשכול:

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

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

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

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

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

    apiVersion: v1
    kind: Service
    metadata:
      ...
      name: my-service
      namespace: default
      ...
    spec:
      allocateLoadBalancerNodePorts: true
      clusterIP: 10.96.2.165
      clusterIPs:
      - 10.96.2.165
      externalTrafficPolicy: Cluster
      internalTrafficPolicy: Cluster
      ipFamilies:
      - IPv4
      ipFamilyPolicy: SingleStack
      ports:
      - nodePort: 31565
        port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: metrics
        department: sales
      sessionAffinity: None
      type: LoadBalancer
    status:
      loadBalancer:
        ingress:
        - ip: 192.168.1.13
    

    בפלט שלמעלה אפשר לראות שלשירות יש clusterIP וכתובת IP חיצונית. יש בו גם nodePort, port ו-targetPort.

    המידע על clusterIP לא רלוונטי לתרגיל הזה. כתובת ה-IP החיצונית (status.loadBalancer.ingress.ip) מגיעה מטווח הכתובות שציינתם כשקבעתם מאגרי כתובות של מאזן עומסים (spec.loadBalancer.addressPools) בקובץ התצורה של האשכול.

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

    • כתובת IP חיצונית: 192.168.1.13
    • port: 80
    • nodePort: ‏31565
    • targetPort: 8080

    לקוח שולח בקשה אל 192.168.1.13 ביציאת TCP‏ 80. הבקשה מנותבת למאזן העומסים, ומשם היא מועברת ל-Pod של חבר ביציאת TCP‏ 8080.

  4. מתקשרים לשירות:

    curl INGRESS_IP_ADDRESS
    

    מחליפים את INGRESS_IP_ADDRESS בכתובת ה-IP של הכניסה בקטע status של השירות שאוחזר בשלב הקודם (status.loadBalancer.ingress).

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

    Hello, world!
    Version: 2.0.0
    Hostname: my-deployment-869f65669b-wn4ft
    

מגבלות יציאות של LoadBalancer

הסוג LoadBalancer הוא הרחבה של הסוג NodePort. לכן לשירות מסוג LoadBalancer יש כתובת IP של אשכול וערך אחד או יותר של nodePort. כברירת מחדל, Kubernetes מקצה יציאות צומת לשירותים מסוג LoadBalancer. ההקצאות האלה יכולות לנצל במהירות את יציאות הצמתים הזמינות מתוך 2,768 שהוקצו לאשכול. כדי לשמור את יציאות הצמתים, משביתים את הקצאת יציאות הצמתים של איזון העומסים על ידי הגדרת השדה allocateLoadBalancerNodePorts לערך false במפרט השירות LoadBalancer. ההגדרה הזו מונעת מ-Kubernetes להקצות יציאות צמתים לשירותי LoadBalancer. מידע נוסף זמין במאמר השבתת הקצאה של NodePort למאזן עומסים במאמרי העזרה של Kubernetes.

זוהי מניפסט ליצירת שירות שלא משתמש ביציאות של צמתים:

apiVersion: v1
kind: Service
metadata:
  name: service-does-not-use-nodeports
spec:
  selector:
    app: my-app
  type: LoadBalancer
  ports:
  - port: 8000
  # Set allocateLoadBalancerNodePorts to false
  allocateLoadBalancerNodePorts: false

מחיקת השירות

כדי למחוק את השירות:

  1. משתמשים בפקודה kubectl delete כדי למחוק את השירות מהאשכול:

    kubectl delete service my-service --kubeconfig CLUSTER_KUBECONFIG
    
  2. כדי לוודא שהשירות נמחק:

    kubectl get services --kubeconfig CLUSTER_KUBECONFIG
    

    הפלט לא יכלול יותר את my-service.

מחיקת הפריסה

כדי למחוק את הפריסה:

  1. משתמשים בפקודה kubectl delete כדי למחוק את הפריסה מהאשכול:

    kubectl delete deployment my-deployment --kubeconfig CLUSTER_KUBECONFIG
    

    מוודאים שהפריסה נמחקה:

    kubectl get deployments --kubeconfig CLUSTER_KUBECONFIG
    

    הפלט לא יכלול יותר את my-deployment.

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

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