• בלוג
  • מדריך: תמיכה במספר סביבות קוברנטס עם Kustomize

מדריך: תמיכה במספר סביבות קוברנטס עם Kustomize

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

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

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

המנגנון המובנה ב kubectl לניהול שינויים בין סביבות נקרא kustomize. בפוסט זה אציג דוגמה פשוטה לפרויקט שמשתמש ב kustomize כדי לייצר קבצי yaml שונים לסביבות השונות.

1. איך זה עובד

קסטומייז מחלק את קבצי ה yaml של קוברנטס ל-3 תיקיות מרכזיות:

  1. תיקיית base שם נמצאים קבצי ה yaml ה"בסיסיים", לפני שהתאמנו אותם לסביבות מסוימות. זה בעצם החלק שמשותף לכל הסביבות. בתיקיה זו יהיה קובץ בשם kustomization.yaml שמהווה סוג של אינדקס לכל הקבצים בתיקיה.

  2. תיקיית components, בתוכה אפשר ליצור תיקיה לכל "פיצ'ר" של הקלאסטר, ובתוך תיקיית הפיצ'ר יהיו כל קבצי ה yaml של אותו הפיצ'ר (או הקומפוננט).

  3. תיקיית overlays שבתוכה תהיה תיקיה לכל סביבה. בתוך כל תיקיית סביבה יהיה קובץ kustomization.yaml שמכיל הוראות להתאמה של קבצי ה yaml מ base ומ components עבור סביבה זו.

זה אומר שאם יש לי פרויקט שבסביבת פרודקשן צריך איזה ג'וב מיוחד שלא קיים בסביבת פיתוח, אני יכול ליצור תת תיקיה בתוך components עם השם של הג'וב, בתוכה לשים את קובץ ה yaml המתאים לג'וב הזה, ואז בתוך overlays/production/kustomization.yaml לבקש להוסיף את הקומפוננטה של הג'וב להגדרות הבניה בסביבת פרודקשן.

או אם אני צריך ליצור יותר replications בסביבת production, אז יהיה לי בקובץ overlays/production/kustomization.yaml הוראה שאומרת שצריך לשנות את שדה replication של אוביקט deployment מסוים לערך גבוה יותר.

2. דוגמה - פרויקט שכולל מיפוי תיקיה רק בסביבת פרודקשן

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

מבנה התיקיות של הפרויקט נראה כך:

.
├── base
│   ├── kustomization.yaml
│   ├── redis-deployment.yaml
│   └── redis-service.yaml
├── components
│   └── datavolume
│       ├── data-persistentvolumeclaim.yaml
│       ├── kustomization.yaml
│       └── redis-deployment.yaml
├── docker-compose.yml
└── overlays
    ├── dev
    │   └── kustomization.yaml
    └── production
        └── kustomization.yaml

6 directories, 9 files

תיקיית הבסיס כוללת את שני ה yaml-ים של redis שנדרשים בשביל להפעיל את השרת.

בתיקיית components יש לי תת-תיקיה שנקראת datavolume ובתוכה קובץ yaml שיוצר Volume ולידו קובץ yaml באותו שם של קובץ yaml בסיסי (נקרא redis-deployment.yaml) שיכלול רק את השינויים בקובץ ה deployment שיופעלו אם "קומפוננטה" זו משולבת בבניה.

ובתיקיית overlays יש לי תיקיות עבור כל סביבה dev ו production.

3. תיקיית base

עכשיו נראה את הקבצים בכל תיקיה. תחילה ב base הקובץ הכי מעניין הוא kustomization.yaml שמהווה סוג של אינדקס על תיקיית הבסיס:

resources:
- redis-deployment.yaml
- redis-service.yaml

כל מה שיש בקובץ זה מפתח יחיד בשם resources שמכיל מערך של קבצי yaml ששייכים לפרויקט.

תוכן הקובץ redis-deployment.yaml הוא:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    kompose.cmd: kompose convert -f ../docker-compose.yml
    kompose.version: 1.25.0 (a70f80cc)
  creationTimestamp: null
  labels:
    io.kompose.service: redis
  name: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      io.kompose.service: redis
  strategy:
    type: Recreate
  template:
    metadata:
      annotations:
        kompose.cmd: kompose convert -f ../docker-compose.yml
        kompose.version: 1.25.0 (a70f80cc)
      creationTimestamp: null
      labels:
        io.kompose.service: redis
    spec:
      containers:
        - image: redis:6.2
          name: redis
          lifecycle:
            postStart:
              exec:
                command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
          ports:
            - containerPort: 6379
          resources: {}
      restartPolicy: Always
status: {}

ותוכן הקובץ redis-service.yaml הוא:

apiVersion: v1
kind: Service
metadata:
  annotations:
    kompose.cmd: kompose convert -f ../docker-compose.yml
    kompose.version: 1.25.0 (a70f80cc)
  creationTimestamp: null
  labels:
    io.kompose.service: redis
  name: redis
spec:
  ports:
    - name: "6379"
      port: 6379
      targetPort: 6379
  selector:
    io.kompose.service: redis
status:
  loadBalancer: {}

4. תיקיית components/datavolume

התיקיה השניה היא הקומפוננטה אותה נרצה לשלב בבניה בסביבה מסוימת. אפשר לבנות כמה קומפוננטות שאתם רוצים בתור תתי תיקיות של תיקיית components. לכל קומפוננטה יש קובץ kustomization.yaml ושלי נראה כך:

apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component

resources:
- data-persistentvolumeclaim.yaml

patchesStrategicMerge:
  - redis-deployment.yaml

הקובץ אומר שאם אתם משלבים קומפוננטה זו אתם צריכים להוסיף את הקובץ data-persistentvolumeclaim.yaml ובנוסף אליו צריכים לעשות Merge לערכים מהקובץ redis-deployment.yaml שנמצא אצלי בתיקיה. הקובץ redis-deployment.yaml הוא המעניין בין השניים אז נתחיל איתו:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  template:
    spec:
      containers:
        - name: redis
          volumeMounts:
            - mountPath: /data
              name: data
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: data

ואנחנו רואים שזה לא קובץ Deployment מלא אלא רק החלק מהקובץ שמתעסק עם ה mount של ה volume החדש. מה שמאוד חשוב בקובץ זה שה metadata.name יהיה זהה לאותו deployment אותו רוצים לעדכן.

הקובץ האחרון בקומפוננטה הוא data-persistentvolumeclaim.yaml ותוכנו הוא:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  creationTimestamp: null
  labels:
    io.kompose.service: data
  name: data
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Mi
status: {}

זה כבר קובץ yaml מלא שיוצר PersistentVolumeClaim. בגלל שהוא בתוך הקומפוננטה ולא בתוך base, אז רק סביבות שישתמשו בקומפוננטה זו יפעילו אותו.

5. תיקיית overlays/dev

הסביבה הראשונה היא dev והיא מכילה רק קובץ kustomization.yaml יחיד. זה התוכן שלו:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ../../base

והוא למעשה מציין סביבה זהה לגמרי ל base. בסביבת הפיתוח אין שום תוספת ושום שינוי.

6. תיקיית overlays/production

סביבת הייצור זה כבר סיפור אחר כי היא צריכה להוסיף את הקומפוננטה שיצרנו. הנה הקובץ overlays/production/kustomization.yaml שמתאר את הסביבה:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ../../base

components:
  - ../../components/datavolume

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

7. איך לבנות קבצי הגדרות לקלאסטר

אחרי שכל ה yaml-ים במקום אני יכול להריץ:

$ kubectl kustomize overlays/production

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

$ kubectl kustomize overlays/production | kubectl apply -f -

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

$ kubectl kustomize overlays/dev | kubectl apply -f -

8. איפה לומדים עוד

התיעוד של קוברנטס כולל כמה פרקים על kustomize אז אם אתם אוהבים לקרוא את התיעוד של קוברנטס זה יכול לשמח אתכם. הדף הרלוונטי הוא בקישור הזה: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/.

אני מוצא שבעבודה עם קוברנטס הרבה יותר קל לי להסתכל על דוגמאות עובדות ועם kustomize זה קל כי יש תיקיית דוגמאות די טובה בדף הגיטהאב של הפרויקט בקישור: https://github.com/kubernetes-sigs/kustomize/tree/master/examples.