פריסת Apache Kafka ב-GKE באמצעות Strimzi

במדריך הזה מוסבר איך להשתמש באופרטור Strimzi כדי לפרוס אשכולות של Apache Kafka.

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

אופרטורים הם תוספי תוכנה שמשתמשים במשאבים מותאמים אישית כדי לנהל אפליקציות ורכיבים שלהן. במאמר תבנית אופרטור במסמכי Kubernetes בקוד פתוח אפשר לקרוא מידע נוסף על הסיבות לשימוש באופרטורים. אופרטור Strimzi מציע גמישות באפשרויות הפריסה ומאפשר להשתמש ב-taints וב-tolerances של Kubernetes כדי להריץ את Kafka בצמתים ייעודיים.

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

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

מטרות

  • תכנון ופריסה של תשתית GKE ל-Apache Kafka
  • פריסה והגדרה של אופרטור Strimzi
  • הגדרת Apache Kafka באמצעות אופרטור Strimzi

יתרונות

היתרונות של Strimzi כוללים:

  • אופרטורים של Strimzi מספקים גישה פשוטה ומקורית ל-Kubernetes לניהול אשכולות Kafka. ‫Strimzi משתמש במשאבים מותאמים אישית שמייצגים נושאים ומשתמשים ב-Kafka, וכך הופך את ניהול האשכולות לפשוט יותר ומתאים לשיטות המומלצות של Kubernetes.
  • האבטחה היא ערך עליון ב-Strimzi כברירת מחדל, ולכן המערכת יוצרת אישורים למאזינים ותומכת בשיטות אימות מאובטחות כמו TLS, ‏ SCRAM-SHA ו-OAuth. ‫Strimzi מטפל גם ב-NetworkPolicies לכל מאזיני Kafka.
  • ‫Strimzi לא מסתמך על תלות חיצונית. הוא כולל אשכולות של Kafka ושל ZooKeeper עם כלי ייצוא מובנים של מדדים, כך שלא צריך להשתמש בכלים נוספים. אפשר גם לשנות את ההגדרות של הברוקר כדי לעמוד בדרישות ספציפיות.

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

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

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

בהגדרה טיפוסית, ZooKeeper מתאם בין אשכולי Kafka על ידי עזרה בבחירת מוביל בין הברוקרים, ומבטיח מעבר חלק לגיבוי במקרה של בעיות.

אפשר גם לפרוס את ההגדרה של Kafka בלי Zookeeper על ידי הפעלת מצב KRaft, אבל הקהילה של Strimzi לא רואה בשיטה הזו פתרון מוכן לייצור כי היא לא כוללת תמיכה במשאבי KafkaTopic, באימות של פרטי הכניסה ועוד.

זמינות ותוכנית התאוששות מאסון (DR)

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

שימוש בכמה צמתים ואזורים הוא חיוני כדי להשיג אשכול Kubernetes עם זמינות גבוהה בגלל הסיבות הבאות: Google Cloud

  • עמידות בפני תקלות: מספר צמתים מחלקים את עומס העבודה בין הצמתים באשכול, וכך מבטיחים שאם צומת אחד ייכשל, הצמתים האחרים יוכלו להשתלט על המשימות, ולמנוע השבתה והפרעות בשירות.
  • יכולת הרחבה: שימוש בכמה צמתים עוזר להבטיח שניתן להוסיף או להסיר צמתים לפי הצורך, וכך להקצות משאבים בצורה אופטימלית ולעמוד בדרישות של תנועה מוגברת או עומסי עבודה גדולים יותר.
  • זמינות גבוהה: שימוש בכמה אזורים בתוך אזור עוזר להבטיח יתירות ומצמצם את הסיכון לנקודת כשל יחידה. אם יש הפסקה זמנית בשירות באזור זמינות שלם, האשכול יכול להמשיך לפעול באזורים אחרים, וכך לשמור על זמינות השירות.
  • יתירות גיאוגרפית: באמצעות פריסת צמתים באזורים שונים, הנתונים והשירותים של האשכול מפוזרים גיאוגרפית, מה שמספק עמידות מפני אסונות טבע, הפסקות חשמל או שיבושים מקומיים אחרים שעשויים להשפיע על אזור יחיד.
  • עדכונים ותחזוקה מתמשכים: שימוש בכמה אזורים עוזר לוודא שאפשר לבצע עדכונים ותחזוקה מתמשכים בצמתים נפרדים בלי להשפיע על הזמינות הכוללת של האשכול. כך אפשר להבטיח שירות רציף, וגם לבצע עדכונים ותיקונים בצורה חלקה.
  • הסכמי רמת שירות (SLA): Google Cloud מספקת הסכמי רמת שירות לפריסות מרובות אזורים, ומציעה רמת זמינות וזמן פעולה תקינה מינימליים.

תרשים פריסה

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

בתרשים, Kafka StrimziPodSet נפרס על פני שלושה צמתים בשלושה אזורים שונים. אפשר לשלוט בהגדרה הזו באמצעות הגדרת הכללים affinity ו-topology spread של ה-Pod הנדרש במפרט של המשאב המותאם אישית StrimziPodSet.

אם אזור אחד נכשל, באמצעות ההגדרה המומלצת, ‏ GKE מתזמן מחדש את ה-Pods בצמתים חדשים ומשכפל נתונים מהרפליקות שנותרו, גם עבור Kafka וגם עבור Zookeeper.

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

המשאב המותאם אישית StrimziPodSet

במדריך הזה נעשה שימוש במשאב המותאם אישית StrimziPodSet שהוצג בגרסה 0.29 של Strimzi, במקום ב-StatefulSets.

המשאבים StrimziPodSet מאפשרים לשפר את יכולת ההתאמה של האשכול, ומאפשרים להעביר אפשרויות הגדרה, כך שתוכלו לבצע שינויים ב-Pods ברמת פירוט גבוהה יותר. המשאב StrimziPodSet מופעל כברירת מחדל בגרסאות Strimzi 0.35 ואילך.

עלויות

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

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

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

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

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

  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,‏ Backup for GKE ו-Resource Manager:

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

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

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com gkebackup.googleapis.com cloudresourcemanager.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,‏ Backup for GKE ו-Resource Manager:

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

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

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com gkebackup.googleapis.com cloudresourcemanager.googleapis.com
  14. נותנים תפקידים לחשבון המשתמש. מריצים את הפקודה הבאה לכל אחד מהתפקידים הבאים ב-IAM: roles/storage.objectViewer, roles/logging.logWriter, roles/container.clusterAdmin, roles/container.serviceAgent, roles/iam.serviceAccountAdmin, roles/serviceusage.serviceUsageAdmin, roles/iam.serviceAccountAdmin

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

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

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

הכנת הסביבה

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

כדי להגדיר את הסביבה באמצעות Cloud Shell:

  1. מפעילים סשן של Cloud Shell מGoogle Cloud המסוף על ידי לחיצה על Activate Cloud Shell סמל ההפעלה של Cloud Shell. Google Cloud סשן יופעל בחלונית התחתונה של מסוף Google Cloud .

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

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

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

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

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

    cd kubernetes-engine-samples/streaming/
    

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

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

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

רגילה

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

כדי לפרוס את התשתית הזו, מריצים את הפקודות הבאות מ-Cloud Shell:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=kafka/terraform/gke-standard init
terraform -chdir=kafka/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.
  • ‫2 מאגרי צמתים עם הפעלה של שינוי גודל אוטומטי (1-2 צמתים לכל אזור, צומת אחד לכל אזור לכל הפחות)
  • ServiceAccount עם הרשאות רישום ביומן ומעקב.
  • גיבוי ל-GKE לצורך התאוששות מאסון.
  • השירות המנוהל של Google Cloud ל-Prometheus לניטור אשכולות.

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

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

Outputs:

kubectl_connection_command = "gcloud container clusters get-credentials strimzi-cluster --region us-central1"

טייס אוטומטי

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

כדי לפרוס את התשתית, מריצים את הפקודות הבאות מ-Cloud Shell:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=kafka/terraform/gke-autopilot init
terraform -chdir=kafka/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.

Outputs:

kubectl_connection_command = "gcloud container clusters get-credentials strimzi-cluster --region us-central1"

מתבצעת התחברות לאשכול

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

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

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

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

  1. מוסיפים את מאגר Strimzi Helm Chart:

    helm repo add strimzi https://strimzi.io/charts/
    
  2. מוסיפים מרחב שמות לאופרטור Strimzi ולמקלט Kafka:

    kubectl create ns kafka
    
  3. פורסים את אופרטור האשכול Strimzi באמצעות Helm:

    helm install strimzi-operator strimzi/strimzi-kafka-operator -n kafka
    

    כדי לפרוס את Strimzi Cluster Operator ואת אשכולי Kafka במרחבי שמות שונים, מוסיפים את הפרמטר --set watchNamespaces="{kafka-namespace,kafka-namespace-2,...}" לפקודת helm.

  4. מוודאים ש-Strimzi Cluster Operator נפרס בהצלחה באמצעות Helm:

    helm ls -n kafka
    

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

    NAME            NAMESPACE    REVISION    UPDATED                              STATUS    CHART                        APP VERSION
    strimzi-operator    kafka      1       2023-06-27 11:22:15.850545 +0200 CEST    deployed    strimzi-kafka-operator-0.35.0    0.35.0
    

פריסת Kafka

אחרי שפורסים את האופרטור באשכול, אפשר לפרוס מופע של אשכול Kafka.

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

הגדרה בסיסית

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

  • שלוש רפליקות של ברוקרים של Kafka, עם מינימום של שתי רפליקות זמינות שנדרשות לעקביות של האשכול.
  • שלוש רפליקות של צמתי ZooKeeper, שיוצרות אשכול.
  • שני מאזינים של Kafka: אחד ללא אימות, ואחד שמשתמש באימות TLS עם אישור שנוצר על ידי Strimzi.
  • הערכים של Java ‏MaxHeapSize ו-MinHeapSize מוגדרים ל-4 GB עבור Kafka ול-2 GB עבור ZooKeeper.
  • הקצאת משאבי CPU של בקשת CPU אחת ומגבלות CPU של 2 גם ל-Kafka וגם ל-ZooKeeper, יחד עם בקשות ומגבלות של 5GB זיכרון ל-Kafka (4GB לשירות הראשי ו-0.5GB ל-metrics exporter) ו-2.5GB ל-ZooKeeper (2GB לשירות הראשי ו-0.5GB ל-metrics exporter).
  • Entity-operator עם הבקשות והמגבלות הבאות:
    • tlsSidecar: 100 m/500 m CPU ו-128 Mi זיכרון.
    • topicOperator: 100 m/500 m CPU ו-512 Mi זיכרון.
    • userOperator: 500 m CPU ו-2 Gi זיכרון.
  • נפח אחסון של 100GB מוקצה לכל Pod באמצעות premium-rwo storageClass.
  • הגדרת Tolerations,‏ nodeAffinities ו-podAntiAffinities לכל עומס עבודה, כדי להבטיח חלוקה נכונה בין הצמתים, תוך שימוש במאגרי הצמתים המתאימים ובאזורים שונים.
  • תקשורת בתוך האשכול מאובטחת באמצעות אישורים בחתימה עצמית: רשויות אישורים (CA) נפרדות לאשכול וללקוחות (mTLS). אפשר גם להגדיר שימוש ברשות אישורים אחרת.

ההגדרה הזו מייצגת את ההגדרה המינימלית שנדרשת ליצירת אשכול Kafka שמוכן לייצור. בקטעים הבאים מוצגות הגדרות בהתאמה אישית לטיפול בהיבטים כמו אבטחת אשכולות, רשימות של בקרת גישה (ACL), ניהול נושאים, ניהול אישורים ועוד.

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

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

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

    הפקודה הזו יוצרת משאב מותאם אישית של Kafka באופרטור Strimzi, שכולל בקשות ומגבלות של CPU וזיכרון, בקשות של אחסון בלוקים ושילוב של taints ו-affinities כדי להפיץ את ה-Pods שהוקצו בין צמתי Kubernetes.

  2. ממתינים כמה דקות בזמן ש-Kubernetes מפעיל את עומסי העבודה הנדרשים:

    kubectl wait kafka/my-cluster --for=condition=Ready --timeout=600s -n kafka
    
  3. מוודאים שעומסי העבודה של Kafka נוצרו:

    kubectl get pod,service,deploy,pdb -l=strimzi.io/cluster=my-cluster -n kafka
    

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

    NAME                                            READY   STATUS  RESTARTS   AGE
    pod/my-cluster-entity-operator-848698874f-j5m7f   3/3   Running   0        44m
    pod/my-cluster-kafka-0                          1/1   Running   0        5m
    pod/my-cluster-kafka-1                          1/1   Running   0        5m
    pod/my-cluster-kafka-2                          1/1   Running   0        5m
    pod/my-cluster-zookeeper-0                      1/1   Running   0        6m
    pod/my-cluster-zookeeper-1                      1/1   Running   0        6m
    pod/my-cluster-zookeeper-2                      1/1   Running   0        6m
    
    NAME                                TYPE      CLUSTER-IP   EXTERNAL-IP   PORT(S)                             AGE
    service/my-cluster-kafka-bootstrap  ClusterIP   10.52.8.80   <none>      9091/TCP,9092/TCP,9093/TCP          5m
    service/my-cluster-kafka-brokers    ClusterIP   None         <none>      9090/TCP,9091/TCP,9092/TCP,9093/TCP   5m
    service/my-cluster-zookeeper-client   ClusterIP   10.52.11.144   <none>      2181/TCP                            6m
    service/my-cluster-zookeeper-nodes  ClusterIP   None         <none>      2181/TCP,2888/TCP,3888/TCP          6m
    
    NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/my-cluster-entity-operator   1/1   1          1         44m
    
    NAME                                            MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
    poddisruptionbudget.policy/my-cluster-kafka     2             N/A             1                   5m
    poddisruptionbudget.policy/my-cluster-zookeeper   2             N/A             1                   6m
    

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

  • שני StrimziPodSets ל-Kafka ול-ZooKeeper.
  • שלושה פודים של רפליקות של ברוקר Kafka.
  • שלושה רכיבי Pod לשכפול של ZooKeeper.
  • ‫2 PodDisruptionBudgets, כדי להבטיח זמינות מינימלית של שני עותקים לשמירה על עקביות האשכול.
  • שירות בשם my-cluster-kafka-bootstrap, שמשמש כשרת bootstrap ללקוחות Kafka שמתחברים מתוך אשכול Kubernetes. כל מאזיני Kafka הפנימיים זמינים בשירות הזה.
  • שירות ללא ראש שנקרא my-cluster-kafka-brokers שמאפשר תרגום DNS של כתובות ה-IP של פודים של ברוקרים של Kafka באופן ישיר. השירות הזה משמש לתקשורת בין ברוקרים.
  • שירות בשם my-cluster-zookeeper-client שמאפשר למתווכי Kafka להתחבר לצמתי ZooKeeper כלקוחות.
  • שירות ללא ראש שנקרא my-cluster-zookeeper-nodes ומאפשר פתרון DNS של כתובות IP של ZooKeeper Pod ישירות. השירות הזה משמש לחיבור בין רפליקות של ZooKeeper.
  • פריסת Deployment בשם my-cluster-entity-operator שמכילה את topic-operator ו-user-operator ומאפשרת ניהול של משאבים מותאמים אישית KafkaTopics ו-KafkaUsers.

אפשר גם להגדיר שני NetworkPolicies כדי לאפשר קישוריות למאזיני Kafka מכל Pod ומרחב שמות. כללי המדיניות האלה גם יגבילו את החיבורים ל-ZooKeeper למתווכים, ויאפשרו תקשורת בין ה-Pods של האשכול לבין יציאות שירות פנימיות שמוגבלות לתקשורת באשכול.

אימות וניהול משתמשים

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

‫Strimzi מספק שיטה מקורית ב-Kubernetes לניהול משתמשים באמצעות User Operator נפרד ומשאב Kubernetes מותאם אישית תואם, KafkaUser, שמגדיר את תצורת המשתמש. הגדרת המשתמש כוללת הגדרות לאימות ולהרשאה, ומקצה את המשתמש המתאים ב-Kafka.

‫Strimzi יכול ליצור מאזינים ומשתמשים של Kafka שתומכים בכמה מנגנוני אימות, כמו אימות שמבוסס על שם משתמש וסיסמה (SCRAM-SHA-512) או TLS. אפשר גם להשתמש באימות OAuth 2.0, שלרוב נחשב לגישה טובה יותר בהשוואה לשימוש בסיסמאות או באישורים לאימות, בגלל האבטחה וניהול פרטי הכניסה החיצוניים.

פריסת אשכול Kafka

בקטע הזה מוסבר איך לפרוס אופרטור של Strimzi שמדגים יכולות של ניהול משתמשים, כולל:

  • קלאסטר Kafka עם אימות מבוסס-סיסמה (SCRAM-SHA-512) שמופעל באחד מהמאזינים.
  • KafkaTopic עם 3 העתקים.
  • KafkaUser עם רשימת ACL שבה מצוין שלמשתמש יש הרשאות קריאה וכתיבה בנושא.
  1. מגדירים את אשכול Kafka לשימוש במאזין עם אימות SCRAM-SHA-512 מבוסס-סיסמה ביציאה 9094 והרשאה פשוטה:

    kubectl apply -n kafka -f kafka-strimzi/manifests/03-auth/my-cluster.yaml
    
  2. יוצרים Topic, User ו-Pod של לקוח כדי להריץ פקודות מול אשכול Kafka:

    kubectl apply -n kafka -f kafka-strimzi/manifests/03-auth/topic.yaml
    kubectl apply -n kafka -f kafka-strimzi/manifests/03-auth/my-user.yaml
    

    Secret my-user עם פרטי הכניסה של המשתמש מותקן ב-Pod של הלקוח כVolume.

    פרטי הכניסה האלה מאשרים שלמשתמש יש הרשאות לפרסם הודעות בנושא באמצעות מאזין עם אימות מבוסס-סיסמה (SCRAM-SHA-512) מופעל.

  3. יוצרים תרמיל לקוח:

    kubectl apply -n kafka -f kafka-strimzi/manifests/03-auth/kafkacat.yaml
    
  4. ממתינים כמה דקות עד שה-Pod של הלקוח יהפוך ל-Ready ואז מתחברים אליו:

    kubectl wait --for=condition=Ready pod --all -n kafka --timeout=600s
    kubectl exec -it kafkacat -n kafka -- /bin/sh
    
  5. יוצרים הודעה חדשה עם פרטי הכניסה my-user ומנסים לצרוך אותה:

    echo "Message from my-user" |kcat \
      -b my-cluster-kafka-bootstrap.kafka.svc.cluster.local:9094 \
      -X security.protocol=SASL_SSL \
      -X sasl.mechanisms=SCRAM-SHA-512 \
      -X sasl.username=my-user \
      -X sasl.password=$(cat /my-user/password) \
      -t my-topic -P
    kcat -b my-cluster-kafka-bootstrap.kafka.svc.cluster.local:9094 \
      -X security.protocol=SASL_SSL \
      -X sasl.mechanisms=SCRAM-SHA-512 \
      -X sasl.username=my-user \
      -X sasl.password=$(cat /my-user/password) \
      -t my-topic -C
    

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

    Message from my-user
    % Reached end of topic my-topic [0] at offset 0
    % Reached end of topic my-topic [2] at offset 1
    % Reached end of topic my-topic [1] at offset 0
    

    מקלידים CTRL+C כדי להפסיק את התהליך של החשבון לשימוש פרטי.

  6. יציאה מהמעטפת של ה-Pod

    exit
    

גיבויים ותוכנית התאוששות מאסון (DR)

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

אפשר להשתמש בגיבוי ל-GKE כדי לגבות:

  • מניפסטים של משאבים ב-Kubernetes.
  • משאבים מותאמים אישית של Strimzi API וההגדרות שלהם, שחולצו משרת ה-API של Kubernetes באשכול שעובר גיבוי.
  • נפחי אחסון שתואמים למשאבי PersistentVolumeClaim שנמצאו במניפסטים.

אפשר גם לבצע גיבוי של אשכול Kafka שנפרס באמצעות האופרטור Strimzi. אתם צריכים לגבות:

  • ההגדרה של Kafka, שכוללת את כל המשאבים המותאמים אישית של Strimzi API, כמו KafkaTopics ו-KafkaUsers.
  • הנתונים, שמאוחסנים ב-PersistentVolumes של ברוקרי Kafka.

אחסון של מניפסטים של משאבי Kubernetes, כולל הגדרות Strimzi, במאגרי Git יכול לבטל את הצורך בגיבוי נפרד של הגדרות Kafka, כי אפשר להחיל מחדש את המשאבים על אשכול Kubernetes חדש כשצריך.

כדי להגן על שחזור נתונים של Kafka בתרחישים שבהם מופעלת מכונת שרת Kafka או אשכול Kubernetes שבו Kafka פרוס, מומלץ להגדיר את מחלקת האחסון של Kubernetes שמשמשת להקצאת נפחי אחסון עבור ברוקרים של Kafka עם האפשרות reclaimPolicy שמוגדרת ל-Retain. מומלץ גם לצלם תמונות מצב של נפחי Kafka broker.

המאניפסט הבא מתאר StorageClass שמשתמש באפשרות reclaimPolicyRetain:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: premium-rwo-retain
...
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer

בדוגמה הבאה מוצג StorageClass שנוסף ל-spec של משאב מותאם אישית של אשכול Kafka:

# ...
spec:
  kafka:
    # ...
    storage:
      type: persistent-claim
      size: 100Gi
      class: premium-rwo-retain

במקרה כזה, נפחי אחסון קבועים (PersistentVolumes) שהוקצו באמצעות מחלקת האחסון לא נמחקים גם כשבקשת נפח האחסון הקבוע (PersistentVolumeClaim) המתאימה נמחקת.

כדי לשחזר את מופע Kafka באשכול Kubernetes חדש באמצעות ההגדרה הקיימת ונתוני מופע הברוקר:

  1. החלת משאבי Strimzi Kafka מותאמים אישית קיימים (Kakfa,‏ KafkaTopic,‏ KafkaUser וכו') על אשכול Kubernetes חדש
  2. מעדכנים את ה-PersistentVolumeClaims עם השם של מופעי ברוקר Kafka החדשים ל-PersistentVolumes הישנים באמצעות המאפיין spec.volumeName ב-PersistentVolumeClaim.

הסרת המשאבים

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

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

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

    gcloud projects delete PROJECT_ID

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

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

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

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

    export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
    terraform -chdir=kafka/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)")
    

    השלב הזה נדרש כי כברירת מחדל, Strimzi משתמש בפרמטר deleteClaim: false לאחסון. אם מוחקים את האשכול, כל הדיסקים נשארים זמינים.

  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
    

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