הגדרת Vagrant לסביבות פיתוח מקומיות: מכונות וירטואליות משוחזרות

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

היכולות שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

הגדרת Vagrant: מדוע סביבות שונות בין מפתחים

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

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

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

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

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

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

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

סביבת פיתוח ניתנת לשחזור: מה משתנה בעבודה

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

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

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

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

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

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

הגדרת Vagrant או מכולות: אפשרויות לסביבות מקומיות

סביבה מקומית היא פשרה בין דיוק השחזור של סביבת העבודה לזמן העלאתה. Vagrant מתאר מכונה באופן דקלרטיבי: ב-Vagrantfile נרשמים ה-image, הפניות הרשת, התיקיות המשותפות והספק, והפרוביז'נינג בסקריפטים או ב-Ansible מביא את המערכת למצב הרצוי. מהנדס חדש מקבל סביבה זהה בפקודה אחת, ולא לפי הוראה בת עשרה שלבים.

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

אפשרות מתי מתאימה מגבלות
מכונה וירטואלית (Vagrant) נדרשת סביבה קרובה לשרת העבודה: ליבה משלה, שירותי מערכת, הגדרות רשת צורכת יותר משאבי מארח, העלאה ובנייה מחדש ארוכות יותר ממכולה
מכולה האפליקציה והתלותים שלה, מחזור עריכות מהיר, סביבות מקבילות ליבה משותפת עם המארח: חלק מתרחישי המערכת אינם משוחזרים
מערכת משותפת ברשת אינטגרציה של כמה שירותים, בדיקות על נתונים אמיתיים משאב משותף: עריכות של אחד שוברות את האחרים, אין בידוד
הרכבה ידנית חקירה חד-פעמית של בעיה, חומרה לא סטנדרטית אינה ניתנת לשחזור: מצב המכונות סוטה, הזמן להעלאה אינו מתקצר

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

סדר ההטמעה: מתיאור המכונה ועד מסירה לצוות

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

  1. סקירת הדרישות הנוכחיות. מתעדים אילו שירותים נדרשים להרצת הפרויקט, אילו גרסאות runtime ומסד נתונים בשימוש, אילו פורטים ותיקיות נתונים מעורבים. בנפרד רושמים את מה שהמפתחים מתקינים ביד ומה שהכי סוטה בין המכונות.
  2. סכימת המערכת. קובעים את מספר המכונות ותפקידיהן, את הקשרים ביניהן ברשת, את הכרכים המשותפים ונקודות הכניסה. בשלב זה ניכר היכן צומת אחד מספיק והיכן נדרשת מכונה נפרדת למסד נתונים או למטמון.
  3. תיאור המכונה. מכינים קונפיגורציה: image בסיסי, משאבים מוקצים, הפניית פורטים, תיקיות מסונכרנות. כל מה שקודם חי בהוראה של "תעשה כך" עובר לקובץ.
  4. הכנה אוטומטית. התקנת חבילות, הגדרת שירותים, יישום מיגרציות וטעינת נתוני בדיקה מתבצעים בסקריפטים בהרצה הראשונה. הסקריפטים אידמפוטנטיים — הרצה חוזרת אינה שוברת סביבה שכבר הוגדרה.
  5. בדיקה על מערכת נקייה. מעלים את המערכת מאפס על מכונה ללא מטמון מקומי, images ותלותים שמורים. מודדים את הזמן עד למצב עבודה מלא ומוודאים שהשלבים אינם נשענים על מערך כלים אישי של מישהו.
  6. מסירה והדרכה. מוסרים את הריפוזיטורי עם הקונפיגורציה, הוראה קצרה להפעלה, עצירה ובנייה מחדש, וניתוח של תקלות אופייניות. מסכמים מי אחראי לעדכון ה-image הבסיסי בעת החלפת גרסאות.

קונפיגורציה, סכימות ותקנות לצוות

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

  • קובץ תיאור הסביבה — נקודת האמת היחידה: גרסת ה-image הבסיסי, משאבי המכונה, הפניית פורטים, תיקיות מסונכרנות. משתנה רק דרך בדיקה, כמו קוד רגיל.
  • סקריפטים של הגדרה ראשונית — התקנת תלותים, יצירת משתמשים, מיגרציות ומילוי בנתוני בדיקה. אידמפוטנטיים: הרצה חוזרת אינה שוברת סביבה שכבר נבנתה.
  • סכימת המערכת — אילו מכונות נכללות בקונטור, כיצד הן רואות זו את זו ברשת, אילו שירותים נגישים מהמארח. הסכימה מסירה שאלות של "למה אצלי הפורט לא נפתח".
  • תקנון עדכון — תדירות הבנייה מחדש של ה-image הבסיסי, מערך הבדיקות לפני הוצאת גרסה חדשה ונקודת חזרה לקודמת.
  • כללי גרסאות — שינויים בסביבה עוברים בענף ותג נפרדים; ניתן לחזור לכל גרסת מערכת קודמת ללא בנייה מחדש מאפס.
  • הוראה למפתחים — תזכורת של עמוד אחד: כיצד להעלות את הסביבה, ליצור מחדש מאפס, לאפס מצב והיכן לראות את יומן ההפעלה.
  • צ'ק-ליסט קבלה — בדיקות שלפיהן מהנדס חדש בהרצה אחת משתכנע שהסביבה עובדת במלואה.

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

קייס: מעבר של צוות לתיאור סביבה אחיד

לפני המעבר

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

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

מה שינו

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

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

מה נהיה

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

במה נבדלת מכונה וירטואלית ממכולה?

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

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

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

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

לכן Vagrant מבית HashiCorp מתאר בדיוק מכונה: הקונפיגורציה קובעת את ה-image הבסיסי, נפח הזיכרון, הפניית פורטים, תיקייה משותפת והרצת תרחישי ההגדרה — הסביבה עולה באופן זהה אצל כל מהנדס, ללא עריכות ידניות.

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

ספקות נפוצים לגבי סביבות מקומיות

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

אצל חלק מהצוות הסביבות מוגדרות ביד — הכול צריך להיעשות מחדש?

לא. אנחנו לא מוחקים מכונות עובדות: מתארים את המצב הנוכחי בקונפיגורציית Vagrant בהדרגה — קודם ה-image הבסיסי והתיקיות המשותפות, אחר כך השירותים. לאחר מכן הסביבה עולה בפקודה אחת בעמדת עבודה חדשה.

אצל המפתחים יש Windows ו-macOS — האם הסביבה תהיה זהה?

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

חלק מהשירותים לא ניתן להעלות מקומית — מה עושים?

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

כיצד נפתרות שאלות הרשאות הגישה לתיקיות משותפות?

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

נדון במשימה: נכין אומדן ותוכנית הטמעה

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

כדי שהאומדן והתוכנית יהיו ריאליים, ושהעבודה לא תיתקע באישורים, יש לאסוף לפני ההתחלה:

  • גישה לריפוזיטורי עם הרשאות קריאה וענף נפרד לשינויים — כך אנחנו רואים את סקריפטי הבנייה האמיתיים, ולא סיפור מפי אחר;
  • רשימת שירותים ודרישות: מסדי נתונים, תורים, מטמון, אינטגרציות חיצוניות, ואילו מהם חייבים לעלות מקומית ואילו די להחליף ב-mock;
  • הרכב הצוות ומכונות העבודה: כמה מפתחים, אילו מערכות הפעלה, כמה משאבים כל אחד יכול להקצות למכונות וירטואליות;
  • מגבלות הסביבה: כללי רשת ארגוניים, מראות חבילות סגורות, דרישות אבטחה ל-images;
  • איש קשר של אחראי שמתאם שינויים בקונפיגורציה ומאשר קבלה;
  • רשימת התקלות הנוכחיות: מה לרוב נשבר בעת פריסה אצל מפתח חדש — זה קובע את קריטריוני המוכנות.

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