Flyway לאוטומציה של מיגרציות מסד נתונים: הגדרה והטמעה ב-CI/CD

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

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

שאלות נפוצות

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

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

מיגרציות ידניות שוברות שחרורים: היכן מתפרקת הגדרת Flyway

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

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

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

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

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

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

מה נותן סדר מנוהל של מיגרציות סכימה

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

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

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

אפשרויות הגדרה של Flyway: השוואת מצבי עבודה

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

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

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

כיצד לבחור מצב לפי סביבה

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

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

שלבי יישום: מביקורת סכימה ועד מסירת נהלים

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

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

מה נשאר במאגר ובצוות אחרי היישום

היישום נחשב завершённым לא כשהמיגרציה עברה בסביבת הבדיקות, אלא כשנשאר לצוות מערך תוצרים שכל מהנדס יכול לשחרר לפיו את הגרסה הבאה, ולא רק מחבר השינויים. להלן הסט המינימלי שאנו מוסרים יחד עם צינור עבודה פעיל; כל סעיף נבדק בקבלה.

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

המערך נשאר במאגר שלכם ובמערכת ניהול המשימות שלכם — אפשר להשתמש בו גם בלעדינו.

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

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

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

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

מה השתנה אחרי היישום

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

מה לעשות אם חלק מהמיגרציות כבר יושמו ידנית

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

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

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

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

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

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

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

השירות עולה בכמה מופעים — האם המיגרציה תיושם פעמיים?

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

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

מה יישאר בבסיס הנתונים אם מיגרציה תיפול באמצע?

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

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

כיצד מוחקים עמודות ומתאמים שינויים מסוכנים?

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

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

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

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

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

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