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

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

במדריך זה, נתמקד בשיטת למתחילים להקמת צינור CI/CD בסיסי באמצעות Bitbucket, שרת Linux ו-Python עם Flask. במיוחד, ניצור תהליך אוטומטי שמושך את השינויים האחרונים ממאגר ה-Bitbucket שלך לשרת ה-Linux שלך בכל פעם שיש דחיפה או מיזוג לסניף מסוים.

התהליך יופעל על ידי וובהוקים של Bitbucket ושרת Python קטן המבוסס על Flask שמאזין לאירועי וובהוק נכנסים ומפעיל את ההטמעה.

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

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

עם סיום המדריך הזה, יהיה לך דוגמה פועלת של כיצד לאוטומציה את ההתקנות באמצעות Bitbucket, Linux ו-Python, שבה תוכל לבנות עליה בעת שתרגיש נוח יותר עם מושגי CI/CD.

תוכן עניינים:

  1. למה CI/CD חשוב?

  2. שלב 1: הגדרת Webhook ב-Bitbucket

  3. שלב 2: הגדרת הקשב ב-Flask על שרת ה-Linux שלך

  4. שלב 3: חשיפת היישום Flask (אופציונלי)

  5. שלב 4: בדיקת ההתקנה

  6. שלב 5: שיקולים בטחוניים

  7. סיכום

למה CI/CD חשוב?

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

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

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

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

מה נכסה במדריך זה

במדריך זה, נלמד איך להגדיר צינור CI/CD פשוט המאופטמת את ההפצה של שינויי קוד ממאגר Bitbucket לשרת Linux. הנה מה שתלמדו:

  1. איך להגדיר את מאגר ה-Bitbucket כך שישלח התראות webhook בכל פעם שיש דחיפה או מיזוג לסניף ספציפי.

  2. איך להתקין שרת Python בעל מבנה Flask על השרת שלך כדי להאזין לאירועי webhook נכנסים.

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

  4. איך לבדוק ולתקן את תהליך ההפצה האוטומטית שלך.

עד סוף המדריך הזה, יהיה לך דוגמה פועלת של צינור CI/CD בסיסי שתוכל להתאים ולהרחיב כפי שנדרש. בואו נתחיל!

שלב 1: הגדרת Webhook ב-Bitbucket

לפני שנתחיל עם ההתקנה, בואו נסביר בקצרה מהו Webhook ואיך הוא משתלב בתהליך ה- CI/CD שלנו.

Webhook הוא מנגנון שמאפשר למערכת אחת להודיע למערכת אחרת על אירוע בזמן אמת. בהקשר של Bitbucket, ניתן להגדיר Webhook כך שישלח בקשת HTTP (לעיתים בקשת POST עם נתוני גוף) לכתובת URL מסוימת בכל פעם שאירוע ספציפי מתרחש במאגר שלך, כמו דחיפה לסניף או מיזוג בקשת משיכה.

במקרה שלנו, ה-Webhook יודיע לשרת ה-Python שבסיסו של Flask (המופעל על השרת שלך ב-Linux) כאשר יש דחיפה או מיזוג לסניף מסוים. ההודעה הזאת תפעיל סקריפט על השרת שימשך את השינויים האחרונים מהמאגר ויפרסם אותם באופן אוטומטי. בגדר כך, ה-Webhook פועל כגשר בין Bitbucket והשרת שלך, מאפשר הפעלה אוטומטית חלקה של תהליך ההפצה.

עכשיו שהבנת את התפקיד של Webhook, בוא נגדיר אחד ב-Bitbucket:

  1. התחברו ל-Bitbucket ונווטו אל המאגר שלכם.

  2. בסרגל הצד שמאל, לחצו על הגדרות.

  3. בתחום ה-Workflow, מצאו ולחצו על Webhooks.

  4. לחצו על הכפתור הוספת webhook.

  5. הזינו שם עבור ה-webhook שלכם (לדוגמה, "Automatic Pull").

  6. בשדה ה-URL, ספקו את כתובת ה-URL של השרת שלכם שבו ה-webhook ישלח את הבקשה. אם אתם מריצים אפליקציית Flask מקומית, זה יהיה משהו דומה ל-http://your-server-ip/pull-repo. (בסביבות הפיתוח, מומלץ בחום להשתמש ב-HTTPS על מנת לאבטח את התקשורת בין Bitbucket לשרת שלכם.)

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

  8. שמור את ה-webhook עם שם שמסביר את עצמו כך שיהיה קל לזהות אותו מאוחר יותר.

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

כך תראה ההגדרה של ה-webhook של Bitbucket

שלב 2: הגדר את האזנן של Flask בשרת ה-Linux שלך

בשלב הבא, תגדיר שרת אינטרנט פשוט על המכונה שלך בלינוקס שישמיע ל-webhook מ-Bitbucket. כאשר הוא מקבל את ההתראה, הוא יבצע git pull או פורס pull (במקרה של שינויים מקומיים) כדי לעדכן את המאגר.

התקן את Flask:

כדי ליצור את היישום Flask, התקן תחילה את Flask באמצעות הרצת:

pip install flask

צור את היישום Flask:

צור קובץ Python חדש (לדוגמה, app_repo_pull.py) על השרת שלך והוסף את הקוד הבא:

from flask import Flask
import subprocess

app = Flask(__name__)

@app.route('/pull-repo', methods=['POST'])
def pull_repo():
    try:
        # אחזר את השינויים האחרונים מהמאגר המרוחק
        subprocess.run(["git", "-C", "/path/to/your/repository", "fetch"], check=True)
        # אפס באופן כפוי את הסניף המקומי כדי להתאים לסניף המרוחק 'test'
        subprocess.run(["git", "-C", "/path/to/your/repository", "reset", "--hard", "origin/test"], check=True)  # החלף את 'test' בשם הסניף שלך
        return "Force pull successful", 200
    except subprocess.CalledProcessError:
        return "Failed to force pull the repository", 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

כך נראה הקוד:

  • subprocess.run(["git", "-C", "/path/to/your/repository", "fetch"]): פקודה זו מביאה את השינויים האחרונים מהמאגר המרוחק מבלי להשפיע על ספריית העבודה המקומית.

  • subprocess.run(["git", "-C", "/path/to/your/repository", "reset", "--hard", "origin/test"]): פקודה זו מבצעת איפוס קשה, מכריחה את המאגר המקומי להתאים לענף test במרחק. החלף את test בשם הענף שלך.

ודא שתחליף את /path/to/your/repository בנתיב המדויק למאגר ה-Git המקומי שלך.

שלב 3: לחשוף את אפליקציית ה-Flask (אופציונלי)

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

ראשית, התקן את NGINX אם עדיין לא עשית זאת על ידי הרצת הפקודה הזו:

sudo apt-get install nginx

בשלב הבא, עליך להגדיר את NGINX כך שיפנה בקשות לאפליקציית ה-Flask שלך. פתח את קובץ התצורה של NGINX:

sudo nano /etc/nginx/sites-available/default

שנה את ההגדרות כך שיכלול בלוק זה:

server {
    listen 80;
    server_name your-server-ip;

    location /pull-repo {
        proxy_pass http://localhost:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

עכשיו רק טען מחדש את NGINX כדי ליישם את השינויים:

sudo systemctl reload nginx

שלב 4: בדוק את ההגדרה

עכשיו שהכל מוכן, התחיל את אפליקציית ה-Flask על ידי ביצוע סקריפט Python זה:

python3 app_repo_pull.py

עכשיו נבדוק אם הכל עובד:

  1. בצע commit: דחוף commit לסניף test במאגר ה-Bitbucket שלך. פעולה זו תפעיל את ה-webhook.
  1. הפעלת ה-webhook: ה-webhook ישלח בקשת POST לשרת שלך. אפליקציית Flask תקבל את הבקשה הזו, תבצע פעולת force pull מהסניף test, ותעדכן את המאגר המקומי.

  2. אימות ה-pull: בדוק את פלט הלוג של אפליקציית Flask שלך או בדוק את המאגר המקומי כדי לוודא שהשינויים נמשכו ויושמו בהצלחה.

שלב 5: שיקולים אבטחתיים

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

1. שימוש בשרת מאובטח עם חוקי חומת אש נכונים

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

דוגמה להגדרת שרת מאובטחה:
  • תוכנה מינימלית: התקן רק את התוכנה שאתה זקוק אליה (לדוגמה, Python, Flask, NGINX) והסר שירותים לא נחוצים.

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

  • הגדרת חומת אש: השתמש בחומת אש כדי לשלוט בתעבורת נכנסת ויוצאת ולהגביל גישה לשרת שלך.

לדוגמה, הגדרת UFW (חומת אש פשוטה) באובונטו עשויה להיראות כך:

# מאפשר חיבורי SSH (פורט 22) לגישה מרחוק
sudo ufw allow ssh

# מאפשר HTTP (פורט 80) ו-HTTPS (פורט 443) לתעבורת אינטרנט
sudo ufw allow http
sudo ufw allow https

# מפעיל את החומת אש
sudo ufw enable

# בודק את מצב החומת אש
sudo ufw status

במקרה זה:

  • החומת אש מאפשרת חיבורים נכנסים של SSH בפורט 22, HTTP בפורט 80, ו-HTTPS בפורט 443.

  • כל היציאות או השירותים המיותרים צריכים להיות חסומים כברירת מחדל כדי להגביל את החשיפה לתקיפות.

כללי חומת אש נוספים:
  • הגבלת גישה לנקודת הקצה של ה-webhook: באופיראנטה הטובה ביותר, עליכם להרשות תעבורה לנקודת הקצה של ה-webhook רק מכתובות ה-IP של Bitbucket כדי למנוע גישה חיצונית. ניתן להגדיר זאת בחומת האש שלכם או באמצעות השרת האינטרנטי שלכם (לדוגמה, NGINX) על ידי קבלת בקשות רק מטווח ה-IP של Bitbucket.

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

2. הוספת אימות לאפליקציית Flask

מאחר שהאפליקציה שלכם ב-Flask תהיה נגישה לציבור דרך כתובת ה-webhook, עליכם לשקול להוסיף אימות כדי לוודא שרק משתמשים מורשים (כמו שרתי Bitbucket) יכולים להפעיל את ה-pull.

דוגמה לאימות בסיסי:

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

from flask import Flask, request, abort
import subprocess

app = Flask(__name__)

# הגדר טוקן סודי לאימות ה-webhook
SECRET_TOKEN = 'your-secret-token'

@app.route('/pull-repo', methods=['POST'])
def pull_repo():
    # בדוק אם הבקשה מכילה את הטוקן הנכון
    token = request.headers.get('X-Hub-Signature')
    if token != SECRET_TOKEN:
        abort(403)  # אסור אם הטוקן אינו נכון

    try:
        subprocess.run(["git", "-C", "/path/to/your/repository", "fetch"], check=True)
        subprocess.run(["git", "-C", "/path/to/your/repository", "reset", "--hard", "origin/test"], check=True)
        return "Force pull successful", 200
    except subprocess.CalledProcessError:
        return "Failed to force pull the repository", 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
איך זה עובד:
  • ה-X-Hub-Signature הוא כותרת מותאמת אישית שאתה מוסיף לבקשה כאשר אתה מגדיר את ה-webhook ב-Bitbucket.

  • רק בקשות עם הטוקן הנכון יורשמו להפעיל את ה-pull. אם הטוקן חסר או שאינו נכון, הבקשה תושלם עם תשובת 403 Forbidden.

ניתן גם להשתמש בצורות מורכבות יותר של אימות, כגון OAuth או HMAC (Hash-based Message Authentication Code), אך גישת הטוקן הפשוטה זו עובדת עבור רוב המקרים.

3. השתמש ב-HTTPS לתקשורת מאובטחת

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

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

  • אמינות ושלמות: HTTPS עוזר לוודא שהנתונים שנשלחים לשרת שלך לא עברו תיקול.

שימוש ב־Let’s Encrypt לאבטחת אפליקציית Flask שלך עם SSL:
  1. התקן את Certbot (הכלי לקבלת תעודות Let’s Encrypt):
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx

קבל תעודת SSL חינמית עבור הדומיין שלך:

sudo certbot --nginx -d your-domain.com
  • פקודה זו תגדיר באופן אוטומטי את Nginx לשימוש ב־HTTPS עם תעודת SSL חינמית מ־Let’s Encrypt.

  • וודא שמשתמשים ב־HTTPS: וודא שאפליקציית Flask שלך או תצורת Nginx כוללת חוק שמכוון את כל התעבורה לשימוש ב־HTTPS. ניתן לעשות זאת על ידי יצירת כלל הפניה ב־Nginx:

server {
    listen 80;
    server_name your-domain.com;

    # הפנית HTTP ל-HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    # תצורת Nginx אחרת...
}

חידוש אוטומטי: תעודות Let’s Encrypt תקפות למשך 90 ימים, לכן חשוב להגדיר חידוש אוטומטי:

sudo certbot renew --dry-run

פקודה זו בודקת את תהליך החידוש כדי לוודא שהכל עובד.

4. רישום ומעקב

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

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

  • שימוש בכלים למעקב: הגדר כלים כמו Prometheus, Grafana, או New Relic למעקב אחר ביצועי השרת ובריאות האפליקציה.

סיכום

במדריך זה, חקרנו איך להגדיר צינור CI/CD פשוט וידידותי למתחילים שמאפשר העלאות אוטומטיות באמצעות Bitbucket, שרת Linux, ו-Python עם Flask. הנה סיכום של מה שלמדת:

  1. יסודות CI/CD: דנו ביסודות של אינטגרציה רציפה (CI) ושקיפות/הפצה רציפה (CD), שהן שיטות חיוניות לאוטומציה של אינטגרציה, בדיקה והפצת קוד. למדת כיצד CI/CD מסייע בהאצת הפיתוח, צמצום שגיאות ושיפור שיתוף פעולה בין המפתחים.

  2. הגדרת Webhooks של Bitbucket: למדת כיצד להגדיר webhook של Bitbucket כדי להודיע לשרת על פעולת push או מיזוג לענף מסוים. ה-webhook הזה משמש כמנגנון הפעלה להתחלת תהליך ההפצה באופן אוטומטי.

  3. יצירת מאזין Webhook במבוסס Flask: הראינו לך כיצד להגדיר אפליקציית Flask על השרת שלך ב-Linux כדי להאזין לבקשות webhook נכנסות מ-Bitbucket. אפליקציית Flask זו מקבלת את ההודעות ומריצה את הפקודות של Git הנחוצות כדי למשוך ולהפיץ את השינויים האחרונים.

  4. אוטומציה של תהליך ההעלאה: באמצעות Python ו-Flask, אוטומצנו את תהליך משיכת השינויים ממאגר ה-Bitbucket וביצענו משיכת force כדי לוודא שהקוד האחרון נוצר. למדת גם איך להגדיר את השרת כך שיחשף את אפליקציית Flask ויקבל בקשות באופן מאובטח.

  5. שיקולים בטחוניים: כיסינו שלבים בטחוניים חיוניים כדי להגן על תהליך ההעלאה שלך:

    • כללי חומת אש: דנו בהגדרת כללי חומת אש כדי להגביל את החשיפה ולוודא שרק תעבורת מורשית (מ-Bitbucket) יכולה לגשת אל השרת שלך.

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

    • HTTPS: הסברנו כיצד לאבטח את התקשורת בין השרת שלך ו-Bitbucket באמצעות תעודות SSL מ-Let's Encrypt.

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

השלבים הבאים

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

  • צינורות פיתוח בשלבים מרובים

  • שילוב עם כלים לקונטיינרים כמו Docker

  • בדיקות ואסטרטגיות פיתוח מורכבות יותר

  • שימוש בכלים לאורכסטרציה כמו Kubernetes לצורך התמקצעות

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

ניתן לצפות את הקוד מכאן.