הגדרת CI/CD ליישומי Serverless (SAM/Serverless Framework)

צעדים ידניים בפריסת יישומי serverless מאטים שחרורים והופכים חזרות לאחור למסוכנות. אנו מגדירים 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 ללא שרת כשהצוות גדל

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

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

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

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

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

השפעות מדידות: מהירות פריסה ושיעור כשלים

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

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

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

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

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

מצבי פריסה ב-CI/CD ללא שרת: השוואת גישות

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

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

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

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

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

איך בונים צינור: מביקורת ועד מסירה

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

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

תשתית כקוד, סודות ומדיניות גישה

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

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

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

ניתוח הטמעה: מדדים לפני ואחרי

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

מה שינו בתהליך

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

מדדים לפני ואחרי

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

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

במה שונה פריסה הדרגתית מהחלפת סביבה כולה

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

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

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

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

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

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

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

ספקות טכניים שאנחנו מסירים לפני התחלה

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

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

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

איפה נשמרים סודות ומפתחות גישה?

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

מה יקרה בשחרורים במקביל?

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

איך בנויה חזרה לאחור לגרסה הקודמת?

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

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

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

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

בתשובה תקבלו:

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

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