הגדרת Docker Layer Caching להאצת הבנייה

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

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

שאלות נפוצות

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

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

למה Docker layer caching מפסיק לעבוד: איפה נעלמות השכבות

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

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

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

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

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

מה נותן שימוש חוזר בשכבות: זמן בנייה ושיעור הפגיעות במטמון

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

השכבות של ה-image Docker נשמרות במטמון לפי תוכן ההוראות: כל עוד קובץ התלויות לא השתנה, שלב התקנת החבילות נלקח מוכן. בפרויקט טיפוסי הבנייה מתקצרת מ-8–12 דקות ל-2–3, ושיעור הפגיעות במטמון נשמר ברמה של 80–90% כשמבצעים שינויים בקוד האפליקציה.

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

נפח האחסון וצפיות ה-deploy

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

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

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

שיטות שמירה במטמון: מטמון מקומי, registry של images, volume משותף

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

מצב לצוות אחד

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

אפשרות מתי מתאימה מגבלות
מטמון בנייה מקומי node קבוע אחד, בניות חוזרות תכופות של פרויקט אחד לא שורד יצירה מחדש של ה-node, לא מתחלק בין מכונות
מטמון ב-registry של images כמה nodes וענפים, בנייה בסביבות מבודדות נדרש גישה ל-registry וניקוי תגים; שכבות פרטיות לא אמורות לצאת החוצה
volume משותף למטמון חווה של nodes לבנייה עם אחסון רשת משותף נעילות בכתיבה מקבילה, הרשת הופכת לצוואר בקבוק

כשיש כמה nodes

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

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

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

איך אנחנו מגדירים את מטמון הבנייה של Docker: שלבי העבודה

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

הכנה ובדיקה

  1. מבצעים audit ל-pipeline הבנייה: בודקים את סדר ההוראות בתיאור ה-image, מה משתנה בכל קומיט ומה פעם בחודש. שכבות שמשתנות בתדירות גבוהה מעלים למעלה, שכבות שמשתנות לעיתים רחוקות משאירים למטה — הן בדיוק אלה שהופכות לשכבות שנשמרות במטמון.
  2. בונים סכמת מטמון: קובעים אילו שכבות משותפות לענפים, והיכן המטמון יחיה — על node הבנייה או באחסון חיצוני שנגיש לכל ה-nodes.
  3. מבצעים הגדרה של המטמון ב-registry: ייצוא וייבוא של המטמון ל-image, תגים נפרדים לענפים ול-images בסיס, כדי ששכבות לא ידרסו זו את זו.
  4. מבצעים בדיקת פגיעות: לפי לוג הבנייה מאמתים כמה שכבות הועלו מהמטמון, מודדים את הזמן לפני ואחרי, ומסירים מקונטקסט הבנייה קבצים מיותרים — הם שוברים את המטמון לפני הזמן.

פריסה והעברה

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

מה נשאר ב-repository: קונפיגורציות, סכמות ונהלים

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

קוד ותשתית

  • קונפיגורציה של pipeline הבנייה — קבצי הבנייה ב-repository: סדר השלבים, החלוקה לשכבות, תלויות שהוצאו החוצה.
  • סכמת המטמון — אילו שכבות Docker נשמרות במטמון, איזה key משמש, ממה הוא תלוי והיכן הוא נשמר: על ה-builder או ב-registry משותף.
  • נוהל ביטול תוקף — מה מאפס את המטמון (החלפת image הבסיס, קובץ התלויות) ונוהל לאיפוס מלא בחירום.
  • מדיניות גישה ל-registry — תפקידי קריאה וכתיבה, פרטי זיהוי נפרדים לבנייה, איסור כתיבה אנונימית, תוקף מוגבל ל-tokens.
  • Observability — שיעור הפגיעות במטמון והתראה כשהוא נופל: ההאטה נראית לפני שהיא הופכת לבעיה.

תיעוד והרשאות

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

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

Case study: הבנייה של monorepo הואצה, שיעור הכשלים ירד

מה היה לפני העבודה

monorepo של ארבעים שירותים נבנה ב-pipeline אחד Docker: registry משותף ל-images, runner משותף, ענף אחד לכל הצוותים. שכבות התלויות נבנו מחדש בכל שינוי בעץ — תיקון בשירות אחד גרר התקנה מחדש של חבילות בכל ה-repository, ומעבר מלא ארך 22–26 דקות.

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

מה השתנה אחרי

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

מעבר מלא התקצר מ-22–26 ל-6–8 דקות, ובנייה חוזרת של שירות שלא השתנה נכנסת בתוך דקה. שיעור הכשלים ירד מ-18% ל-4%: אותו סוג תקלות בדיוק נסגר על ידי מבנה המטמון ולא על ידי נוהל.

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

במה שונה מטמון השכבות ממטמון התלויות והחבילות?

יש שלוש רמות של שמירה במטמון בבנייה, והן לא מחליפות זו את זו. מטמון השכבות פועל ברמת ההוראות: Docker מחשב את ה-key של השכבה מתוך טקסט ההוראה וה-hash של שכבת האב. מטמון התלויות חי בתוך מנהל החבילות — זה המחסן שלו עצמו של ספריות שהורדו. ה-volume שנטען כ-mount הוא ספרייה על host הבנייה, ששורדת מחיקת container ולא נכנסת ל-image המוכן.

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

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

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

ה-volume צריך key נפרד לכל ענף בנייה — אחרת בניות מקבילות דורסות זו לזו את המחסן ומניבות תוצאה לא יציבה.

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

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

שתי בניות רצות בו-זמנית — האם הן לא יערבבו את המטמון?

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

image הבסיס עודכן — האם המטמון יישאר תקף?

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

האם המטמון יעבור ל-node אחר או ל-agent בנייה אחר?

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

האם המטמון בטוח? האם סודות לא יישארו בו?

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

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

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

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

מה אנחנו מוסרים בתשובה:

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

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