GitLab Container Registry: היכן CI/CD נשבר
רישום האימג'ים ב-GitLab כמעט אף פעם לא נשבר "מעצמו" — הוא נשבר בנקודות החיבור: בין הבנייה, התיוג והניקוי. הכשל הטיפוסי הראשון הוא התנפחות האחסון. כל ריצה מפרסמת שכבה חדשה, התגים הישנים נשארים, ותוך כמה חודשים הרישום גדל מהר יותר מהמוצר.
כל עוד יש מספיק מקום, אף אחד לא רואה את הבעיה; כשהמקום נגמר, כבר לא הבנייות נופלות, אלא כל השרת עם הרישום.
המקור השני — התנגשויות תגים. אם הבנייה דורסת את latest או עושה שימוש חוזר בתג בלתי ניתן לשינוי, אז חזרה לגרסה קודמת הופכת לבלתי אפשרית: תחת אותו שם כבר נמצא אימג' אחר. לאבחן זאת קשה — הבנייה עברה, הפריסה עברה, אבל בסביבת הבדיקה רץ משהו אחר ממה שציפו.
קטגוריה נפרדת — שגיאות אימות. טוקן פג תוקף של הראנר, הרשאות שגויות של חשבון השירות או אי-התאמה בטווח הנראות גורמים לכשל לא בשלב הפרסום, אלא בשלב משיכת האימג' בסביבה אחרת. הסימפטום במקרה זה נראה כמו "הבנייה עברה, אבל אנחנו לא מצליחים לפרוס".
ולבסוף, הידרדרות הבנייות: ככל שיש יותר זבל ברישום, כך פעולות ההורדה והניקוי אורכות יותר, וככל שהריצות נתקלות לעתים קרובות יותר בטיים-אאוטים. מפרקים כיצד זה נסגר ברמת מדיניות השמירה, סכמת התיוג והרשאות הגישה.
מה נותן רישום אימג'ים מסודר
רישום הוא לא "מחסן אימג'ים", אלא נקודה שבה נפגשים מהירות הבנייה, מהירות החזרה לאחור ושלמות מה שיוצא לפרודקשן.
כאשר הוא מסודר, האפקט נראה בגדלים מדידים: הבנייה מפסיקה בכל פעם למשוך שכבות בסיס ממקורות חיצוניים, כי הן נמצאות מקומית ומשמשות מחדש בין משימות, וזמן השחזור לאחר תקלה נקבע לא על ידי חיפוש הגרסה הנכונה, אלא בפקודת חזרה לאחור אחת לתג ספציפי.
האפקט המדיד הראשון — מהירות. מטמון שכבות בצד הרישום ושימוש חוזר באימג'י בסיס בתוך הרשת מסירים הורדה חוזרת של אותן תלויות: שלב בנייה טיפוסי מתקצר פי כמה, ולא באחוזים. השני — זמן שחזור.
כאשר כל שחרור מסומן בתג בלתי ניתן לשינוי ומקושר לקומיט, חזרה לאחור מפסיקה להיות ארכאולוגיה: המהנדס מחזיר את האימג' העובד הקודם תוך דקות, ולא בונה אותו מחדש מענף ישן.
האפקט השלישי — מחלקות כשל שהוסרו. נעלם "אצלי זה נבנה, בסטייג' זה נפל" בגלל שכבות בסיס שונות, נעלמת העלאה ידנית של אימג'ים בעקיפין לצינור, נעלמת הסיטואציה שבה לפרודקשן יצא תג שנכתב מחדש מעל הישן.
השלמות מובטחת בכך שהתג מצביע על אותו דייג'סט, והעקיבות — בקישור "אימג' → קומיט → משימה → מחבר".
בדיוק את ההיגיון הזה אנחנו מטמיעים בעת הגדרת הרישום GitLab Container Registry: מדיניות שמירה, הפרדת הרשאות ופרסום אוטומטי מהצינור, כדי שהרישום ישקף את מצב הקוד האמיתי, ולא את הכוונות.
השוואת גישות לאחסון אימג'ים
הבחירה בין רישום מובנה, אחסון חיצוני וסכימה היברידית נקבעת לא לפי נוחות, אלא לפי היכן נמצאים הבנייה, הריצה ומדיניות הגישה.
רישום מובנה ב-GitLab מספק מינימום של חלקים נעים: האימות עובר בירושה מהפרויקט, הרשאות הקריאה והכתיבה תואמות לתפקידים, וניקוי האימג'ים מנוהל לפי אותם כללי מחזור חיים כמו שאר הארטיפקטים. המגבלה — הרישום חי על אותו מתאר כמו GitLab עצמו, וחולק איתו שטח דיסק ורוחב פס.
אחסון חיצוני מסיר עומס מהמתאר הראשי ומאפשר להפריד בין הבנייה לאספקת האימג'ים לאזורי זמינות שונים. המחיר לכך — שכבת אימות נפרדת, סנכרון הרשאות ומנגנון משל עצמו למחיקת תגים מיושנים: מדיניות ניקוי שנשכחה הופכת את האחסון למזבלה שגדלה מהר יותר מקצב הגעת הגרסאות.
סכימה היברידית לוקחת את הטוב משניהם: הבנייה מתבצעת ברישום המובנה, והאספקה לריצה — דרך מראה חיצונית עם חימום מראש.
| אפשרות | מתי מתאימה | מגבלות |
|---|---|---|
| רישום מובנה | צוות קטן, מתאר אחיד, מסלול קצר מהבנייה לפריסה | חולק משאבים עם GitLab, מוגבל להיקף של מתאר אחד |
| אחסון חיצוני | מספר אשכולות, אזורים מפוזרים, תדירות גבוהה של אספקת אימג'ים | אימות נפרד, סנכרון ידני של הרשאות וניקוי |
| סכימה היברידית | בנייה במקום אחד, ריצה במספר מקומות, נדרש חימום מטמון | מורכבת יותר להגדרה, דורשת מדיניות תיוג מתואמת |
בפועל הבחירה מצטמצמת לשתי שאלות: כמה מתארים צורכים את האימג'ים ומי אחראי למחיקתם. אם התשובה אחת — הרישום המובנה מספיק. אם יש כמה מתארים וביניהם גבולות רשת, הסכימה ההיברידית מחזירה את עצמה בזמן אספקת האימג' בעת הפריסה.
שלבי הטמעה והגדרה
אנחנו מתחילים את העבודה בסקירה של הצינור הנוכחי: בודקים היכן נבנים האימג'ים, לאן הם מפורסמים, כיצד בנויות הרשאות הגישה וכמה זמן לוקח המחזור מהקומיט ועד לארטיפקט המוגמר. בשלב זה אנחנו מזהים את צווארי הבקבוק — בניות כפולות, היעדר מטמון שכבות, צעדים ידניים בעת השחרור.
בסיכום הסקירה אנחנו מתאמים את הסכימה: אילו מאגרים ותגים אנחנו מקימים, כיצד אנחנו מפרידים את הגישה בין צוותים וסביבות, והיכן נשמרים הסודות לאימות מול הרישום.
הגדרה ובדיקה
- סקירה. מנתחים את הבניות הנוכחיות, פרסום האימג'ים, ההרשאות וזמן המעבר בצינור — ומקבלים מפת צווארי בקבוק.
- סכימה. מתכננים את מבנה המאגרים והתגים, מדיניות גישה לפי תפקידים, כללי ניקוי של אימג'ים ישנים.
- הגדרת הרישום. מקימים את האחסון, מחברים אימות, מגדירים מגבלות ומדיניות שמירה.
- אינטגרציה עם הצינור. מטמיעים את הבנייה והפרסום של האימג'ים בשחרור האוטומטי, מוסיפים מטמון שכבות ובדיקות אבטחה.
- בדיקה. מריצים מהדורת בדיקה: בנייה, פרסום, פריסה, חזרה לתג הקודם — ומוודאים שהכול משוחזר.
- מסירה. מוסרים לצוות תיעוד, הרשאות ותקנון עבודה עם הרישום, ומכשירים את המהנדסים.
לאחר הבדיקה אנחנו מתעדים מדדים: זמן בנייה, שיעור הצעדים האוטומטיים, מהירות החזרה לאחור. המסירה כוללת לא רק הרשאות, אלא גם תקנון ברור — כיצד לשחרר אימג'ים, כיצד לנקות את הרישום, ומה לעשות בעת כשל בפרסום. תארו את המשימה שלכם — נחזור עם הערכה ותוכנית עבודה.
מה הלקוח מקבל לידיו
לאחר מסירת הפרויקט לא נשאר לכם "גישה לשרת", אלא ערכה שלפיה ניתן להעביר את התשתית לצוות אחר או להקים אותה מחדש בלעדינו. כל מה שאנחנו מגדירים מתועד במאגר ובמסמכים — בלי פעולות ידניות "מהזיכרון".
- תצורות אחסון ובנייה: קובצי הגדרת המאגר, מניפסטים של פריסה, פרמטרים של שמירה וניקוי אימג'ים — במערכת בקרת גרסאות, עם היסטוריית שינויים.
- תרשים זרימת האימג'ים: מבנייה במשימה ועד פרסום במאגר ואספקה לסביבה — עם הנקודות שבהן נבדקות הרשאות וחתימות.
- מדיניות גישה: תפקידים והיקפי הרשאה של טוקנים, הפרדה בין הרשאות קריאה לכתיבה, כללים לצרכנים חיצוניים ולבוטים של בנייה.
- נוהל ניקוי: כמה אימג'ים ותגיות נשמרים, מה נמחק אוטומטית, וכיצד נשמרת היכולת לחזור לגרסה קודמת.
- תיעוד תפעול: כיצד לפרסם אימג', כיצד לשלול גישה, כיצד לשחזר את המאגר מגיבוי, ולמי לפנות בעת תקלה.
- תרשים גיבוי ושחזור: תדירות, מקום אחסון העותקים, ותרחיש מוכח של העלאה מחדש לאחר כשל.
- רשימת בדיקה לקבלה ומסירה: רשימת הבדיקות המאשרות שהצינור והמאגר פועלים כשורה לאחר החלפת האחראי.
כל סעיף אנחנו עוברים יחד עם הצוות שלכם בשלב המסירה — כדי שהמסמך לא יישאר פורמליות, אלא יתאים למצב האמיתי של המערכת. תארו את המשימה — נחזור עם הערכה ותוכנית.
מקרה בוחן: כיצד קוצר זמן הבנייה פי שלושה
הלקוח — צוות מוצר של 14 מפתחים, מונורפו, 6 שירותים. בניית האימג' ארכה 19 דקות: בכל קומיט נבנו מחדש כל השכבות, מכיוון שהמטמון לא נוצל מחדש בין הראנרים. הרישום גדל ללא שליטה — תגים הצטברו ללא מדיניות, נפח האחסון חצה טרהבייט, ומחצית מהאימג'ים כלל לא נבנו.
GitLab Container Registry חובר כרישום הראשי לצד הצינור. הבנייה פוצלה לשכבת בסיס עם תלויות ולשכבה יישומית — שכבת הבסיס נבנית מחדש רק כאשר המניפסט משתנה, והשאר נלקח מהמטמון. הופעל מטמון מבוזר בין הראנרים, כדי שמשימות מקבילות לא יבנו את אותו הדבר פעמיים.
מה השתנה במספרים
| מדד | לפני | אחרי |
|---|---|---|
| זמן בניית האימג' | 19 דק' | 6 דק' |
| שיעור הבנייות שנכשלו | 11% | 2% |
| נפח האחסון | 1.1 טב | 340 גב |
הכשלים כמעט נעלמו בזכות שני דברים: הבנייה הפסיקה להיות תלויה בהורדות חיצוניות ברגע ההרצה, והתג תמיד מצביע על אימג' בלתי משתנה — החזרה לגרסה קודמת אורכת דקות, ולא שעות של בירורים.
מה נעשה עם האחסון
כלל מחזור חיים שומר את 10 האימג'ים האחרונים לכל תג ומנקה את השאר — הרישום הפסיק לגדול, ובמקביל החזרה לגרסה קודמת נותרת אפשרית. בנפרד הוגדר מחיקת שכבות "תלויות" שנשארות לאחר דריסת תג: הן בדיוק יצרו שליש מהנפח.
הבנייה קוצרה פי שלושה, נפח האחסון — פי שלושה ומעלה, ושיעור הכשלים ירד פי חמישה. הצוות הפסיק להמתין לצינור ולנקות את הרישום ידנית.
במה שונה GitLab Container Registry מרישום חיצוני?
רישום מובנה הוא חלק מ-GitLab עצמו: האימג'ים נשמרים לצד הקוד, הפייפליינים והמשימות, ולא בשירות נפרד. מבחינת הבנייה המשמעות היא שלאחר docker build האימג' עובר לאותו פרויקט שבו נמצא קוד המקור, והשלב הבא בפייפליין מושך אותו בלי להגדיר אישורי גישה חיצוניים ונתיבי רשת.
רישום חיצוני דורש אינטגרציה נפרדת: טוקנים משלו, כללי גישה משלו, קונטור נפרד ל-CI-ראנרים, ואת כל זה יש לסנכרן עם מחזור החיים של הפרויקט ב-GitLab.
ניהול הגישה בשני המקרים מבוסס על טוקנים, אבל ההיגיון שונה. ברישום המובנה ההרשאות עוברות בירושה מתפקידי הפרויקט: מפתח דוחף אימג'ים של הענף שלו, מהנדס שחרור — תגים, אורח רק קורא.
הגישה נשללת במקום אחד — כשמסירים משתתף מהפרויקט הוא מאבד גם את הגישה לאימג'ים, מה שסוגר את החור הטיפוסי שבו עובד שפוטר שומר על טוקן pull של רישום חיצוני. בפתרון חיצוני יש לנהל תפקידים במקביל ולסנכרן ידנית, וחוסר סנכרון בין שתי מערכות הוא מקור לאירועי דליפת אימג'ים פרטיים.
עלות הבעלות מורכבת לא מהתעריף, אלא מהעבודה הנלווית. הרישום המובנה אינו דורש שירות נפרד, גיבוי שלו, ניטור זמינות ועדכון — המשימות האלה כבר מכוסות על ידי התפעול של GitLab עצמו.
רישום חיצוני מוסיף עוד רכיב לקונטור עמידות לתקלות: מדיניות רשת בין הראנרים לרישום, מפתחות הצפנה נפרדים, לוח זמנים משלו לעדכונים. בנוסף מדיניות שמירה: כלל lifecycle מנקה תגים ישנים, אבל יש להגדיר אותו בכל מערכת בנפרד.
הבחירה המעשית תלויה בהיקף. כל עוד הצוות ומספר הפרויקטים מתונים, הרישום המובנה נותן פחות חלקים נעים והתנהגות צפויה בעת rollback — האימג' של השחרור הקודם נמצא באותו מקום שבו נבנה.
רישום חיצוני מוצדק כאשר אימג'ים נצרכים על ידי אשכולות מחוץ ל-GitLab, יש צורך בנקודה אחודה למספר פלטפורמות או בהפצה מבוזרת גיאוגרפית. אז האינטגרציה וסנכרון ההרשאות הופכים למחיר מודע עבור עצמאות האחסון ממערכת הבנייה.
ספקות טכניים ותשובות
נבחן את השאלות שעולות לרוב בשלב התכנון ואחרי ההשקה: הרשאות גישה, גידול בנפח, מעבר בין רישומים ותאימות לבניות הנוכחיות.
כיצד להפריד את הגישה לתמונות בין צוותים וסביבות?
ההרשאות ניתנות ברמת הפרויקט והקבוצה: מפתחים דוחפים לענפים שלהם, הבונה — לתגים ביניים, ותגי הייצור סגורים בתפקיד נפרד. עבור צרכנים חיצוניים אנו משתמשים בטוקנים עם תוקף מוגבל והיקף הרשאה לקריאה בלבד. סודות אינם נשמרים בקונפיגורציית הבנייה — הם מועברים דרך משתנים מוגנים, הזמינים רק בענפים מוגנים.
מה יקרה לרישום כשהתמונות יגיעו לאלפים?
הגידול בנפח הוא שאלה של מדיניות, לא של גודל הדיסק. כללי lifecycle שומרים את N התמונות האחרונות לכל תג ומוחקים את השאר לפי לוח זמנים, כך שהרישום אינו גדל ללא בקרה, וחזרה לגרסה קודמת נשארת אפשרית. בנוסף, מטמון הבנייה מועבר לכרך נפרד, כדי שלא יתחרה על מקום עם תמונות העבודה.
כיצד לעבור מרישום אחר ללא השבתה?
את ההגירה מבצעים בשלבים: תחילה מגדירים סנכרון, לאחר מכן מעבירים את הבניות לכתובת החדשה, ואת הצרכנים — אחד אחד, עם בדיקה בכל שלב. הרישום הישן נשאר זמין לקריאה בלבד, עד שנוודא שכל הפריסות מגיעות מהחדש. חזרה לאחור אפשרית בכל שלב, כל עוד הכתובת הישנה לא נותקה.
האם הוא תואם לבניות ולפריסות הנוכחיות שלנו?
הרישום פועל לפי פרוטוקול התמונות הסטנדרטי, ולכן הבניות הקיימות והאורקסטרטור מתחברים בהחלפת כתובת ופרטי התחברות — אין צורך לשכתב את הצינורות. בנפרד נבדקים תרחישים עם מספר ארכיטקטורות וחתימת תמונות, אם הם כבר בשימוש. אם בצינור קיימות בדיקות אבטחה משלו, הן ממשיכות לפעול מעל הכתובות החדשות.
כיצד להבין שהרישום מוגדר כראוי?
הקריטריון פשוט: הבנייה מפרסמת תמונה, הפריסה מושכת בדיוק אותה, וגרסאות ישנות נמחקות לפי הכלל מבלי לפגוע בקיימות. בנוסף, יומן הגישה מראה מי ומתי פנה לתמונות. בדיקה זו מריצים לפני העברה לעבודה, ולא אחרי התקלה הראשונה.
נדון במשימה שלכם
כדי לחזור עם הערכה ותוכנית, ולא עם מילים כלליות, אנחנו צריכים את ההקשר של המשימה שלכם. תארו כיצד בנויה כעת הפצת האימג'ים: היכן הם נבנים, לאן הם מפורסמים, מי וכיצד מושך אותם לסביבות. זה מספיק כדי להבין את היקף העבודה והסיכונים.
לאחר מכן העבודה מתנהלת בשלבים:
- מנתחים את תהליך הבנייה והפרסום הנוכחי של האימג'ים — היכן יש פעולות ידניות, היכן צווארי בקבוק, ומה נשבר לעתים קרובות ביותר.
- מדייקים את הדרישות: כמה סביבות, אילו מדיניות שמירה, והאם נדרשים registries נפרדים לצוותים ולפרויקטים.
- מכינים תוכנית הטמעה של GitLab Container Registry עם חיבור ל-repositories ולמשימות הבנייה שלכם.
- מתאמים את סכמת הרשאות הגישה וההפרדה לפי תפקידים — מי מפרסם ומי רק מושך אימג'ים.
- מגדירים ניקוי אוטומטי של גרסאות ישנות, כדי שה-registry לא יתפח ללא בקרה.
- מריצים בנייה ואספקה על שירות אחד כפיילוט, ומודדים זמן ויציבות.
- מעבירים את שאר השירותים ומוסרים תיעוד לצוות שלכם.
מה שחשוב לנו לקבל מכם כבר בהתחלה:
- רשימת השירותים והסביבות שיש לחבר;
- כיצד נשמרים ומנוהלים כעת האימג'ים מבחינת גרסאות;
- דרישות לזמני שמירה ולחזרה לגרסאות קודמות;
- מי מצד הצוות שלכם יקבל את העבודה;
- מגבלות תשתית, אם יש כאלה.
תארו את המשימה בצורה הנוחה לכם — נחזור עם הערכת זמנים, הרכב העבודה ותוכנית לפי שלבים.







