פריסת PostgreSQL ב-GKE באמצעות Zalando

במדריך הזה מוסבר איך להשתמש באופרטור Zalando Postgres כדי לפרוס אשכולות Postgres ב-Google Kubernetes Engine ‏ (GKE).

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

המדריך הזה מיועד לאדמינים של פלטפורמות, למומחי Cloud Architect ולאנשי תפעול שרוצים להריץ את PostgreSQL כאפליקציית מסד נתונים ב-GKE במקום להשתמש ב-Cloud SQL ל-PostgreSQL.

מטרות

  • תכנון ופריסה של תשתית GKE ל-Postgres
  • פריסה והגדרה של אופרטור Zalando Postgres
  • הגדרת Postgres באמצעות האופרטור כדי להבטיח זמינות, אבטחה, יכולת מעקב וביצועים

יתרונות

היתרונות של Zalando:

  • דרך דקלרטיבית (הצהרתית) וספציפית ל-Kubernetes לניהול ולהגדרה של אשכולות PostgreSQL
  • זמינות גבוהה שסופקה על ידי Patroni
  • תמיכה בניהול גיבוי באמצעות קטגוריות של Cloud Storage
  • עדכונים מתגלגלים על שינויים באשכול Postgres, כולל עדכונים מהירים של גרסאות משניות
  • ניהול משתמשים דקלרטיבי עם יצירה ורוטציה של סיסמאות באמצעות משאבים בהתאמה אישית
  • תמיכה ב-TLS, בהחלפת אישורים ובמאגרי חיבורים
  • שיבוט של אשכולות ושכפול נתונים

ארכיטקטורת פריסה

במדריך הזה נשתמש באופרטור Zalando Postgres כדי לפרוס ולהגדיר אשכול Postgres עם זמינות גבוהה ב-GKE. ב-cluster יש רפליקה אחת של leader ושתי רפליקות של standby (קריאה בלבד) שמנוהלות על ידי Patroni. ‫Patroni הוא פתרון קוד פתוח שמתוחזק על ידי Zalando כדי לספק זמינות גבוהה ויכולות מעבר אוטומטי לגיבוי (auto-failover) ל-Postgres. במקרה של כשל בשרת הראשי, עותק המתנה משודרג אוטומטית לתפקיד של שרת ראשי.

בנוסף, פורסים אשכול GKE אזורי עם זמינות גבוהה עבור Postgres, עם כמה צמתים של Kubernetes שפרוסים על פני כמה אזורי זמינות. ההגדרה הזו עוזרת להבטיח סבילות לתקלות, יכולת הרחבה ויתירות גיאוגרפית. הוא מאפשר עדכונים ותחזוקה מתמשכים, ומספק הסכמי רמת שירות (SLA) לזמינות ולזמן פעולה. מידע נוסף זמין במאמר אשכולות אזוריים.

התרשים הבא מציג אשכול Postgres שפועל בכמה צמתים ואזורים באשכול GKE:

בתרשים, Postgres StatefulSet נפרס בשלושה צמתים בשלושה אזורים שונים. אתם יכולים לקבוע איך GKE יפרוס את הפודים לצמתים על ידי הגדרת כללי הזיקה והאנטי-זיקה הנדרשים של הפוד במפרט של המשאב המותאם אישית postgresql. אם אזור אחד נכשל, GKE מתזמן מחדש את ה-Pods בצמתים זמינים אחרים באשכול, באמצעות ההגדרה המומלצת. כדי לשמור נתונים באופן קבוע, משתמשים בדיסקים מסוג SSD ‏(premium-rwo StorageClass), שהם מומלצים ברוב המקרים למסדי נתונים עם עומס גבוה, כי יש להם חביון נמוך וערך גבוה של פעולות קלט/פלט בשנייה (IOPS).

עלויות

במסמך הזה משתמשים ברכיבים הבאים של Google Cloud, והשימוש בהם כרוך בתשלום:

כדי להעריך את ההוצאות בהתאם לתחזית השימוש שלכם, אתם יכולים להיעזר במחשבון העלויות.

משתמשים חדשים של Google Cloud ? יכול להיות שאתם זכאים לתקופת ניסיון בחינם.

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

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

ב-Cloud Shell מותקן מראש התוכנה שדרושה למדריך הזה, כולל kubectl,‏ ה-CLI של gcloud,‏ Helm ו-Terraform. אם אתם לא משתמשים ב-Cloud Shell, אתם צריכים להתקין את ה-CLI של gcloud.

  1. נכנסים לחשבון Google Cloud . אם אתם משתמשים חדשים ב- Google Cloud, צרו חשבון כדי שתוכלו להעריך את הביצועים של המוצרים שלנו בתרחישים מהעולם האמיתי. לקוחות חדשים מקבלים בחינם גם קרדיט בשווי 300$ להרצה, לבדיקה ולפריסה של עומסי העבודה.
  2. התקינו את ה-CLI של Google Cloud.

  3. אם אתם משתמשים בספק זהויות חיצוני (IdP), קודם אתם צריכים להיכנס ל-CLI של gcloud באמצעות המאגר המאוחד לניהול זהויות.

  4. כדי לאתחל את ה-CLI של gcloud, הריצו את הפקודה הבאה:

    gcloud init
  5. יוצרים או בוחרים Google Cloud פרויקט.

    תפקידים שנדרשים כדי לבחור או ליצור פרויקט

    • Select a project: כדי לבחור פרויקט לא צריך תפקיד IAM ספציפי – אפשר לבחור כל פרויקט שקיבלתם בו תפקיד.
    • יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד Project Creator (יצירת פרויקטים) (roles/resourcemanager.projectCreator), שכולל את ההרשאה resourcemanager.projects.create. איך מקצים תפקידים
    • יוצרים Google Cloud פרויקט:

      gcloud projects create PROJECT_ID

      מחליפים את PROJECT_ID בשם של פרויקט Google Cloud שיוצרים.

    • בוחרים את הפרויקט שיצרתם: Google Cloud

      gcloud config set project PROJECT_ID

      מחליפים את PROJECT_ID בשם הפרויקט ב- Google Cloud .

  6. מוודאים שהחיוב מופעל בפרויקט Google Cloud .

  7. מפעילים את ממשקי ה-API של Compute Engine,‏ IAM,‏ GKE וגיבוי ל-GKE:

    תפקידים שנדרשים להפעלת ממשקי API

    כדי להפעיל ממשקי API, צריך את תפקיד ה-IAM 'אדמין של Service Usage' (roles/serviceusage.serviceUsageAdmin), שכולל את ההרשאה serviceusage.services.enable. איך מקצים תפקידים

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com gkebackup.googleapis.com
  8. התקינו את ה-CLI של Google Cloud.

  9. אם אתם משתמשים בספק זהויות חיצוני (IdP), קודם אתם צריכים להיכנס ל-CLI של gcloud באמצעות המאגר המאוחד לניהול זהויות.

  10. כדי לאתחל את ה-CLI של gcloud, הריצו את הפקודה הבאה:

    gcloud init
  11. יוצרים או בוחרים Google Cloud פרויקט.

    תפקידים שנדרשים כדי לבחור או ליצור פרויקט

    • Select a project: כדי לבחור פרויקט לא צריך תפקיד IAM ספציפי – אפשר לבחור כל פרויקט שקיבלתם בו תפקיד.
    • יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד Project Creator (יצירת פרויקטים) (roles/resourcemanager.projectCreator), שכולל את ההרשאה resourcemanager.projects.create. איך מקצים תפקידים
    • יוצרים Google Cloud פרויקט:

      gcloud projects create PROJECT_ID

      מחליפים את PROJECT_ID בשם של פרויקט Google Cloud שיוצרים.

    • בוחרים את הפרויקט שיצרתם: Google Cloud

      gcloud config set project PROJECT_ID

      מחליפים את PROJECT_ID בשם הפרויקט ב- Google Cloud .

  12. מוודאים שהחיוב מופעל בפרויקט Google Cloud .

  13. מפעילים את ממשקי ה-API של Compute Engine,‏ IAM,‏ GKE וגיבוי ל-GKE:

    תפקידים שנדרשים להפעלת ממשקי API

    כדי להפעיל ממשקי API, צריך את תפקיד ה-IAM 'אדמין של Service Usage' (roles/serviceusage.serviceUsageAdmin), שכולל את ההרשאה serviceusage.services.enable. איך מקצים תפקידים

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com gkebackup.googleapis.com
  14. מעניקים תפקידים לחשבון המשתמש. מריצים את הפקודה הבאה לכל אחד מהתפקידים הבאים ב-IAM: roles/storage.objectViewer, roles/container.admin, roles/iam.serviceAccountAdmin, roles/compute.admin, roles/gkebackup.admin, roles/monitoring.viewer

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE

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

    • PROJECT_ID: מזהה הפרויקט.
    • USER_IDENTIFIER: המזהה של חשבון המשתמש . לדוגמה, myemail@example.com.
    • ROLE: תפקיד ה-IAM שאתם מקצים לחשבון המשתמש.

מגדירים את הסביבה

כדי להגדיר את הסביבה, מבצעים את השלבים הבאים

  1. הגדרת משתני סביבה:

    export PROJECT_ID=PROJECT_ID
    export KUBERNETES_CLUSTER_PREFIX=postgres
    export REGION=us-central1
    

    מחליפים את PROJECT_ID במזהה הפרויקט. Google Cloud

  2. משכפלים את המאגר ב-GitHub:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  3. עוברים לספריית העבודה:

    cd kubernetes-engine-samples/databases/postgres-zalando
    

יצירת תשתית האשכול

בקטע הזה מריצים סקריפט של Terraform כדי ליצור אשכול GKE פרטי, אזורי וזמין מאוד.

אפשר להתקין את האופרטור באמצעות אשכול Standard או Autopilot.

רגילה

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

פריסת התשתית הזו:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-standard init
terraform -chdir=terraform/gke-standard apply \
  -var project_id=${PROJECT_ID} \
  -var region=${REGION} \
  -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

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

‫Terraform יוצר את המשאבים הבאים:

  • רשת VPC ותת-רשת פרטית לצמתים של Kubernetes
  • נתב לגישה לאינטרנט דרך NAT
  • אשכול GKE פרטי באזור us-central1
  • מאגר צמתים עם קנה מידה אוטומטי מופעל (צומת אחד עד שני צמתים לכל אזור, צומת אחד לכל אזור מינימום)
  • ServiceAccount עם הרשאות רישום ביומן ומעקב
  • גיבוי ל-GKE לצורך התאוששות מאסון
  • השירות המנוהל של Google Cloud ל-Prometheus לניטור אשכולות

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

...
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
...

טייס אוטומטי

התרשים הבא מציג אשכול פרטי אזורי של Autopilot GKE:

פורסים את התשתית:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-autopilot init
terraform -chdir=terraform/gke-autopilot apply \
  -var project_id=${PROJECT_ID} \
  -var region=${REGION} \
  -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

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

‫Terraform יוצר את המשאבים הבאים:

  • רשת VPC ותת-רשת פרטית לצמתים של Kubernetes
  • נתב לגישה לאינטרנט דרך NAT
  • אשכול GKE פרטי באזור us-central1
  • ServiceAccount עם הרשאת רישום ביומן ומעקב
  • השירות המנוהל של Google Cloud ל-Prometheus לניטור אשכולות

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

...
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
...

התחברות לאשכול

מגדירים את kubectl לתקשורת עם האשכול:

gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --location ${REGION}

פריסת אופרטור Zalando באשכול

פורסים את Zalando operator באשכול Kubernetes באמצעות Helm chart.

  1. מוסיפים את מאגר תרשימי Helm של Zalando:

    helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator
    
  2. יוצרים מרחב שמות לאופרטור Zalando ולאשכול Postgres:

    kubectl create ns postgres
    kubectl create ns zalando
    
  3. פורסים את האופרטור של Zalando באמצעות כלי שורת הפקודה של Helm:

    helm install postgres-operator postgres-operator-charts/postgres-operator -n zalando \
        --set configKubernetes.enable_pod_antiaffinity=true \
        --set configKubernetes.pod_antiaffinity_preferred_during_scheduling=true \
        --set configKubernetes.pod_antiaffinity_topology_key="topology.kubernetes.io/zone" \
        --set configKubernetes.spilo_fsgroup="103"
    

    אי אפשר להגדיר את ההגדרות של podAntiAffinity ישירות במשאב המותאם אישית שמייצג את אשכול Postgres. במקום זאת, מגדירים את podAntiAffinity ההגדרות באופן גלובלי לכל אשכולות Postgres בהגדרות האופרטור.

  4. בודקים את סטטוס הפריסה של אופרטור Zalando באמצעות Helm:

    helm ls -n zalando
    

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

    NAME                 NAMESPACE    REVISION    UPDATED                                STATUS      CHART                       APP VERSION
    postgres-operator    zalando     1           2023-10-13 16:04:13.945614 +0200 CEST    deployed    postgres-operator-1.10.1    1.10.1
    

פריסת Postgres

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

  • שלוש רפליקות של Postgres: רפליקה אחת ראשית ושתי רפליקות במצב המתנה.
  • הקצאת משאבי מעבד (CPU) של בקשת מעבד אחת ושתי מגבלות מעבד, עם בקשות ומגבלות זיכרון של 4 GB.
  • הגדרנו Tolerations‏, nodeAffinities ו-topologySpreadConstraints לכל עומס עבודה, כדי להבטיח חלוקה נכונה בין צמתי Kubernetes, תוך שימוש במאגרי הצמתים המתאימים ובאזורי זמינות שונים.

ההגדרה הזו מייצגת את ההגדרה המינימלית שנדרשת כדי ליצור אשכול Postgres שמוכן לייצור.

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

apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
  name: my-cluster
spec:
  dockerImage: ghcr.io/zalando/spilo-15:3.0-p1
  teamId: "my-team"
  numberOfInstances: 3
  users:
    mydatabaseowner:
    - superuser
    - createdb
    myuser: []
  databases:
    mydatabase: mydatabaseowner
  postgresql:
    version: "15"
    parameters:
      shared_buffers: "32MB"
      max_connections: "10"
      log_statement: "all"
      password_encryption: scram-sha-256
  volume:
    size: 5Gi
    storageClass: premium-rwo
  enableShmVolume: true
  podAnnotations:
    cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
  tolerations:
  - key: "app.stateful/component"
    operator: "Equal"
    value: "postgres-operator"
    effect: NoSchedule
  nodeAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 1
      preference:
        matchExpressions:
        - key: "app.stateful/component"
          operator: In
          values:
          - "postgres-operator"
  resources:
    requests:
      cpu: "1"
      memory: 4Gi
    limits:
      cpu: "2"
      memory: 4Gi
  sidecars:
    - name: exporter
      image: quay.io/prometheuscommunity/postgres-exporter:v0.14.0
      args:
      - --collector.stat_statements
      ports:
      - name: exporter
        containerPort: 9187
        protocol: TCP
      resources:
        limits:
          cpu: 500m
          memory: 256M
        requests:
          cpu: 100m
          memory: 256M
      env:
      - name: "DATA_SOURCE_URI"
        value: "localhost/postgres?sslmode=require"
      - name: "DATA_SOURCE_USER"
        value: "$(POSTGRES_USER)"
      - name: "DATA_SOURCE_PASS"
        value: "$(POSTGRES_PASSWORD)"

קובץ המניפסט הזה כולל את השדות הבאים:

  • spec.teamId: תחילית לאובייקטים של האשכול שבוחרים
  • spec.numberOfInstances: המספר הכולל של המופעים באשכול
  • spec.users: רשימת המשתמשים עם הרשאות
  • spec.databases: רשימת מסדי הנתונים בפורמט dbname: ownername
  • spec.postgresql: פרמטרים של postgres
  • spec.volume: פרמטרים של Persistent Disk
  • spec.tolerations: תבנית ה-Pod של ה-tolerations שמאפשרת לתזמן את ה-Pods של האשכול בצמתי pool-postgres
  • spec.nodeAffinity: תבנית ה-Pod‏ nodeAffinity שמציינת ל-GKE שעדיף לתזמן את ה-Pods באשכול בצמתים pool-postgres.
  • spec.resources: בקשות ומגבלות לגבי פודים באשכול
  • spec.sidecars: רשימה של קונטיינרים מסוג sidecar, שמכילה את postgres-exporter

מידע נוסף זמין במאמר Cluster manifest reference (הפניה למניפסט של אשכול) במסמכי התיעוד של Postgres.

יצירת אשכול Postgres בסיסי

  1. יוצרים אשכול Postgres חדש באמצעות ההגדרה הבסיסית:

    kubectl apply -n postgres -f manifests/01-basic-cluster/my-cluster.yaml
    

    הפקודה הזו יוצרת משאב מותאם אישית של PostgreSQL של Zalando operator עם:

    • בקשות ומגבלות של יחידת עיבוד מרכזית (CPU) וזיכרון
    • הכתמים והזיקות מאפשרים לפזר את העותקים של ה-Pod שהוקצו בין הצמתים של GKE.
    • מסד נתונים
    • שני משתמשים עם הרשאות בעלים של מסד נתונים
    • משתמש ללא הרשאות
  2. מחכים ש-GKE יתחיל את עומסי העבודה הנדרשים:

    kubectl wait pods -l cluster-name=my-cluster  --for condition=Ready --timeout=300s -n postgres
    

    יכול להיות שיחלפו כמה דקות עד שהפקודה הזו תושלם.

  3. מוודאים ש-GKE יצר את עומסי העבודה של Postgres:

    kubectl get pod,svc,statefulset,deploy,pdb,secret -n postgres
    

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

    NAME                                    READY   STATUS  RESTARTS   AGE
    pod/my-cluster-0                        1/1     Running   0         6m41s
    pod/my-cluster-1                        1/1     Running   0         5m56s
    pod/my-cluster-2                        1/1     Running   0         5m16s
    pod/postgres-operator-db9667d4d-rgcs8   1/1     Running   0         12m
    
    NAME                        TYPE        CLUSTER-IP  EXTERNAL-IP   PORT(S)   AGE
    service/my-cluster          ClusterIP   10.52.12.109   <none>       5432/TCP   6m43s
    service/my-cluster-config   ClusterIP   None        <none>      <none>  5m55s
    service/my-cluster-repl     ClusterIP   10.52.6.152 <none>      5432/TCP   6m43s
    service/postgres-operator   ClusterIP   10.52.8.176 <none>      8080/TCP   12m
    
    NAME                        READY   AGE
    statefulset.apps/my-cluster   3/3   6m43s
    
    NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/postgres-operator   1/1     1           1           12m
    
    NAME                                                MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
    poddisruptionbudget.policy/postgres-my-cluster-pdb   1              N/A             0                   6m44s
    
    NAME                                                            TYPE                DATA   AGE
    secret/my-user.my-cluster.credentials.postgresql.acid.zalan.do  Opaque              2   6m45s
    secret/postgres.my-cluster.credentials.postgresql.acid.zalan.do   Opaque            2   6m44s
    secret/sh.helm.release.v1.postgres-operator.v1                  helm.sh/release.v1   1      12m
    secret/standby.my-cluster.credentials.postgresql.acid.zalan.do  Opaque              2   6m44s
    secret/zalando.my-cluster.credentials.postgresql.acid.zalan.do  Opaque              2   6m44s
    

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

  • ‫Postgres StatefulSet, ששולט בשלושה עותקים של Pod ל-Postgres
  • PodDisruptionBudgets, כדי להבטיח שיש לפחות עותק זמין אחד
  • שירות my-cluster, שמטרגט רק את העותק המשוכפל הראשי
  • שירות my-cluster-repl, שחושף את יציאת Postgres לחיבורים נכנסים ולשכפול בין רפליקות של Postgres
  • שירות my-cluster-config headless, כדי לקבל את רשימת העותקים של Postgres Pod שפועלים
  • סודות עם פרטי כניסה של משתמש לגישה למסד הנתונים ולשכפול בין צמתי Postgres

אימות ל-Postgres

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

apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
  name: my-cluster
spec:
  ...
  users:
    mydatabaseowner:
    - superuser
    - createdb
    myuser: []
  databases:
    mydatabase: mydatabaseowner

במניפסט הזה:

  • למשתמש mydatabaseowner יש את התפקידים SUPERUSER ו-CREATEDB, שמאפשרים לו הרשאות אדמין מלאות (כלומר, ניהול ההגדרה של Postgres, יצירת מסדי נתונים, טבלאות ומשתמשים חדשים). אסור לשתף את המשתמש הזה עם לקוחות. לדוגמה, ב-Cloud SQL אין אפשרות ללקוחות לקבל גישה למשתמשים עם התפקיד SUPERUSER.
  • לא הוקצו תפקידים למשתמש myuser. השיטה הזו תואמת לשיטה המומלצת של שימוש ב-SUPERUSER כדי ליצור משתמשים עם הרשאות מינימליות. mydatabaseowner העניק ל-myuser הרשאות מפורטות. כדי לשמור על האבטחה, צריך לשתף את פרטי הכניסה של myuser רק עם אפליקציות לקוח.

שמירת סיסמאות

מומלץ להשתמש בscram-sha-256 שיטה המומלצת לאחסון סיסמאות. לדוגמה, המניפסט הבא מתאר משאב בהתאמה אישית שמציין הצפנה של scram-sha-256 באמצעות השדה postgresql.parameters.password_encryption:

apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
  name: my-cluster
spec:
  ...
  postgresql:
    parameters:
      password_encryption: scram-sha-256

עדכון של פרטי הכניסה של המשתמש

אתם יכולים לשנות את פרטי הכניסה של המשתמשים שמאוחסנים ב-Kubernetes Secrets באמצעות Zalando. לדוגמה, המניפסט הבא מתאר משאב מותאם אישית שמגדיר רוטציה של פרטי הכניסה של המשתמש באמצעות השדה usersWithSecretRotation:

apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
  name: my-cluster
spec:
  ...
  usersWithSecretRotation:
  - myuser
  - myanotheruser
  - ...

דוגמה לאימות: חיבור ל-Postgres

בקטע הזה נסביר איך לפרוס לקוח לדוגמה של Postgres ולהתחבר למסד הנתונים באמצעות הסיסמה מ-Kubernetes Secret.

  1. מריצים את ה-Pod של הלקוח כדי ליצור אינטראקציה עם אשכול Postgres:

    kubectl apply -n postgres -f manifests/02-auth/client-pod.yaml
    

    פרטי הכניסה של המשתמשים myuser ו-mydatabaseowner נלקחים מהסודות הקשורים ומותקנים כמשתני סביבה ב-Pod.

  2. מתחברים ל-Pod כשהוא מוכן:

    kubectl wait pod postgres-client --for=condition=Ready --timeout=300s -n postgres
    kubectl exec -it postgres-client -n postgres -- /bin/bash
    
  3. מתחברים ל-Postgres ומנסים ליצור טבלה חדשה באמצעות myuser פרטי הכניסה:

    PGPASSWORD=$CLIENTPASSWORD psql \
      -h my-cluster \
      -U $CLIENTUSERNAME \
      -d mydatabase \
      -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);"
    

    הפקודה אמורה להיכשל עם שגיאה דומה לזו:

    ERROR:  permission denied for schema public
    LINE 1: CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR...
    

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

  4. צור טבלה עם פרטי הכניסה של mydatabaseowner והענק ל-myuser את כל ההרשאות בטבלה:

    PGPASSWORD=$OWNERPASSWORD psql \
      -h my-cluster \
      -U $OWNERUSERNAME \
      -d mydatabase \
      -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);GRANT ALL ON test TO myuser;GRANT ALL ON SEQUENCE test_id_seq TO myuser;"
    

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

    CREATE TABLE
    GRANT
    GRANT
    
  5. מזינים נתונים אקראיים לטבלה באמצעות פרטי הכניסה myuser:

    for i in {1..10}; do
      DATA=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13)
      PGPASSWORD=$CLIENTPASSWORD psql \
      -h my-cluster \
      -U $CLIENTUSERNAME \
      -d mydatabase \
      -c "INSERT INTO test(randomdata) VALUES ('$DATA');"
    done
    

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

    INSERT 0 1
    INSERT 0 1
    INSERT 0 1
    INSERT 0 1
    INSERT 0 1
    INSERT 0 1
    INSERT 0 1
    INSERT 0 1
    INSERT 0 1
    INSERT 0 1
    
  6. מקבלים את הערכים שהוזנו:

    PGPASSWORD=$CLIENTPASSWORD psql \
      -h my-cluster \
      -U $CLIENTUSERNAME \
      -d mydatabase \
      -c "SELECT * FROM test;"
    

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

    id |  randomdata
    ----+---------------
      1 | jup9HYsAjwtW4
      2 | 9rLAyBlcpLgNT
      3 | wcXSqxb5Yz75g
      4 | KoDRSrx3muD6T
      5 | b9atC7RPai7En
      6 | 20d7kC8E6Vt1V
      7 | GmgNxaWbkevGq
      8 | BkTwFWH6hWC7r
      9 | nkLXHclkaqkqy
     10 | HEebZ9Lp71Nm3
    (10 rows)
    
  7. יוצאים מהמעטפת של ה-Pod:

    exit
    

איך Prometheus אוסף מדדים עבור אשכול Postgres

בתרשים הבא אפשר לראות איך מתבצע איסוף מדדים של Prometheus:

בתרשים, אשכול פרטי של GKE מכיל:

  • ‫Pod של Postgres שאוסף מדדים בנתיב / ובפורט 9187
  • כלי איסוף שמבוססים על Prometheus ומעבדים את המדדים מ-Pod של Postgres
  • משאב PodMonitoring ששולח מדדים ל-Cloud Monitoring

השירות המנוהל של Google Cloud ל-Prometheus תומך באיסוף מדדים בפורמט Prometheus. ב-Cloud Monitoring נעשה שימוש בלוח בקרה משולב למדדי Postgres.

‫Zalando חושפת מדדי אשכול בפורמט Prometheus באמצעות רכיב postgres_exporter כקונטיינר sidecar.

  1. יוצרים את המשאב PodMonitoring כדי לגרד מדדים לפי labelSelector:

    kubectl apply -n postgres -f manifests/03-prometheus-metrics/pod-monitoring.yaml
    
  2. נכנסים לדף GKE Clusters Dashboard במסוף Google Cloud .

    כניסה ללוח הבקרה של GKE Clusters

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

  3. נכנסים לדף Dashboards במסוף Google Cloud .

    מעבר למרכזי השליטה

  4. פותחים את לוח הבקרה של PostgreSQL Prometheus Overview. בלוח הבקרה מוצג מספר השורות שאוחזרו. יכול להיות שיחלפו כמה דקות עד שהדשבורד יוקצה אוטומטית.

  5. מתחברים ל-Pod של הלקוח:

    kubectl exec -it postgres-client -n postgres -- /bin/bash
    
  6. הוספת נתונים אקראיים:

    for i in {1..100}; do
      DATA=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13)
      PGPASSWORD=$CLIENTPASSWORD psql \
      -h my-cluster \
      -U $CLIENTUSERNAME \
      -d mydatabase \
      -c "INSERT INTO test(randomdata) VALUES ('$DATA');"
    done
    
  7. יש לרענן את הדף. התרשימים Rows ו-Blocks מתעדכנים כדי להציג את המצב בפועל של מסד הנתונים.

  8. יוצאים מהמעטפת של ה-Pod:

    exit
    

הסרת המשאבים

מחיקת הפרויקט

    כדי למחוק Google Cloud פרויקט:

    gcloud projects delete PROJECT_ID

מחיקת משאבים בודדים

  1. מגדירים משתני סביבה.

    export PROJECT_ID=${PROJECT_ID}
    export KUBERNETES_CLUSTER_PREFIX=postgres
    export REGION=us-central1
    
  2. מריצים את הפקודה terraform destroy:

    export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
    terraform  -chdir=terraform/FOLDER destroy \
      -var project_id=${PROJECT_ID} \
      -var region=${REGION} \
      -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
    

    מחליפים את FOLDER ב-gke-autopilot או ב-gke-standard.

    כשמופיעה בקשה, כותבים yes.

  3. חיפוש כל הדיסקים שלא צורפו:

    export disk_list=$(gcloud compute disks list --filter="-users:* AND labels.name=${KUBERNETES_CLUSTER_PREFIX}-cluster" --format "value[separator=|](name,zone)")
    
  4. מוחקים את הדיסקים:

    for i in $disk_list; do
      disk_name=$(echo $i| cut -d'|' -f1)
      disk_zone=$(echo $i| cut -d'|' -f2|sed 's|.*/||')
      echo "Deleting $disk_name"
      gcloud compute disks delete $disk_name --zone $disk_zone --quiet
    done
    
  5. מחיקת המאגר ב-GitHub:

    rm -r ~/kubernetes-engine-samples/
    

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

  • כדאי להעמיק את הקריאה ולהכיר דוגמאות לארכיטקטורות, תרשימים ושיטות מומלצות בנושאי Google Cloud. כל אלה זמינים במרכז הארכיטקטורה של Cloud.