שיעור היכרות עם Terragrunt
פורסם בתאריך 3 בנובמבר 2024
בשיעור קודם קיבלנו היכרות עם פרוייקט ה - infrastructure as code שלנו, יצרנו פרוייקט GCP, VPC, GKE, והפעלנו את FluxCD בקלאסטר שלנו באמצעות OpenTofu.
במהלך קורס זה אנחנו מתמקדים על best practices, זהו למה כל המשאבים בענן שלנו צריכים להיות נוצרים באמצעות IAC (במקרה שלנו Terraform/OpenTofu), עלינו להתרגל להשתמש ב IAC ליצירת המשאבים בענן שלנו, ותיקיית הקורס מתמקדת לא רק להיות קוד המקור של השיעורים שלנו אלא גם ערכת הכלים שאתה יכול לבסס עליה את הפרוייקטים האמיתיים שלך.
כאשר עובדים על פרוייקטים אמיתיים יש לנו לעיתים קרובות יותר מסביבות אחת, ויותר מקלסטר אחד, ואנחנו צריכים לנהל אותם בדרך שתהיה קלה לתחזוקה ולהתרחבות.
אותן הסביבות ישתנו במשאבים שיש להם, בהגדרות שהם משתמשים בהם, ואנחנו צריכים להתמודד עם ההבדלים האלה בקורס זה.
יתרה מכך יש לנו צורך לנהל את ההרשאות של הפרוייקטים שלנו, ולהפריד את ההרשאות של הפרוייקטים השונים, הצוותים, הפרוייקטים, ה devops, והמפתחים, כל אחד מהם יצטרך הרשאות מינימליות ליצירת התשתיות שהם צריכים.
כאשר יוצרים תשתיות חשוב ליצור מודולים קטנים ולהשתמש בהם כמה שיותר. לדוגמא מאחר והרבה מהסביבות יצרו קלאסטר K8S מנוהל (באמצעות GKE) אנחנו יכולים ליצור מודול לכך ולהשתמש בו בכל סביבה שיש לה קלאסטר K8S. כאשר משתמשים במודול כזה בסביבה, ייווצר עבורו state של terraform, ואנחנו רוצים לשמור את ה state בצורה מאובטחת בתוך bucket. האם זה אומר שנצטרך להגדיר מחדש את ה backend של כל מודול שנשתמש בו? ואם כן, האם זה אומר שנצטרך להגדיר מחדש את ה backend של כל מודול שנשתמש בו, ולהגדיר מחדש את הספקים של כל מודול שנשתמש בו? התשובה היא לא, ובשיעור זה נלמד איך להשתמש ב - Terragrunt כדי לנהל את ההתקנות שלנו בצורה נכונה ומאורגנת תוך כדי מניעת DRY violations.
שיעור זה יהווה היכרות ראשונית עם Terragrunt ונלמד כיצד לארגן את הפרוייקט IAC שלנו באמצעות Terragrunt, נלמד כיצד לפצל את הפרוייקט שלנו למודולים קטנים, נלמד כיצד למנוע DRY violations באמצעות Terragrunt, ונלמד כיצד לנהל את התלותים שלנו באמצעות Terragrunt.
תוכנית השיעור
זהו שיעור היכרות עם שבו נתחיל לנהל את פרוייקט ה IAC שלנו באמצעות Terragrunt. נלמד את הנושאים הבאים:
- היכרות עם Terragrunt
- מבנה התיקיות
- יצירת ה -
terragrunt.hcl
בשורש הפרוייקט - יצירת קונפיגורציות שחוזרות על עצמן
- יצירת common שיכיל תיקיות ופרוייקט
- איחסון ה state ב bucket
הרגל רע: פרוייקט IAC מונוליטי
יצירת פרוייקט infastructure שמורכב מיחידת state אחת עצומה בגודלה הוא רעיון רע שמומלץ בחום להימנע ממנו. הנקודה מוסברת בצורה ברורה בהרצאה הבאה: The following lecutre אבל אני אסכם את הנקודות העיקריות:
- איטיות - ככל שהתשתיות גדלה, פעולות פשוטות כמו
terragrunt plan
יקחו זמן רב plan/output
בלתי אפשרי להבנה - מתקבל תוצאת plan עצומה שקשה להבין, לעקוב אחריה, וקל לפספס דברים חשובים בתוך התוכנית כמו דברים חשובים שימחקו (אם יש לכם מאות שינויים זה יהיה קל לפספס)- קשה לכתוב טסטים
- קושי בשימוש חוזר בחלקי קוד
- אבטחה - תצטרכו לספק הרשאות כל-יכול למי שמריץ את הקוד
- מקביליות של הרצה של מספר מפתחים היא יותר קשה
- קל לטעות והנזק יהיה יותר משמעותי
מודולים גדולים בקוד התשתיות עושים נזק וקשים לתחזוקה.
במקרה שלנו מהשיעור הקודם יש לנו פרוייקט מונוליטי עם state אחד שנוצר מקובץ main.tf
אחד.
צריך לשאוף לפצל את הפרוייקט למודולים קטנים עם כמה שיותר בידוד, בידוד על פי סביבות ובידוד על פי סוגי התשתיות שצריך ליצור.
צריך לפצל את המודול הגדול למודולים קטנים, מבודדים ככל האפשר, מחולקים לפי סוגי התשתיות שהם יוצרים, ולנהל את התלותים ביניהם.
הרגל רע: ניהול מודולים קטנים מבודדים באמצעות Terraform/OpenTofu
במקום פרוייקט IAC אחד גדול עם state אחד, נחלק אותו למודולים קטנים עם state משלהם, אם ננסה לנהל את זה באמצעות Terraform/OpenTofu נתקל בקשיים:
- חזרה על הקונפיגורציות של ה - Providers
- חזרה על הקונפיגורציות של אחסון ה - state בתוך bucket
- משתנים שחוזרים על עצמם
- קושי בניהול התלות בין המודולים השונים
- קושי בהרצת
apply
על מספר מודולים ובסדר הנכון - קושי בשימוש חוזר בקוד
מומלץ להשתמש ב - Terragrunt כדי לנהל את המודולים הקטנים בצורה נכונה ומאורגנת.
היכרות עם Terragrunt
Terragrunt יעטוף לנו את ה - Terraform/OpenTofu ויספק לנו כלים נוספים לניהול מודולים רבים.
כל מודול יכיל קובץ terragrunt.hcl
שיכול לכלול הגדרות providers שחוזרים על עצמם, לכלול קוד שחוזר על עצמו, לטעון משתנים חוזרים, ובאופן כללי להתמקד בדברים החדשים שהמודול עושה תוך כדי מינימום חזרה על קוד קיי והגדרות שחוזרות שהיינו צריכים לכלול אם היינו עובדים עם Terraform/OpenTofu בלבד.
כל מודול שניצור יכיל state נפרד שיאוחסן ב bucket.
באמצעות Terragrunt נוכל ליצור סביבת פרודקשיין וסביבת נון פרודקשיין, שמורכבים ממודולים שחוזרים על עצמם, עם שימוש ללא שכפול קוד במודולים שחוזרים על עצמם.
Terragrunt cli
ניתן להתקין את Terragrunt באמצעות הפקודה:
כפי שהזכרנו Terragrunt הוא מעטפת זעירה סביב terraform, אז כל פקודה שהיינו מריצים באמצעות הפקודה terraform/tofu עכשיו הופכת להיות terragrunt (terragrunt תעביר את הפקודה ל terraform/tofu).
בנוסף terragrunt יוסיף פקודות נוספות שיעזרו לנו בניהול מודולים רבים.
לדוגמא נוכל להריץ terragrunt run-all apply
כדי להפעיל שינויים בכל המודולים תחת התיקייה שאנחנו נמצאים בה.
Terragrunt יעזור לנו בניהול פרוייקט שמורכב ממודולים קטנים
באמצעות Terragrunt יהיה קל לנו לנהל פרוייקט IAC שנבנה ממודולים קטנים. Terragrunt יעזור לנו לנהל את התלותיות בין אותם המודולים, ויעוזר לנו להריץ את אותן המודולים בסדר הנכון תוך כדי התחשבות באותן התלותיות בין המודולים. באמצעות Terragrunt ניתן להימנע מ - DRY violations, ולנהל את ההגדרות החוזרות במקום אחד. נראה דוגמא לכך במהלך השיעור.
מבנה התיקיות
מבנה התיקיות משחק תפקיד חשוב בפרוייקט Terragrunt. אנחנו משתמשים הרבה ב - composition (נקרא לזה כאן inheritance אף על פי שזה יותר דומה ל composition) ב Terragrunt, וההתייחסות להורשה היא על פי מבנה התיקיות. בדרך כלל נשים את הלוגיקה המשותפת בתיקיית ההורה, והיא יכולה להיות נגישה לתיקיות הילד. נעבור על מבנה התיקיות של הפרוייקט שלנו:
Loading graph...
נעבור על התוכנית:
_env
- תיקיית ה -_env
מכילה פונקציות terragrunt ליצירת רכיב כךשהוא.common
- תיקיית ה -common
מכילה רכיבים שמשותפים לכל הסביבות.prod/non-prod
- תיקיות ה -prod
וה -non-prod
מכילות את הסביבות שלנו (נציג את הסביבות בשיעורים הבאים).auth
- תיקיית ה -auth
מכילה groups, users, service accounts, והרשאות שנשתמש בהן לאימות עם הענן.
פונקציות, בלוקים, ו - attributes של Terragrunt
אומרים ל Terragrunt איך לעבוד באמצעות קבצי קונפיגורציה שכתובים ב - HCL. לקבצי הקונפיגורציה ניתן להשתמש במספר דברים יחודיים ל - Terragrunt וגם בפונקציות של Terraform/OpenTofu.
נעבור על מספר דברים ש Terragrunt הוסיף שניתן להשתמש בקבצי הקונפיגורציה, ונסביר על אותם האלמנטים שבהם נשתמש בשיעור זה.
בלוקים
לקבצי הקונפיגורציה של terragrunt נשתמש בבלוקים הבאים:
locals {}
- מאפשר להגדיר משתנים מקומיים שניתן להשתמש בהם בקובץ הקונפיגורציה.generate "someName" {}
- מאפשר ליצור קובץ חדש בזמן הריצה שיכיל קוד חדש.include "someName" {}
- מאפשר לכלול קובץ קונפיגורציה אחר בקובץ הקונפיגורציה.dependency "someName" {}
- מאפשר להגדיר תלות בין מודולים.terraform {}
- הרצת קוד terraform בקובץ הקונפיגורציה.remote_state {}
- הגדרת אחסון ה state ב bucket.
attributes ופונקציות
להגדרת terragrunt נשתמש בפונקציות וב attributes הבאים:
inputs = {}
- הגדרות variables ואתחולם שמועברים לקוד ה - terraform שמחובר.find_in_parent_folders()
- מחפש קובץ בתיקיות ההורה.path_relative_to_include()
- מחזיר את הנתיב של המודול שהריץ את הקוד יחסית לנתיב של הקובץ שהריץ את הפונקציה.
פונקציות ב - Terraform/OpenTofu
בקבצי הקונפיגורציה של terragrunt ניתן עדיין להשתמש בפונקציות של terraform/OpenTofu, כאשר נשתמש בפונקציות של terraform/OpenTofu נשתמש בהן באופן רגיל כמו שהיינו עושים בקובץ הקונפיגורציה של terraform/OpenTofu. להלן רשימה של פונקציות שנשתמש בהן בשיעור זה:
dirname()
- מחזיר את שם התיקייה של הקובץ.file()
- קורא את תוכן הקובץ.yamldecode()
- ממיר קובץ yaml למשתנה.
יצירת ה - terragrunt.hcl
בשורש הפרוייקט
הפרוייקט IAC שלנו נמצא בתיקייה /iac/gcp/tofu
, ובתיקייה זו ניצור את הקובץ terragrunt.hcl
שיכיל את ההגדרות המשותפות לכל המודולים.
ניצור את הקובץ terragrunt.hcl
בתיקיית הפרוייקט ונכניס אליו את ההגדרות הבאות:
נשים לב למספר נקודות:
- ישנם משתנים שהולכים לחזור על עצמם במודולים רבים, את אותם המשתנים מאגדים תחת לוגיקה והקשר מסויים, ושמים אותם בקבצים כמו:
common_vars.yaml
,region_vars.yaml
,billing_vars.yaml
. ניתן למצוא את חלק מהקבצים האלו, וחלק מוסתרים אז ניתן לראות את הקבצים עם סיומת שלexample.yaml
בתיקיית הפרוייקט. למרות שאותם משתנים מוגדרים בקבצים ניתן לעקוף אותם במידה ויוצרים קובץ עם שם דומה בתיקייה פנימית של המודול. - אנחנו מגדירים את ה google provider ובנתיים לצורך האימות הוא ישתמש במשתנה שלנו ב gcp. לא צריך להגדיר את ה google provider במודולים הפנימיים שפשוט יכללו את ההגדרות ששמנו פה.
הגדרות הבסיסיות האלה בשורש הפרוייקט יאפשרו לנו להתחיל ליצור את המשאבים הדרושים. יש לוודא שמתחברים ל gcp על ידי הרצת הפקודה:
_env - Folder, Project
תיקיית ה - _env
תכיל קונפיגורציות שחוזרות על עצמן, מאן פונקציות לשימוש חוזר בקוד.
ה - _env
תשתמש במידה רבה במודולים של הפרוייקט: terraform-google-modules.
ניתן גם לקודד את ה input ים שחוזרים על עצמם באותם הקבצים זה יחסוך את העבודה של להכניס אינפוטים שחוזרים על עצמם.
בתוך התיקייה /iac/gcp/tofu/_env
ניצור את הקבצים: folder.hcl
, project.hcl
.
אחרי שיצרנו את הפונקציות terragrunt שלנו המבוססות על terraform-google-modules
, נוכל להשתמש בקונפיגורציות הפונקציות האלו כדי ליצור משאבים שנצטרך כדי ליצור את ה state ב bucket.
Common - Folder, Project
נשתמש במודולים שיצרנו ב - _env
כדי ליצור את ה - common
שבו ניצור את ה folder, project.
ניצור מספר קבצים:
common/folders/root/terragrunt.hcl
- זה יצור את התיקייה הראשיתacademeez-k8s-flux
common/folders/shared/terragrunt.hcl
- תחת התיקייה הראשית ניצור תיקייה שנקראתshared
למשאבים שמשותפיםcommon/project/terragrunt.hcl
- זה יצור את הפרוייקטacademeez-k8s-flux-common
אנחנו משתמשים בקונפיגורציות שיצרנו בתיקיית _env
כדי ליצור תיקיית root, shared, ופרוייקט שיכיל את המשאבים המשותפים.
כמה נקודות לשים לב:
- כאשר נרצה להגיד ל terragrunt ליצור משאבי ענן, בדרך כלל אנחנו נכלול את הקונפיגורציות שרשמנו ב terragrunt.hcl ששמנו בשורש של הפרוייקט.
את זה אנחנו עושים בבלוק ה include הראשון
include "root" {}
ואנחנו מגיעים לשורש הפרוייקט על ידי קריאה לפונקציהfind_in_parent_folders()
שיצביע לקובץ ה terragrunt.hcl שבשורש הפרוייקט. וכדי לקבל רק את תיקיית השורש נעטוף את זה בפונקציהdirname(find_in_parent_folders())
. - אנחנו משתמשים ב
dependency
block כדי לקבל את התלות בין המודולים, לדוגמא במודול של הפרוייקט המשותף אנחנו משתמשים בתלות בין המודול של הפרוייקט לתיקיית ה shared. זה יוצרת תלות בין המודולים והמודול יחכה ליצירת התיקייה ה shared לפני שהוא ייצור את הפרוייקט. Terragrunt יסייע לנו לנהל את התלות בין המודולים ולהריץ אותם בסדר הנכון. - שימו לב שאנחנו נאחסן את הפרוייקט שאנחנו יוצרים ב
common_vars.yaml
תחת המשתנהcommon_project
ונשתמש בו במודולים הבאים.
אחרי שכל הקוד נכתב אנחנו יכולים להריץ את כל המשאבים שיצרנו בפקודה אחת:
אחסון ה state ב bucket
ברירת המחדל של terragrunt היא לשמור את ה state באופן מקומי על הדיסק תחת התיקייה .terragrunt-cache
.
אנחנו צריכים להגדיר את הדברים בצורה יותר מאובטחת ולשמור את ה state במקום מרוחק, לשתף את ה state בין מפתחים, ולהגן עליו מפני אסונות באמצעות versioning, ולאפשר rollback.
מומלץ לאחסן את ה - state ב bucket ב GCP.
במקום לחזור על הקונפיגורציות אחסון האלה, אנחנו נגדיר את הכל במקום אחד בקובץ terragrunt.hcl
שבשורש הפרוייקט.
בצורה כזו נשתף את הקונפיגורציות האלה בין כל המודולים.
נעדכן את הקובץ terragrunt.hcl
שבשורש הפרוייקט כך:
בדוגמא זו אנחנו משתמשים ב - terragrunt
remote_state
block כדי לאחסן את ה state ב bucket מרוחק.
קונפיגורציה זו תכלל בכל המודולים ובאמצעות הפונקציה path_relative_to_include()
נשמור את ה state במיקום שונה ב bucket לכל מודול לפי המיקום שלו בפרוייקט.
ה - remote_state
block ייצור את ה bucket בפעם הראשונה.
אחרי שהוספנו את הקוד הזה נוכל להעביר את כל ה state ל bucket באמצעות הפקודה:
סיכום
בשיעור זה למדנו על כלי שנשתמש בו בפרוייקט IAC שלנו שנקרא Terragrunt.
באמצעות Terragrunt נוכל לנהל את המודולים שלנו בצורה נכונה ומאורגנת, לנהל את התלות בין המודולים, ולהימנע מקוד שחוזר על עצמו.
אנחנו אומרים ל Terragrunt איך לעבוד על ידי יצירת קבצי קונפיגורציות בקבצי terragrunt.hcl
בנוסף נשתמש הרבה בירושה כדי להגדיר דברים שחוזרים על עצמם במקום אחד.
בנוסף הצלחנו גם להימנע ממשתנים שחוזרים על עצמם על ידי קידוד שלהם בקבצים חיצוניים.
נמשיך לעבוד עם Terragrunt גם בשיעור הבא כאשר נוסיף אימות והרשאות, ונלמד איך לעשות את זה בצורה נכונה.