← חזרה אל בלוג

בלוג

שליטה ב-Docker Compose לאירוח אתרים מבודד וניתן לשחזור

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

סיכום

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

מעבר ל"זה עובד אצלי במכונה": שליטה במחסנית אירוח האתרים שלך עם Docker Compose

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

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

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

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

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

  • שרת אינטרנט: מגיש את החלק הקדמי של היישום שלך (למשל, Nginx, Apache).
  • שרת יישומים/סביבת ריצה: מריץ את קוד ה-backend שלך (למשל, Node.js, Python/Gunicorn, PHP-FPM).
  • מסד נתונים: מאחסן נתונים קבועים (למשל, PostgreSQL, MySQL, MongoDB).
  • מטמון: משפר ביצועים על ידי אחסון נתונים הנגישים בתדירות גבוהה (למשל, Redis, Memcached).
  • שירותים נוספים: כגון תורי הודעות, מנועי חיפוש או מעבדי משימות ברקע.

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

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

הפתרון: Docker Compose לתשתית דקלרטיבית

Docker Compose מתמודד עם אתגרים אלה בכך שהוא מאפשר לך להגדיר את כל מחסנית היישום שלך בקובץ יחיד docker-compose.yml. קובץ זה משמש כתוכנית אב-טיפוס, המציינת כל שירות, התמונה שלו, יציאות, ווליומים, משתני סביבה, וכיצד שירותים צריכים להתחבר זה לזה.

מושגי מפתח ב-docker-compose.yml:

  • version: מציין את גרסת פורמט קובץ ה-Compose. מומלץ להשתמש בגרסה עדכנית.
  • services: זהו החלק המרכזי שבו אתה מגדיר כל רכיב מקונטיינר של היישום שלך.
    • image: תמונת ה-Docker לשימוש עבור השירות (למשל, nginx:latest, postgres:14). ניתן גם להשתמש ב-build כדי לציין Dockerfile לתמונות מותאמות אישית.
    • ports: ממפה יציאות ממכונת המארח לקונטיינר (למשל, 80:80 ממפה יציאה 80 של המארח ליציאה 80 של הקונטיינר).
    • volumes: טוען ספריות מארח או ווליומים בשם לתוך הקונטיינר עבור נתונים קבועים או תצורה (למשל, ./html:/usr/share/nginx/html).
    • environment: מגדיר משתני סביבה בתוך הקונטיינר (למשל, POSTGRES_USER=myuser).
    • depends_on: מציין תלויות בין שירותים, מבטיח שהם יתחילו בסדר מסוים (אם כי זה לא מבטיח מוכנות).
    • networks: מגדיר רשתות מותאמות אישית עבור השירותים שלך לתקשורת.
  • networks: מגדיר רשתות מותאמות אישית שהשירותים שלך יכולים להצטרף אליהן לתקשורת מבודדת.
  • volumes: מגדיר ווליומים בשם לאחסון נתונים קבועים.

שלבים מעשיים: בניית מחסנית אירוח אתרים לדוגמה

בואו נבנה תרחיש אירוח אתרים נפוץ: אתר סטטי המוגש על ידי Nginx, עם מסד נתונים PostgreSQL לתוכן דינמי. נוסיף גם מטמון Redis לשיפור ביצועים.

1. מבנה הפרויקט:

צור ספרייה עבור הפרויקט שלך, למשל, my-web-app. בפנים, יהיו לך:

my-web-app/
├── docker-compose.yml
├── nginx/
│   └── default.conf
└── html/
    └── index.html

**2. nginx/default.conf (תצורת Nginx בסיסית):

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

server {
    listen 80;
    server_name localhost;

    root /usr/share/nginx/html;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }
}

**3. html/index.html (תוכן האתר שלך):

קובץ HTML פשוט לבדיקה.

<!DOCTYPE html>
<html>
<head>
    <title>Welcome to My Dockerized Site!</title>
</head>
<body>
    <h1>Hello from Docker Compose!</h1>
    <p>This site is served by Nginx in a container.</p>
</body>
</html>

**4. docker-compose.yml (לב ההגדרה):

קובץ זה מגדיר את שלושת השירותים שלנו: Nginx, PostgreSQL ו-Redis.

version: '3.8'

services:
  webserver:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - db
      - cache
    networks:
      - app-network

  db:
    image: postgres:14
    environment:
      POSTGRES_DB: mydatabase
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mysecretpassword
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - app-network

  cache:
    image: redis:latest
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  db_data:

הסבר על docker-compose.yml:

  • שירות webserver: משתמש בתמונת Nginx הרשמית. הוא ממפה את יציאה 80 של המארח ליציאה 80 של הקונטיינר. הוא טוען את ספריית html המקומית שלנו עבור תוכן האתר ואת nginx/default.conf המותאם אישית שלנו עבור תצורת Nginx. באופן מכריע, הוא depends_on על db ו-cache, מה שמציין ששירותים אלה צריכים להתחיל לפני שרת האינטרנט. הוא מחובר ל-app-network המותאם אישית שלנו.
  • שירות db: משתמש בתמונת PostgreSQL הרשמית. אנו מגדירים משתני סביבה חיוניים ליצירת מסד נתונים, משתמש וסיסמה. ווליום בשם db_data משמש להבטחת שהנתונים של מסד הנתונים יישארו גם אם הקונטיינר יוסר וייווצר מחדש. הוא גם מתחבר ל-app-network.
  • שירות cache: משתמש בתמונת Redis הרשמית. זהו שירות פשוט ללא צורך בנתונים קבועים עבור דוגמה זו ומתחבר ל-app-network.
  • networks: אנו מגדירים רשת גשר יחידה בשם app-network. זה חשוב לבידוד ותקשורת. כברירת מחדל, Docker Compose יוצר רשת, אך הגדרתה במפורש נותנת לנו יותר שליטה ובהירות. שירותים באותה רשת מותאמת אישית יכולים להגיע זה לזה באמצעות שמות השירותים שלהם כשמות מארח (למשל, שרת האינטרנט יכול להתחבר ל-db ב-localhost:5432 או db:5432 בהתאם לתצורה וההקשר).
  • volumes: אנו מגדירים את הווליום בשם db_data. Docker מנהל את מחזור החיים של ווליומים אלה.

5. הפעלת המחסנית שלך:

נווט לספריית הפרויקט שלך (my-web-app/) בטרמינל שלך והרץ:

docker compose up -d
  • docker compose: מפעיל את פקודת Docker Compose.
  • up: יוצר ומפעיל את הקונטיינרים המוגדרים ב-docker-compose.yml.
  • -d: מריץ את הקונטיינרים במצב מנותק (ברקע).

6. אימות:

פתח את דפדפן האינטרנט שלך וגלוש ל-http://localhost. אתה אמור לראות את התוכן של קובץ index.html שלך.

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

docker compose ps

זה יציג לך את הסטטוס של הקונטיינרים webserver, db ו-cache שלך.

7. עצירת המחסנית שלך:

כשתסיים, עצור והסר את הקונטיינרים, הרשתות והווליומים (אופציונלי):

docker compose down

כדי להסיר גם את הווליומים בשם (שימחקו את נתוני מסד הנתונים שלך), השתמש ב:

docker compose down -v

בידוד ושחזור בפעולה

בידוד:

Docker Compose מבטיח בידוד בכמה דרכים:

  • בידוד תהליכים: כל שירות פועל בקונטיינר משלו, מבודד מהמארח ומקונטיינרים אחרים. יש להם מערכת קבצים משלהם, מרחב תהליכים וממשקי רשת.
  • בידוד רשת: על ידי הגדרת רשת מותאמת אישית (app-network), אנו שולטים כיצד שירותים מתקשרים. כברירת מחדל, קונטיינרים ברשתות שונות אינם יכולים לתקשר. שירותים באותה רשת יכולים לתקשר רק אם מותר במפורש או אם הם חושפים יציאות. בדוגמה שלנו, webserver יכול להגיע לשירותי db ו-cache באמצעות שמות השירותים שלהם, אך גישה חיצונית ליציאות מסד הנתונים והמטמון אינה חשופה כברירת מחדל, מה שמשפר את האבטחה.
  • ניהול תלויות: depends_on עוזר לנהל את סדר ההפעלה, ומונע בעיות שבהן שירות מנסה להתחבר לתלות שעדיין לא הופעלה.

שחזור:

קובץ docker-compose.yml הוא המקור היחיד לאמת עבור סביבת היישום שלך. כל אחד עם Docker ו-Docker Compose מותקנים יכול לשכפל את הפרויקט שלך, להריץ docker compose up -d, ולקבל סביבה זהה ופועלת. זה מבטל את בעיית "זה עובד אצלי במכונה" על ידי אריזת לא רק היישום שלך, אלא את כל סביבת ההפעלה שלו.

שיקולים מתקדמים והסתייגויות

  • depends_on לעומת מוכנות שירות: depends_on רק מבטיח שקונטיינר הופעל. הוא אינו מבטיח שהיישום בתוך הקונטיינר מוכן לקבל חיבורים. עבור מסדי נתונים, זוהי בעיה נפוצה. ייתכן שתצטרך ליישם בדיקות תקינות או מנגנוני ניסיון חוזר בקוד היישום שלך או להשתמש בכלים כמו סקריפטים wait-for-it.sh בתוך נקודת הכניסה שלך.
  • פריסות ייצור: בעוד ש-Docker Compose מצוין לפיתוח ובדיקה, עבור ייצור, לרוב תרצה תזמור חזק יותר. כלים כמו Kubernetes או Docker Swarm מיועדים לניהול יישומים מקונטיינרים בקנה מידה, טיפול באיזון עומסים, ריפוי עצמי ועדכונים מתגלגלים. עם זאת, קבצי Docker Compose ניתנים לעיתים קרובות להתאמה או לשמש בסיס למתזמרים מתקדמים יותר אלה.
  • ניהול תמונות: עבור ייצור, מומלץ להשתמש בתגיות תמונה ספציפיות (למשל, postgres:14.5) במקום latest כדי להבטיח פריסות צפויות. ייתכן גם שתבנה תמונות מותאמות אישית משלך באמצעות Dockerfiles עבור קוד היישום שלך.
  • אבטחה: תמיד היה מודע למידע רגיש כמו סיסמאות למסד נתונים. השתמש במשתני סביבה, ושקול להשתמש בסודות Docker או בכלי ניהול סודות חיצוניים עבור סביבות ייצור במקום לקודד אותם ישירות ב-docker-compose.yml.
  • מגבלות משאבים: עבור ייצור, תרצה להגדיר מגבלות משאבים (CPU, זיכרון) עבור הקונטיינרים שלך כדי למנוע משירות אחד לצרוך את כל המשאבים הזמינים במארח.
  • מורכבות רשת: ככל שהיישום שלך גדל, ניהול תצורות רשת מורכבות יכול להפוך למאתגר. יכולות הרשת של Docker עוצמתיות אך דורשות תכנון קפדני.

מסקנה

Docker Compose משנה את הדרך בה אנו חושבים על פריסה וניהול של יישומי אינטרנט. בכך שהוא מאפשר לך להגדיר את כל המחסנית שלך באופן דקלרטיבי בקובץ docker-compose.yml, הוא מביא עקביות, בידוד ושחזור ללא תחרות לתהליכי הפיתוח והפריסה שלך. הוא מתמודד ישירות עם בעיית "זה עובד אצלי במכונה" על ידי אריזת לא רק היישום שלך, אלא את כל סביבת ההפעלה שלו. בין אם אתה מפתח יחיד המגדיר פרויקט אישי או חלק מצוות גדול יותר, שליטה ב-Docker Compose היא צעד חיוני לקראת בניית פתרונות אירוח אתרים אמינים, ניתנים לתחזוקה ויעילים יותר. הוא מניח בסיס איתן להבנת טכנולוגיות תזמור קונטיינרים מתקדמות יותר ובסופו של דבר מוביל למחזורי פיתוח חלקים יותר ומערכות ייצור חזקות יותר.

Sources (5)