בפוסט הקודם דיברנו על המוטיבציה ל CI/CD/CDD, על הציפיות והסיבות לאמץ את המתודולוגיות הללו, ותיארנו בפירוט מהו CI (הרעיון מעט שונה ממה שמקובל לחשוב).
בפוסט זה ארצה לפרט יותר על CD - ואולי גם כאן הרעיונות נבלעו תחת תפיסה פופולארית פשטנית.
בפוסט זה ארצה לפרט יותר על CD - ואולי גם כאן הרעיונות נבלעו תחת תפיסה פופולארית פשטנית.
Continuous Delivery (בקיצור: CD)
המונח CD התחיל להיות נפוץ בעקבות הספר הפופלארי של ג'ז האמבל ודייויד פארלי (למעלה באמצע).
המחברים לא המציאו את הרעיונות, אלא נתנו תוקף ומסגרת לתהליכים שהיו בשימוש ע"י חברות כמו Yahoo, אמזון, פייסבוק, גוגל, ועוד.
התרומה הראשונית של תנועת ה CD הייתה להחזיר את רעיון ה CI למרכז המפה, לא CI כסיסמה - אלא הבנה מעמיקה יותר של רעיון ה CI.
רבים בתעשייה הכריזו על עצמם כמיישמי CI - גם כאשר היישום לא היה יותר מ Build Server (או "CI Server") שמבצע Build בצורה תדירה. האינטגרציה עדיין נותרה אירוע של סוף ספרינט או רחוק מכך.
האם זו בורות, או פשוט גיוס של עוד מונח מקצועי לשיפור את המוטיבציה של העובדים ("תראו אותנו, אנחנו עושים CI, איזה מעולים!!")? - קשה לי לומר.
אין שום חובה או צורך ליישם את CI - אלא כאשר הוא תורם לתהליכים בחברה. הנחת היסוד היא שהבנה טובה יותר של העקרונות - תסייע לבחון האם התרומה אכן מושגת או לא.
גם CD, באופן טבעי, הוא מוצהר יותר מאשר נעשה בפועל. זהו הטבע של התעשייה.
הצעד החשוב השני שתנועת ה CD עשתה היא להרחיב את מעגל האיטרציות ה SCRUM-י.
יישום נפוץ של סקראם (או מתודולוגיות אג'ייל דומות) בארגונים היה שצוותי הפיתוח עבדו באיטרציות קצרות - אך השלבים בתהליך שלפני הפיתוח (תכנון / אפיון מוצר) והשלבים שבאים אחריהם (בדיקות ו Release) - נותרו תהליכים ארוכים ולא גמישים.
ג'ז האמבל קרא למצב הזה Water-SCRUM-Fall, והוא מתואר בתרשים הבא:
מי לא מכיר את המצב הזה? אני מניח שרובנו...
CD בה להרחיב את תחומי ה SCRUM (ליתר דיוק: האיטרציות הקצרות והתכופות) בארגון, ולכלול בתוכן את ה QA וה Release מצד אחד, אך גם תכנון המוצר - מצד שני.
DevOps Culture - הוא אחד הרעיונות שצצו משם וקיבלו תשומת-לב מיוחדת. הרעיון שבמקום שיהיה "קיר" בין פיתוח ו Operations: פיתוח מייצרים משהו ו"זורקים" ל Operations להתקין בפרודקשיין - הקבוצות ישתלבו זו בזו.
במקום שיהיה ביניהם ניגוד אינטרסים מובנה (פיתוח לחוץ לפתח עוד פיצ'רים, Operations "אחראים" על יציבות המערכת ורוצים כמה שפחות שינויים) - הם עובדים בשיתוף פעולה, יד-ביד, למען מטרה משותפת.
האחריות למה שקורה בפרודקשיין - היא משותפת.
רבים בתעשייה לא הבינו את המסר בצורה נכונה: הם שינו את שם התפקיד מ "אנשי Operations" ל "אנשי DevOps" - והמשיכו בשכנוע-עצמי (או אולי: שכנוע-האחר) שהם התקדמו בצד משמעותי ליישום CD, או בכלל ברמה התהליכית...
זכרו: DevOps זה לא תפקיד - זוהי תרבות.
הספר Continuous Delivery יצא ב 2010, עוד לפני עידן ה SaaS. כלומר: לפני ש SaaS היה הצורה המקובלת לדלוור תוכנה. הספר מדבר בעיקר על Packaged Software - כזו שהלקוח מוריד את קובצי ההתקנה ומתקין בעצמו.
Case Study שג'ז האמבל אוהב להזכיר הוא הטמעת CD במחלקת המדפסות של חברת HP - כיצד לבצע CD ל firmware (הקוד שרץ בתוך המדפסת). זו דוגמה טובה לקוד שניתן לבנות אותו כל יום - אך עדכונים ישוחררו ללקוחות רק אחת לכמה חודשים (או אפילו פחות מכך).
מדד-מפתח באימוץ של CD בארגון הוא ה Lead Time, אותו יש לשפר כל הזמן:
הזמן מרגע שאיש Product ביקש פיצ'ר, או מהזמן שנפתח באג - ועד שהוא מוכן וארוז לשימוש. ארוז ("Shippable") הכוונה שיש לנו את קובצי ההתקנה של המערכת, והם שמישים, בדוקים, ובאיכות טובה.
ההתמקדות ב Lead Time מספקת אופטימיזציה בארגון לתהליכים רבים: תקשורת, תעדוף, Build מהיר, handover ל QA, ותהליכי בדיקות אוטומטיים, ועוד. אם היינו מתמקדים רק ב Process Time, או רק בחלק הפיתוחי של ה Process Time - אולי הפיתוח היה עובד מהר יותר, אבל הפיצ'ר עדיין היה "תקוע":
"הפיצ'ר מוכן, אבל הוא עדיין מחכה רק ל QA/התקנה" או "אנחנו מוכנים להתחיל, אבל מחכים ל Product/עיצוב" - הוא תירוץ שמתכנתים מרגישים נוח איתו, אך הוא לא מספק את צורכי הביזנס.
מכיוון שעל מנת לספק ערך ללקוחות צריך גם לכתוב תוכנה וגם לדלוור אותה - רק מיקוד ושיפור ה E2E יביא אותנו לנקודה בה אנו מדלוורים ערך ללקוח בצורה רציפה.
עוד הבחנה ש CD מתמקד בה היא שהזמן שמושקע בפיתוח מתחלק לחלק נראה, ולבתי-נראה:
כשאנחנו עסוקים כמעט כולנו בפיתוח פיצ'רים, ולא מקדישים זמן לפיתוח הארכיטקטורה ותהליך ה CD שלנו - הזמן הישיר והעקיף שהולך ל Negative Value הולך וצומח - עד שאנחנו כמעט ונעצרים מהיכולת לפתח ערך חיובי.
Technical Debt, כפי שאנו יודעים, זהו סיבוך בקוד, שינויים חשובים ב Design שנדחו, קיצורי דרך לא אלגנטיים - כל אלה גורמים להכנסת כל קוד חדש / שינויי קוד להיות קשים וארוכים יותר. מן "מס בלתי נראה".
"בלתי נראה"? המפתח שעובד על שינויי הקוד מרגיש אותו היטב, אך קשה לשקף אותו לשאר הארגון.
הנה השיפורים שהושגו, בחניכה של ג'ז האמבל במחלקת ה Firmware (מדפסות) של HP:
האם CD מציע לנו עולם שבו 80% מהזמן מוקדש לכתיבת קוד חדש ופיצ'רים? - לא ולא. יש הרבה עבודת אוטומציה ואחזקה. אבל, במקרה הנ"ל הצליחו להגדיל פי 8* - את הזמן שגוף הפיתוח משקיע בפיתוחים חדשים ("Innovation").
ההערה למטה בלבן מסבירה ש 23% מהזמן של הל המפתחים הושקע בכתיבת אוטומציה. כמעט חצי מהזמן שהושקע בכתיבת קוד שנותן ערך לללקוח.
* טוב, זהו Case Study, ויש כל אינטרס להציג את התמונה בצורה אופטימית ככל האפשר. בואו נניח ששיפרו את הזמן שמושקע בקוד חדש - רק פי 4-5 בפועל.
המפתח ליישום CD מההיבט הטכני הוא בניית ה Deployment Pipeline - הצינור בו מעבירים קוד ממערכת ה Source Control - לפרודקשיין.
כל שינוי ב Source Control מפעיל Trigger שגורם לבנייה של תוצר הקומפליציה. במקרה של פיתוח בענן (נניח AWS) - מדובר כנראה בבניה של ה AMI (קרי Amazon Machine Image) או Container, ממנו ניתן "להרים" מכונה בפרודקשיין בפקודה פשוטה. בשל הפופולאריות של Containers, אתייחס אליהם - אם כי ב Gett אני רגיל ביום-יום לעבוד עם AMIs.
נניח שאנו עובדים ב Github ויש לנו branch בשם master עליו מפתחים, ו branch בשם release שמתאר את מה שרץ בפרודקשיין.
חשוב להדגיש: הכוונה היא לא שנבצע merge ל release פעם בשבוע-שבועיים (או לסירוגין: בסוף ה Sprint) ואז יבנה ה Container. זה יהיה Automated Delivery - ולא Continuous Delivery!
הכוונה היא שבכל שינוי ב master (ואם יש כמה כאלה בטווח של דקה, אז אחת לכמה דקות) - ייבנה Container, הוא יופעל בסביבת ה Staging - ועליו המפתחים וה QA יבדקו את הקוד. סביבת ה Staging אמור לשקף את מצב הפיתוח הרגעי, כך שברגע שאנו מתכננים להשיק ("Ship") - יש לנו קוד במצב טוב.
"אבל זה לא יעבוד! סביבת ה Staging תהיה עם פונקציונליות שבורה כל הזמן - והמפתחים וה QA לא יוכלו לעבוד!"
זו הנקודה בה CD מסתמך על יישום של CI:
עלינו להוכיח שהקוד אכן מוכן לדילוור באיכות הרצויה, ועל כן אנו מעבירים אותו בסדרה של "מבחנים" - אלו הן התחנות השונות ב Deployment Pipeline. ככל שמבחן הוא מהיר יותר להרצה - הוא יהיה במיקום מוקדם יותר ב Deployment Pipeline. כלל שמבחן הוא יעיל יותר (סביר יותר שיתפוס בעיות) - הוא יהיה גם כן מוקדם יותר ב Deployment Pipeline.
כלומר: אנו מתחילים עם מבחנים זולים (= מהירים) ובעלי סיכוי גבוה לתפוס תקלות, למשל "Smoke Test" (= "מדליקים את המכשיר ורואים שלא יוצא עשן"), וככל שמתקדמים מגיעים למבחנים יקרים (= אטיים) יותר, ושבודקים יותר מקרי-קצה.
עדיין חשוב מאוד הכלל שאומר: שמירת ה Pipeline עובד היא בעדיפות עליונה. על הארגון לעזוב הכל ולטפל ב Pipeline שבור - ממש כמו שמטפלים ב Production.
זכרו: הטיפול ב Deployment Pipeline הוא משני בדחיפות רק ל Production.
התהליך שב Pipeline רץ כל הזמן, סביבות הבדיקות השונות אמורות לעבוד מסביב לשעון, לאורך כל הספרינט - ולא רק בסוף הספרינט (זו המשמעות של Continuous). ונכון: יהיו כמה גרסאות של שירותים במערכת (אני מניח שיש לכם Microservices) - וחלקן לא יגיע ל Production (אם בשל תקלה בבדיקות, או בשל כך שגרסה מתקדמת יותר "עקפה" אותה והגיעה ל Production לפניה).
הנה אתאר Pipeline לדוגמה.
ה Deployment Pipeline הוא יחסית מורכב, וקשה להבין אותו במבט מהיר. לכן, אתחיל במיפוי של סביבות הבדיקה השונות המעורבות ב Pipeline הזה.
על כל ארגון להתאים את ה Pipeline למציאות שלו. אני מציג דוגמה אחת, וזה בסדר גמור אם ה Pipeline שלכם נראה אחרת.
נקודות חשובות:
ה Manual Trigger מגיע לאחר בדיקות שהן ידניות (כמובן שמישהו יכול להחליט לדלג עליהן במקרים מסוימים ולאשר ללא בדיקה). הוא לא נמצא שם סתם.
הנה תיאור קצת יותר מפורט של ה Pipeline שהראתי למעלה:
ליד כל שלב רשמתי זמן שנחשב סביר לתהליך. סה"כ, גם Pipelines יעילים אורכים כחצי שעה-שעה מרגע ה push לגיט - ועד לפעולה ב Production.
שלב למשל שהוספתי ב Pipeline המפורט הוא שלב שלא מופיע בתרשים ה High Level: בדיקות Rollback.
בסיפור הזה הארגון נתקל בכמה פעמים שהיו בעיות לבצע Rollback של שירותים בפרודקשיין - מה שמגביל את הארגון לשחרר את השירותים לפרודקשיין בחופשיות שהוא רוצה. אופציית ה Rollback היא חיונית להתאוששות מהירה.
על כן נוסף שלב נוסף ב Pipeline בשם Rollback Test. הוא הולך בערך כך:
בהקמת ה Pipeline, וגם לאורך חייו, הארגון ישאל את עצמו שאלות שונות:
שווה לציין באזז עכשווי בשם Pipeline as Code. מכיוון שה Pipeline הופך ונעשה מורכב, התחילה גישה בה ניתן "לתכנת" אותו בשפת תכנות ולא רק בקונפיגורציה.
את המונח Pipeline as Code ייתכן ותשמעו מהפרסומים של Jenkins 2.0 - שלכאורה עבר שינוי מהותי בכדי לתמוך ביכולות הללו. בפועל הוצגה מערכת Plugins שעדיין רחוקה מהאידאל של Pipeline as Code. מקביליות בהרצת בדיקות עדיין מבוססת בעיקרה על Plugins ואיננה יכולת ליבה של המערכת - וכך גם השגת הגמישות ב Pipeline עצמו. ניתן לומר (באופן מעט מרושע) ש Jenkins 2.0 היא מוצר Pipeline by Plugins.
Jenkins הוא עדיין כנראה הכלי הנפוץ ביותר לבניית Deployment Pipeline, אם כי כלים כמו Concourse CI או goCD ו gomatic - נחשבים למתאימים יותר לבניית ה Deployment Pipeline. ייתכן והגיע זמנו של Jenkins לפנות את כס המלכות.
Dark Deployment - הרעיון כאן הוא שאין חובה ש Deployment יהיה גם בעצם Release.
פיצ'רים רבים במערכת - ניתן לשחרר אותם עם Feature Flag כבוי. הפיצ'ר הוא Deployed, אך לא Released.
למה לעשות את זה? בזמן הזה QA או המפתחים יכולים לבדוק את הפיצ'ר בפרודקשן, בסביבה הכי אמיתית עם תעבורה אמיתית. אפשר לעשות beta testing למשתמשים נבחרים - ולהכניס בפיצ'ר שיפורים, ורק כשהוא מוכן, בדוק, ויציב - לשחרר אותו.
כיום הפרקטיקה של Dark Deployment היא דיי מקובלת, גם אם מי שעושה זאת לא מכיר ולא משתמש המונח הרשמי :).
שוחחנו על CD לא מעט - זה נושא גדול, שנוטה להעסיק את הארגון רבות.
עדיין לא שוחחנו על איך מתחילים בהטמעה של CD בארגון שלא רגיל לכך, ולא על Continuous Deployment: האם זה באמת רק דילוג על שלב ה manual tests?
שיהיה בהצלחה!
זהו הרעיון שקוד המערכת יהיה כל הזמן במצב ניתן לדילוור ("shippable state").
המונח CD התחיל להיות נפוץ בעקבות הספר הפופלארי של ג'ז האמבל ודייויד פארלי (למעלה באמצע).
המחברים לא המציאו את הרעיונות, אלא נתנו תוקף ומסגרת לתהליכים שהיו בשימוש ע"י חברות כמו Yahoo, אמזון, פייסבוק, גוגל, ועוד.
התרומה הראשונית של תנועת ה CD הייתה להחזיר את רעיון ה CI למרכז המפה, לא CI כסיסמה - אלא הבנה מעמיקה יותר של רעיון ה CI.
רבים בתעשייה הכריזו על עצמם כמיישמי CI - גם כאשר היישום לא היה יותר מ Build Server (או "CI Server") שמבצע Build בצורה תדירה. האינטגרציה עדיין נותרה אירוע של סוף ספרינט או רחוק מכך.
האם זו בורות, או פשוט גיוס של עוד מונח מקצועי לשיפור את המוטיבציה של העובדים ("תראו אותנו, אנחנו עושים CI, איזה מעולים!!")? - קשה לי לומר.
אין שום חובה או צורך ליישם את CI - אלא כאשר הוא תורם לתהליכים בחברה. הנחת היסוד היא שהבנה טובה יותר של העקרונות - תסייע לבחון האם התרומה אכן מושגת או לא.
גם CD, באופן טבעי, הוא מוצהר יותר מאשר נעשה בפועל. זהו הטבע של התעשייה.
הצעד החשוב השני שתנועת ה CD עשתה היא להרחיב את מעגל האיטרציות ה SCRUM-י.
יישום נפוץ של סקראם (או מתודולוגיות אג'ייל דומות) בארגונים היה שצוותי הפיתוח עבדו באיטרציות קצרות - אך השלבים בתהליך שלפני הפיתוח (תכנון / אפיון מוצר) והשלבים שבאים אחריהם (בדיקות ו Release) - נותרו תהליכים ארוכים ולא גמישים.
ג'ז האמבל קרא למצב הזה Water-SCRUM-Fall, והוא מתואר בתרשים הבא:
מקור: ג'ז האמבל - http://www.slideshare.net/jezhumble/21-century-software |
מי לא מכיר את המצב הזה? אני מניח שרובנו...
CD בה להרחיב את תחומי ה SCRUM (ליתר דיוק: האיטרציות הקצרות והתכופות) בארגון, ולכלול בתוכן את ה QA וה Release מצד אחד, אך גם תכנון המוצר - מצד שני.
DevOps Culture - הוא אחד הרעיונות שצצו משם וקיבלו תשומת-לב מיוחדת. הרעיון שבמקום שיהיה "קיר" בין פיתוח ו Operations: פיתוח מייצרים משהו ו"זורקים" ל Operations להתקין בפרודקשיין - הקבוצות ישתלבו זו בזו.
במקום שיהיה ביניהם ניגוד אינטרסים מובנה (פיתוח לחוץ לפתח עוד פיצ'רים, Operations "אחראים" על יציבות המערכת ורוצים כמה שפחות שינויים) - הם עובדים בשיתוף פעולה, יד-ביד, למען מטרה משותפת.
האחריות למה שקורה בפרודקשיין - היא משותפת.
רבים בתעשייה לא הבינו את המסר בצורה נכונה: הם שינו את שם התפקיד מ "אנשי Operations" ל "אנשי DevOps" - והמשיכו בשכנוע-עצמי (או אולי: שכנוע-האחר) שהם התקדמו בצד משמעותי ליישום CD, או בכלל ברמה התהליכית...
זכרו: DevOps זה לא תפקיד - זוהי תרבות.
הספר Continuous Delivery יצא ב 2010, עוד לפני עידן ה SaaS. כלומר: לפני ש SaaS היה הצורה המקובלת לדלוור תוכנה. הספר מדבר בעיקר על Packaged Software - כזו שהלקוח מוריד את קובצי ההתקנה ומתקין בעצמו.
Case Study שג'ז האמבל אוהב להזכיר הוא הטמעת CD במחלקת המדפסות של חברת HP - כיצד לבצע CD ל firmware (הקוד שרץ בתוך המדפסת). זו דוגמה טובה לקוד שניתן לבנות אותו כל יום - אך עדכונים ישוחררו ללקוחות רק אחת לכמה חודשים (או אפילו פחות מכך).
יישום CD בצד הרעיוני
מדד-מפתח באימוץ של CD בארגון הוא ה Lead Time, אותו יש לשפר כל הזמן:
הזמן מרגע שאיש Product ביקש פיצ'ר, או מהזמן שנפתח באג - ועד שהוא מוכן וארוז לשימוש. ארוז ("Shippable") הכוונה שיש לנו את קובצי ההתקנה של המערכת, והם שמישים, בדוקים, ובאיכות טובה.
ההתמקדות ב Lead Time מספקת אופטימיזציה בארגון לתהליכים רבים: תקשורת, תעדוף, Build מהיר, handover ל QA, ותהליכי בדיקות אוטומטיים, ועוד. אם היינו מתמקדים רק ב Process Time, או רק בחלק הפיתוחי של ה Process Time - אולי הפיתוח היה עובד מהר יותר, אבל הפיצ'ר עדיין היה "תקוע":
"הפיצ'ר מוכן, אבל הוא עדיין מחכה רק ל QA/התקנה" או "אנחנו מוכנים להתחיל, אבל מחכים ל Product/עיצוב" - הוא תירוץ שמתכנתים מרגישים נוח איתו, אך הוא לא מספק את צורכי הביזנס.
מכיוון שעל מנת לספק ערך ללקוחות צריך גם לכתוב תוכנה וגם לדלוור אותה - רק מיקוד ושיפור ה E2E יביא אותנו לנקודה בה אנו מדלוורים ערך ללקוח בצורה רציפה.
עוד הבחנה ש CD מתמקד בה היא שהזמן שמושקע בפיתוח מתחלק לחלק נראה, ולבתי-נראה:
כשאנחנו עסוקים כמעט כולנו בפיתוח פיצ'רים, ולא מקדישים זמן לפיתוח הארכיטקטורה ותהליך ה CD שלנו - הזמן הישיר והעקיף שהולך ל Negative Value הולך וצומח - עד שאנחנו כמעט ונעצרים מהיכולת לפתח ערך חיובי.
Technical Debt, כפי שאנו יודעים, זהו סיבוך בקוד, שינויים חשובים ב Design שנדחו, קיצורי דרך לא אלגנטיים - כל אלה גורמים להכנסת כל קוד חדש / שינויי קוד להיות קשים וארוכים יותר. מן "מס בלתי נראה".
"בלתי נראה"? המפתח שעובד על שינויי הקוד מרגיש אותו היטב, אך קשה לשקף אותו לשאר הארגון.
הנה השיפורים שהושגו, בחניכה של ג'ז האמבל במחלקת ה Firmware (מדפסות) של HP:
האם CD מציע לנו עולם שבו 80% מהזמן מוקדש לכתיבת קוד חדש ופיצ'רים? - לא ולא. יש הרבה עבודת אוטומציה ואחזקה. אבל, במקרה הנ"ל הצליחו להגדיל פי 8* - את הזמן שגוף הפיתוח משקיע בפיתוחים חדשים ("Innovation").
ההערה למטה בלבן מסבירה ש 23% מהזמן של הל המפתחים הושקע בכתיבת אוטומציה. כמעט חצי מהזמן שהושקע בכתיבת קוד שנותן ערך לללקוח.
* טוב, זהו Case Study, ויש כל אינטרס להציג את התמונה בצורה אופטימית ככל האפשר. בואו נניח ששיפרו את הזמן שמושקע בקוד חדש - רק פי 4-5 בפועל.
יישום CD בצד הטכני
המפתח ליישום CD מההיבט הטכני הוא בניית ה Deployment Pipeline - הצינור בו מעבירים קוד ממערכת ה Source Control - לפרודקשיין.
כל שינוי ב Source Control מפעיל Trigger שגורם לבנייה של תוצר הקומפליציה. במקרה של פיתוח בענן (נניח AWS) - מדובר כנראה בבניה של ה AMI (קרי Amazon Machine Image) או Container, ממנו ניתן "להרים" מכונה בפרודקשיין בפקודה פשוטה. בשל הפופולאריות של Containers, אתייחס אליהם - אם כי ב Gett אני רגיל ביום-יום לעבוד עם AMIs.
נניח שאנו עובדים ב Github ויש לנו branch בשם master עליו מפתחים, ו branch בשם release שמתאר את מה שרץ בפרודקשיין.
חשוב להדגיש: הכוונה היא לא שנבצע merge ל release פעם בשבוע-שבועיים (או לסירוגין: בסוף ה Sprint) ואז יבנה ה Container. זה יהיה Automated Delivery - ולא Continuous Delivery!
הכוונה היא שבכל שינוי ב master (ואם יש כמה כאלה בטווח של דקה, אז אחת לכמה דקות) - ייבנה Container, הוא יופעל בסביבת ה Staging - ועליו המפתחים וה QA יבדקו את הקוד. סביבת ה Staging אמור לשקף את מצב הפיתוח הרגעי, כך שברגע שאנו מתכננים להשיק ("Ship") - יש לנו קוד במצב טוב.
"אבל זה לא יעבוד! סביבת ה Staging תהיה עם פונקציונליות שבורה כל הזמן - והמפתחים וה QA לא יוכלו לעבוד!"
זו הנקודה בה CD מסתמך על יישום של CI:
עלינו להוכיח שהקוד אכן מוכן לדילוור באיכות הרצויה, ועל כן אנו מעבירים אותו בסדרה של "מבחנים" - אלו הן התחנות השונות ב Deployment Pipeline. ככל שמבחן הוא מהיר יותר להרצה - הוא יהיה במיקום מוקדם יותר ב Deployment Pipeline. כלל שמבחן הוא יעיל יותר (סביר יותר שיתפוס בעיות) - הוא יהיה גם כן מוקדם יותר ב Deployment Pipeline.
כלומר: אנו מתחילים עם מבחנים זולים (= מהירים) ובעלי סיכוי גבוה לתפוס תקלות, למשל "Smoke Test" (= "מדליקים את המכשיר ורואים שלא יוצא עשן"), וככל שמתקדמים מגיעים למבחנים יקרים (= אטיים) יותר, ושבודקים יותר מקרי-קצה.
עדיין חשוב מאוד הכלל שאומר: שמירת ה Pipeline עובד היא בעדיפות עליונה. על הארגון לעזוב הכל ולטפל ב Pipeline שבור - ממש כמו שמטפלים ב Production.
זכרו: הטיפול ב Deployment Pipeline הוא משני בדחיפות רק ל Production.
התהליך שב Pipeline רץ כל הזמן, סביבות הבדיקות השונות אמורות לעבוד מסביב לשעון, לאורך כל הספרינט - ולא רק בסוף הספרינט (זו המשמעות של Continuous). ונכון: יהיו כמה גרסאות של שירותים במערכת (אני מניח שיש לכם Microservices) - וחלקן לא יגיע ל Production (אם בשל תקלה בבדיקות, או בשל כך שגרסה מתקדמת יותר "עקפה" אותה והגיעה ל Production לפניה).
הנה אתאר Pipeline לדוגמה.
ה Deployment Pipeline הוא יחסית מורכב, וקשה להבין אותו במבט מהיר. לכן, אתחיל במיפוי של סביבות הבדיקה השונות המעורבות ב Pipeline הזה.
על כל ארגון להתאים את ה Pipeline למציאות שלו. אני מציג דוגמה אחת, וזה בסדר גמור אם ה Pipeline שלכם נראה אחרת.
נקודות חשובות:
- את ה Isolated Testing Environment - מרימים לכל Service לדקות בודדות של בדיקה. לא אכפת לנו להפעיל כמה וכמה כאלו במקביל. וירטואליזציה או קונטיינריזציה - היא פלטפורמת ההרצה הטבעית לסביבה הזו.
- ה Integration Environment היא סביבה יחידה - בה ניתן לראות את התנהגות כל השירותים במצב ה dev שלהם ביחד.
- ה Integration Environment דומה ככל האפשר לפרודשיין:
- התקנה מבוצעת באותו האופן: clusters, מכונות נפרדות, DB נפרדים, קונפיגורציה - כמו בפרודקשין.
- ה Data מגיע מפרודקשיין, אך עובר ניקוי למידע פרטי (שלא צריך להיות נגיש לעובדים), או מיותר (למשל: טבלאות audit גדולות).
- לכאורה זו סביבה שעלולה להיות מאוד לא יציבה (גרסאות שונות ומשונות רצות ביחד), אבל עם התבגרות ה pipeline היציבות שלה אמורה להשתפר משמעותית:
- קוד מגיע אליה לאחר שעבר כבר סבב בדיקות.
- תאימות לאחור היא תנאי מחייב.
- עדיף מאוד לבצע deploy ב immutable deployment (על מכונה "נקייה" ולא "מלוכלכת") - containers או AMIs מאוד עוזרים כאן. אחרת - חשוב מנגנון reset לסביבה, והוא כנראה יופעל מפעם לפעם.
- כאשר יש התנגשות בין שירותים - אפשר להחזיר אחד השירותים לגרסה קודמת, אבל השאיפה היא להציע מהיר תיקון ולהתקדם קדימה. Rollback הוא פשרה.
- ה Staging Environment מאפשרת לבצע בדיקות אינטגרציה בין שירות נתון - למצב שיש כרגע בפרודקשיין.
- לא נדיר להגיע לסט בדיקות שהרצת כל הבדיקות שבו אורך שעות רבות (ראיתי גם יממה ויותר) - ועל כן לא מריצים את כל הבדיקות. חשוב לדעת לכל שירות איזה subset של הבדיקות הוא מספיק טוב. כלל אצבע שאני מכיר הוא לחתור ללא יותר מ 10 דקות של בדיקות. כלומר: ייתכן וסך כל הבדיקות אורכות שעתיים או שלוש (כי אנו מקפידים על שיפורי הזמנים: מסירים בדיקות לא יעילות, ועובדים לקצר בדיקות ארוכות) - אך אנו יודעים לסמן לכל שירות איזה סט של בדיקות שנכנס ב-10 דקות הוא ה 80/20.
- לפני שינויים רגישים במערכת - אפשר לסמן ל pipeline להריץ את הסט המלא של הבדיקות. שייקח שלוש שעות. אני מדבר על אירוע שאמור לקרות פעם בחודש בערך. אם השינויים שאנו מבצעים בקוד הם קטנים - אז הם לא כ"כ מסוכנים.
- סביבת Staging יחידה תיצור, מן הסתם, תור ארוך ב pipeline - כי מפתחים רוצים להכניס שינויים כל הזמן. בכדי להשיג מקביליות של עבודה - יהיו כמה סביבות Staging שכאלו: 2, 3, 5, 10 - תלוי בגודל הארגון. בדיקות מהירות מאפשרות לנו להחזיק בפחות סביבות Staging.
- ה Staging Environment דומה ככל האפשר לפרודקשיין:
- התקנה מבוצעת באותו האופן: clusters, מכונות נפרדות, DB נפרדים, קונפיגורציה - כמו בפרודקשין.
- ה Data יהיה לרוב Data שהוכן מראש לבדיקות האוטומציה.
רק לאחר שכל התהליכים האוטומטים הסתיימו (Isolated + Stating Environments), והתאפשרו בדיקות ידניות (של מפתחים / QA) על סביבת ה Integration (או Staging - לבקשתם) - ניתן לבצע את ההחלטה "לשחרר ל Production".
אם אתם זוכרים את הפוסט הקודם, כך זה נראה בצורה הפשטנית:
הנה תיאור קצת יותר מפורט של ה Pipeline שהראתי למעלה:
ליד כל שלב רשמתי זמן שנחשב סביר לתהליך. סה"כ, גם Pipelines יעילים אורכים כחצי שעה-שעה מרגע ה push לגיט - ועד לפעולה ב Production.
שלב למשל שהוספתי ב Pipeline המפורט הוא שלב שלא מופיע בתרשים ה High Level: בדיקות Rollback.
בסיפור הזה הארגון נתקל בכמה פעמים שהיו בעיות לבצע Rollback של שירותים בפרודקשיין - מה שמגביל את הארגון לשחרר את השירותים לפרודקשיין בחופשיות שהוא רוצה. אופציית ה Rollback היא חיונית להתאוששות מהירה.
על כן נוסף שלב נוסף ב Pipeline בשם Rollback Test. הוא הולך בערך כך:
- מתקינים את השירות בגרסה N (בצורה isolated) ומבצעים DB migration.
- מבצעים Rollback: מתקינים את השירות מחדש בגרסה N-1 (ללא rollback ב DB).
- מבצעים בדיקות Service/API של השירות בגרסה N-1 - לראות שהוא עובד בצורה תקינה.
כל התהליך הזה קורה במקביל לשאר התהליך והוא לא אמור להיכשל. אבל אם הוא נכשל - מונעים את היציאה של השירות הזה ל Production (עד שמתקנים את התאימות לאחור).
שלב כזה הוא בדרך כלל פרי ניסיון ולא תכנון מוקדם. קשה להעריך את העלות / תועלת של שלב שכזה - מבלי שהארגון הספציפי, עם המערכת שלו, השוק שלו, והתרבות שלו - עוברים כמה כשלים ב deployments בגלל נושא ה Rollback.
ה Pipeline אמור להשתנות לאורך הזמן ולהתאים את עצמו לצורכי הארגון: לפעמים להוסיף שלבים - ולעתים להסיר ממנו שלבים.
בהקמת ה Pipeline, וגם לאורך חייו, הארגון ישאל את עצמו שאלות שונות:
- האם את הבדיקות הראשונות של המיקרו-שירות, לבצע במכונה בודדת (עם stubs) - או האם להרים landscape שלם? מישהו צריך לשלם על מכונות ה landscape - וזה ייקח יותר זמן.
- כמה אנו מוכנים לחכות לבדיקות? יותר בדיקות = יותר בטחון, מצד שני - פחות יעילות וזמן תגובה לשינויים ב Production?
- היכן לעשות בדיקות ידניות? בסביבת אינטגרציה - ואז לגלות בעיות אינטגרציה מוקדם יותר, או בסביבת Staging? ואז להגביר את הסיכוי למנוע את הבעיה הבאה בפרודקשיין? זו לא רק שאלה של עדיפות פילוסופית: פריון עבודה מול יציבות הפרודקשיין - זו שאלה כמה מנגנוני ה Rollback והבדיקות השונות יעילים, והיכן יש לפצות אותם?
- האם להשקיע ב Load Tests כחלק מה Pipeline - או האם להסתמך על Canary Tests (בהמשך) עבור Load?
- האם לבצע הרצה של כל הבדיקות האפשריות מדי פעם (על תצורה שהגיעה לפרודקשיין), גם אם סט הבדיקות לוקח שעות רבות? (פעמים רבות - עושים זאת).
- ועוד ועוד...
שווה לציין באזז עכשווי בשם Pipeline as Code. מכיוון שה Pipeline הופך ונעשה מורכב, התחילה גישה בה ניתן "לתכנת" אותו בשפת תכנות ולא רק בקונפיגורציה.
את המונח Pipeline as Code ייתכן ותשמעו מהפרסומים של Jenkins 2.0 - שלכאורה עבר שינוי מהותי בכדי לתמוך ביכולות הללו. בפועל הוצגה מערכת Plugins שעדיין רחוקה מהאידאל של Pipeline as Code. מקביליות בהרצת בדיקות עדיין מבוססת בעיקרה על Plugins ואיננה יכולת ליבה של המערכת - וכך גם השגת הגמישות ב Pipeline עצמו. ניתן לומר (באופן מעט מרושע) ש Jenkins 2.0 היא מוצר Pipeline by Plugins.
Jenkins הוא עדיין כנראה הכלי הנפוץ ביותר לבניית Deployment Pipeline, אם כי כלים כמו Concourse CI או goCD ו gomatic - נחשבים למתאימים יותר לבניית ה Deployment Pipeline. ייתכן והגיע זמנו של Jenkins לפנות את כס המלכות.
עוד כמה רעיונות של CD שכדאי להכיר
Infrastructure as Code / Everything as Code - מכיוון שחשוב שהקונפיגורציה של המערכות תהיה זהה בין סביבות ה Staging וה Production, ומכיוון שחשוב שהקמת סביבה לפי אותה קונפיגורציה נתונה יהיה תהליך אוטומטי, מהיר, ואמין - הרעיון הוא שכל הגדרות המערכת, או מה שגורם להן יהיה מנוהל כמו קוד, ב Version Control System - אם אותה בקרה (למשל: pull requests) ותהליכים שמוכיחים את עצמם עבור קוד.
אלו חדשות ישנות כבר - אני מניח.
Blue/Green Deployment - הרעיון בו שחרור גרסה חדשה של שירות מבוצע באופן הבא:
אלו חדשות ישנות כבר - אני מניח.
Blue/Green Deployment - הרעיון בו שחרור גרסה חדשה של שירות מבוצע באופן הבא:
תמיד מחזיקים ב Production שתי סטים של מכונות (או clusters): סט כחול וסט ירוק. כל סט מספיק גדול בכדי לשרת את כל התעבורה ב production בעצמו.
סט אחד תמיד יהיה עם גרסה N, והסט השני - עם גרסה N-1.
נניח שאנו עכשיו בגרסה הירוקה, ורוצים לבצע התקנה של גרסה חדשה: נתקין אותה על סט המכונות הכחול.
נוודא שההתקנה הצליחה (בעזרת smoke tests).
עכשיו פשוט נורה ל Load Balancer להעביר את כל התעבורה ל Set הכחול. זה תהליך של שניות - בד"כ. בקשה שכבר התחילה תסתיים במכונה הירוקה, אבל הבקשה הבאה - תגיע לסט המכונות הכחולות.
הכל טוב? הסט הכחול הפך להיות הסט הפעיל.
יש בעיה? ניתן לבצע Rollback בשניות ולהחזיר את התעבורה לסט הירוק.
חיסרון ניכר הוא הצורך בחומרה כפולה.
וריאציה מקובלת היא להחזיק רק סט אחד של חומרה ברוב הזמן, ורק בעת התקנת גרסה חדשה - להרים סט נוסף (פעולה פשוטה בענן). לאחר ההעברה, מחזיקים את הסט הקודם של המכונות לשעה נוספת - כי רוב התקלות בפרודקשיין מתרחשות זמן קצר לאחר מעבר גרסה. הכל בסדר לאחר שעה? - מורידים את סט המכונות היתיר.
Canary Release - הרעיון הזה הוא וריאציה של Blue/Green Deployment.
הרעיון הוא לבצע את ההתקנה באותו האופן (נניח שהגרסה החדשה שהתקנתי היא על סט המכונות הכחולות), אבל להעביר רק כמות מזערית של תעבורה לסט הכחול: במקום 100% מהתעבורה - להעביר רק 1% מהתעבורה.
עכשיו מחכים זמן קצר לראות אם מערכות המוניטורינג של הסט הכחול מזהה בעיה. נאמר: לרבע שעה.
אם יש בעיה - מחזירים את 1% התעבורה לסט הירוק. אם לא - מתקדמים ל 100% לסט הכחול.
המטפורה לשם Canary Release הוא הנוהג של כורים להחזיק כלובים עם קנריות כאמצעי התרעה מוקדם.
אם היו נפלטים גזים רעילים בעת הכרייה, הציפורים העדינות היו מתות ראשונות - ולכורים הייתה הזדמנות להסתלק לפני שיספגו פגיעה קשה.
Dark Deployment - הרעיון כאן הוא שאין חובה ש Deployment יהיה גם בעצם Release.
פיצ'רים רבים במערכת - ניתן לשחרר אותם עם Feature Flag כבוי. הפיצ'ר הוא Deployed, אך לא Released.
למה לעשות את זה? בזמן הזה QA או המפתחים יכולים לבדוק את הפיצ'ר בפרודקשן, בסביבה הכי אמיתית עם תעבורה אמיתית. אפשר לעשות beta testing למשתמשים נבחרים - ולהכניס בפיצ'ר שיפורים, ורק כשהוא מוכן, בדוק, ויציב - לשחרר אותו.
כיום הפרקטיקה של Dark Deployment היא דיי מקובלת, גם אם מי שעושה זאת לא מכיר ולא משתמש המונח הרשמי :).
סיכום
שוחחנו על CD לא מעט - זה נושא גדול, שנוטה להעסיק את הארגון רבות.
עדיין לא שוחחנו על איך מתחילים בהטמעה של CD בארגון שלא רגיל לכך, ולא על Continuous Deployment: האם זה באמת רק דילוג על שלב ה manual tests?
שיהיה בהצלחה!