אוטומציה של בדיקות אינטגרציה ב-CI/CD: Docker ומקביליות

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

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

שאלות נפוצות

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

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

מדוע בדיקות אינטגרציה של CI/CD מאטות את הפריסה

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

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

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

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

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

הרצה מקבילה ובידוד סביבות בדיקה

זרמים בלתי תלויים במקום הרצה ארוכה אחת

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

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

בידוד נתוני בדיקה

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

יציבות ההרצה וחזרות הוגנות

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

שחזור מהיר של הבילד

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

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

אפשרויות לארגון סביבת הבדיקה

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

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

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

בפועל, לרוב לוקחים סביבה אפמרלית למערך הראשי וסביבה קבועה לתרחישים שאי אפשר לבודד.

סדר ההטמעה: מהאודיט ועד המסירה

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

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

תצורות, תרשימים ונוהלים בפלט

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

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

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

מקרה בוחן: כיצד זמן ההרצה התקצר פי שלושה

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

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

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

מה עשו

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

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

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

מה נהיה

מדד לפני אחרי
משך ההרצה 40+ דקות 12 דקות
שיעור נפילות שווא ~20% 2%
הרצות מחדש ידניות בשבוע עשרות בודדות
תדירות המהדורות פעם בשבועיים 2–3 פעמים בשבוע

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

במה נבדלות בדיקות אינטגרציה של CI/CD מבדיקות יחידה

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

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

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

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

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

ספקות טכניים ומגבלות הגישה

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

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

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

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

האם נדרשת סביבה קבועה?

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

היכן גבול המקביליות?

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

האם אפשר להאיץ את ההרצה בלי לכתוב את הבדיקות מחדש?

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

נדון במשימה ונחזור עם הערכה ותוכנית

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

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

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

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