SSD Nodes Learn Hosting plans →
מדריכים Matt Connorמאת Matt Connor

מדריך פקודות Docker Compose לשרתים: רשימה פרקטית

ריכזנו עבורכם את פקודות Docker Compose V2 החיוניות לניהול שרתים. למדו כיצד להריץ, לעצור ולנקות מכולות בבטחה, ומה לעשות כשמופיעה השגיאה docker-compose: command not found.

פקודות Compose שבאמת משתמשים בהן

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

כל המפורט כאן משתמש ב-Compose V2 או V5: docker compose עם רווח, ולא בסקריפט הישן docker-compose. שניהם תוספי Go; בלינוקס, תוסף ה-Compose מותקן בנפרד מ-Docker Engine. הגרסה Ubuntu 24.04 LTS עדיין מציעה את הכלי הישן מבוסס Python V1 כ-docker-compose בגרסה 1.29.2-6ubuntu1 במאגר ה-universe שלה. בדקו זאת באמצעות docker compose version. אם הפקודה אינה זמינה, הגדירו את המאגר של Docker והתקינו את החבילה docker-compose-plugin.

כל פקודה להלן מורצת מתוך התיקייה שמכילה את ה-compose.yaml שלכם; Compose משתמש בשם התיקייה כשם הפרויקט כברירת מחדל, אלא אם תגדירו אחרת. ללא -f או COMPOSE_FILE, Compose מחפש קובץ תצורה בתיקיית העבודה הנוכחית ובתיקיות האב שלה, לכן הרצה מרמה אחת מעל תמצא את ה-stack שלכם רק אם הקובץ עדיין נמצא בנתיב החיפוש הזה. אם פורמט הקובץ עצמו חדש לכם, התחילו ב-קובץ Compose ראשון על גבי VPS וחזרו לכאן עבור הפקודות.

מחזור חיים: ארבע הפקודות שאתה מריץ, והאחת שמוחקת מכולות

docker compose up -d
docker compose up -d --wait
docker compose stop
docker compose start
docker compose restart web
docker compose down

up -d יוצר את הרשת, יוצר את המכולות, מפעיל אותן ומחזיר שליטה. הפקודה מסתיימת מיד לאחר הפעלת המכולות מבלי להמתין לכך שהיישום יהיה מוכן, וזו הסיבה שתסריט פריסה שמריץ מיד לאחר מכן בדיקת curl נכשל לעיתים קרובות בניסיון הראשון. up -d --wait ממתינה לכך ששירותים עם healthchecks יהיו במצב תקין וששירותים ללא בדיקה כזו יהיו פעילים; שירות לא תקין או --wait-timeout שפג תוקפו יגרמו ליציאה עם קוד שגיאה. הדגל יעיל רק כמידת הדיוק של הבדיקה שמאחוריו, לכן כתוב בדיקת תקינות ש-Compose יכול לסמוך עליה לפני שתסתמך עליה באוטומציה.

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

restart אינה טעינה מחדש (reload). היא עוצרת ומפעילה את אותה מכולה עם התצורה הקיימת שלה, ולכן שינוי במשתנה סביבה, תגית image חדשה או מיפוי פורטים ערוך לא ישפיעו כלל. כדי להחיל שינוי בקובץ עליך להריץ שוב את up -d. Compose משווה כל שירות מול המכולה הרצה שלו ומקים מחדש את אלו שהתצורה או ה-image שלהם השתנו.

החלת שינויים: יצירה מחדש, משיכה או בנייה מחדש

docker compose up -d --force-recreate
docker compose pull && docker compose up -d
docker compose build --no-cache web
docker compose up -d --build web

up -d עושה שימוש חוזר במכולות רצות כאשר התצורה וה־image שלהן לא השתנו; משיכות ובנייה של images מתבצעות בהתאם למדיניות ה־pull של השירות. --force-recreate עוקף את ההשוואה הזו ומחליף כל מכולה גם כאשר התצורה זהה, ולכן זו הדרך המהירה ביותר לנקות מצב (state) לא תקין בתוך המכולה.

תהליך עדכון ה־image המפורש משתמש בשתי פקודות מכיוון שהן מבצעות פעולות שונות. pull מוריד את ה־image העדכני עבור כל תגית המצוינת בקובץ. לאחר מכן, up -d מזהה שמזהה ה־image של השירות אינו תואם עוד למכולה הרצה ויוצר אותה מחדש. עם מדיניות ה־pull המוגדרת כברירת מחדל ב-missing, תגיות השמורות ב-cache עוברות שימוש חוזר, למעט latest, שנמשך תמיד. הסיכון ההפוך מופיע ב-stack מרובה שירותים, שבו משיכת latest עבור כל השירותים בבת אחת עלולה לשבור יישום שעבד עשר שניות קודם לכן; זו הסיבה ש-סביבת עבודה עצמית של AFFiNE ממליצה לקבע (pinning) את היישום ואת ה-image של ה-migration לאותו digest. קיבוע גם הופך שדרוג לעריכה מכוונת של התגית, שלאחריה מתבצעים אותם תהליכי משיכה ויצירה מחדש. ב-stack שמבצע migration למסד הנתונים בזמן העלייה, מומלץ להחזיק dump זמין לפני הרצת כל אחת מהפקודות; זהו הנוהל ש-דלפק תמיכה עצמי של Chatwoot מיישם בכל עדכון גרסה.

build חל על שירותים שמצהירים על סעיף build:, כולל שירותים שמצהירים גם על image:. up -d --build בונה ומפעיל בשלב אחד, וזהו הלופ הרגיל בזמן שינוי קוד. השתמשו ב---no-cache רק כאשר שכבה ב-cache אינה מעודכנת בבירור, מכיוון שהיא בונה מחדש כל שכבה מאפס. פרויקטים מסוימים מספקים את שני הנתיבים מתוך repo משובט אחד, ואז שני הלופים הם נתיבי עדכון חלופיים: מעקב אימונים עצמי של openGym משתמש ב-docker compose up -d --build כדי לבנות את ה-checkout המקובע שלו, מכיוון שמשיכת ה-images מסוג latest שלו עלולה להריץ גרסה חדשה יותר מה-checkout הזה.

צפייה בתהליכים רצים

docker compose ps
docker compose ps -a
docker compose logs -f --tail=100
docker compose logs --since 15m --timestamps db
docker compose top
docker compose ls

ps מציג רק מכולות פעילות. שירות שקרס במהלך העלייה לא יופיע שם עד שתוסיפו את -a, לכן מכולה שחסרה ב-ps בעוד ש-ps -a מציג אותה כ-Exited (1) היא התנהגות תקינה של כשל בעלייה. בדקו את קוד היציאה (exit code), ולאחר מכן קראו את הלוגים.

logs -f עוקב אחר כל השירותים בו-זמנית ומוסיף תחילית של שם השירות לכל שורה; זהו המבט הדרוש כאשר שירותים מתקשרים זה עם זה וסדר האירועים קריטי. ציינו שם של שירות כדי לצמצם את התוצאות. --tail=100 חשוב עבור מכולה שרצה כבר חודש, כיוון שברירת המחדל מדפיסה את כל ההיסטוריה ומציפה את הטרמינל. --since 15m עונה על השאלה הנפוצה ביותר: מה קרה במהלך האתחול שביצעתם זה עתה.

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

קבלת גישה ל-shell בתוך שירות

docker compose exec web sh
docker compose exec -u root web sh
docker compose run --rm web env
docker compose run --rm --no-deps web sh

הפקודה exec מריצה פקודה בתוך מכולה שכבר פועלת. הפקודה run מפעילה מכולה חדשה על בסיס אותה הגדרת שירות, וזהו הפתרון הנדרש כאשר השירות אינו נשאר פעיל מספיק זמן כדי לבצע אליו exec. תמיד יש להשתמש ב-run יחד עם --rm, שכן ללא דגל זה, כל הרצה משאירה אחריה מכולה עצורה, ואלו מצטברות עד ש-docker compose ps -a הופך לבלתי קריא.

נסו את sh לפני bash. חלק מהתמונות המבוססות על Alpine כוללות את bash, כולל התמונה הרשמית של PostgreSQL בגרסת Alpine; כאשר הוא חסר, השגיאה שמתקבלת היא exec: "bash": executable file not found in $PATH. הוספת --no-deps ל-run מדלגת על התלויות של השירות, מה שמונע מבדיקת תצורה מהירה להפעיל את כל מסד הנתונים שלכם.

הפקודה run --rm web env היא הדרך המהירה ביותר לראות את הסביבה שקיבל השירות בפועל, לאחר שכל קובץ .env, בלוק environment: ומשתני ה-shell מוזגו. כאשר ערך מסוים אינו תקין, סדר המיזוג הוא בדרך כלל הסיבה לכך, והקישור כיצד Compose פותר קובצי env וסודות מפרט איזה מקור מקבל עדיפות.

רשתות, פורטים ופתרון שמות

docker compose port web 80
docker compose exec web getent hosts db
docker compose config --networks

כברירת מחדל, Compose מציב כל שירות על רשת פרויקט אחת, וכל שם שירות משמש כשם DNS בתוכה. הרצת getent hosts db בתוך web, כאשר ה-image כולל את getent, בודקת את פתרון השמות; היא אינה בודקת האם db מקבל חיבורים. אם השם מתורגם לכתובת אך החיבור מסורב, בדקו שהשרת רץ ומאזין בכתובת ובפורט המבוקשים; קישור (binding) ל-127.0.0.1 בלבד הוא סיבה אפשרית לכך. אותו גבול מסביר מדוע מכולה שהופעלה מחוץ לפרויקט, בין אם על ידי docker run או כ-stack עצמאי, זקוקה לרשת משותפת כדי לפתור שם שירות כמו jellyfin, וזהו הדבר הראשון שיש לבדוק כאשר ממשק Halcyon עבור ספריית ה-Jellyfin שלכם אינו מצליח להגיע לשרת שאליו הוא מצביע. שאר המודל מוסבר ב-אופן הפעולה של רשתות Compose ו-DNS של שירותים.

port web 80 מדפיס את כתובת המארח והפורט שעליהם פורסם פורט של מכולה, מה שחוסך ניחושים כאשר המיפוי מגיע ממשתנה. פרסום פורט גם כותב חוק firewall ש-Docker מנהל בעצמו, וחוק זה ממוקם לפני החוקים שלכם, כך ששירות שחשבתם שהוא פרטי עלול להיות חשוף לאינטרנט. מקרה זה מכוסה ב-מדוע פורטים של Docker שפורסמו עוקפים את ufw. השארת פורטים אלו ללא פרסום והצבת proxy מאמת על רשת הפרויקט לפני השירותים היא הגישה הבטוחה יותר, וזה מה ש-הרצת Authentik כשכבת הזדהות אחודה מעניקה לכם.

נפחי אחסון ונתונים

docker compose config --volumes
docker compose cp db:/etc/postgresql/pg_hba.conf ./pg_hba.conf
docker compose down -v

config --volumes מציג את הנפחים (volumes) בעלי השם שהוגדרו בפרויקט, אחד בכל שורה. רשימה זו היא רק חלק ממלאי הגיבוי: יש לבדוק גם bind mounts וקובצי תצורה. כאשר הנפחים מכילים מידע שאינו ניתן לשחזור, פקודת הגיבוי המדויקת חשובה לא פחות מהרשימה; זו הסיבה ש-ההשוואה בין PhotoPrism ל-Immich מפרטת את פקודות ה-dump וההעתקה שכל שרת תמונות דורש. cp מעתיק קובץ לתוך מכולה או ממנה החוצה ללא צורך בפתיחת shell, תוך שימוש בתחביר service:path בצד שבו נמצאת המכולה.

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

ניקוי המפנה שטח דיסק מבלי לאבד נתונים

docker compose down --remove-orphans
docker system df
docker image prune -a
docker builder prune

הפקודה --remove-orphans מוחקת מכולות השייכות לפרויקט אך אינן מופיעות עוד בקובץ, וזהו בדיוק המצב שנוצר לאחר שינוי שם של שירות. ללא שימוש בדגל זה, המכולות הללו ימשיכו לרוץ, והפקודה docker compose ps כוללת כברירת מחדל מכולות יתומות שעדיין רצות.

הפקודה docker system df מציגה לאן נעלם שטח הדיסק לפני ביצוע מחיקה כלשהי, ומחלקת את הנתונים לתמונות (images), מכולות, volumes מקומיים ו־build cache, עם נתון על השטח שניתן לפינוי עבור כל קטגוריה. הפקודה image prune -a מסירה כל תמונה שאינה בשימוש על ידי מכולה, בין אם היא מתויגת ובין אם לא; בשרת שהוריד כמה גרסאות של תמונה גדולה, זהו בדרך כלל הצעד המשמעותי ביותר. הפקודה builder prune מסירה כברירת מחדל build cache תלוי (dangling); ניתן להוסיף את -a כדי להסיר את כל ה־build cache שאינו בשימוש.

אף אחת מהפקודות הללו אינה נוגעת ב־named volume. הפקודות docker volume prune --all, docker compose down -v ו־docker volume rm מסירות volumes בעלי שם. הפקודה docker volume prune כשלעצמה מסירה רק volumes אנונימיים.

בדיקת הקובץ לפני גרימת נזק

docker compose config --quiet
docker compose config --services
docker compose --dry-run up -d

config --quiet מבצע ולידציה ולא מדפיס דבר במקרה של הצלחה, לכן הוא מתאים לשלב שלפני הפריסה (pre-deploy) או ל-git hook. הפקודה config מדפיסה את הקובץ הממוזג והמפורש במלואו; זו הדרך לוודא שמשתנה עבר רזולוציה ושהקובץ העוקף (override) הוטמע כפי שציפית. משתנה שלא הוגדר יופיע שם כערך ריק, לצד האזהרה The "X" variable is not set. Defaulting to a blank string..

--dry-run הוא דגל גלובלי ולא דגל של פקודת משנה, לכן הוא מופיע לפני up. הוא מדפיס כל פעולה ש-Compose יבצע מבלי לשנות דבר; מדובר בשלושים שניות שמוטב להשקיע לפני הרצת down על stack קריטי.

עבודה עם קבצים, פרופילים ופרויקטים

docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose --profile debug up -d
docker compose -p staging up -d

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

הדגל --profile מפעיל שירותים שתויגו עם פרופיל זה לצד שירותים ללא תיוג, מה שמאפשר להשאיר כלי ניפוי שגיאות מחוץ ל־up רגיל. הדגל -p מגדיר את שם הפרויקט, כך שניתן להריץ שני עותקים של אותו ה-stack זה לצד זה עם רשתות נפרדות ושמות volume נפרדים. כדי להחזיר את ה-stack לפעולה לאחר אתחול (reboot), יש להשתמש במדיניות הפעלה מחדש (restart policy) או ביחידת שירות שמריצה את Compose עבורכם, כפי שמתואר ב-הפעלת stacks של Compose בעת עליית המערכת.

FAQ

מה החליף את docker-compose עם מקף?

Compose V2 ו-V5, המופעלים כ-docker compose עם רווח. ב-Linux, Compose הוא תוסף המותקן בנפרד; הפצת Ubuntu 24.04 LTS עדיין מציעה את כלי ה-Python בגרסה V1 במאגר ה-universe שלה. אם הפקודה עם הרווח אינה זמינה, הגדירו את המאגר של Docker והתקינו את החבילה docker-compose-plugin. עדכנו סקריפטים ישנים לשימוש בפורמט עם רווח במקום להוסיף alias, כיוון של-V2 יש דגלים שלא היו קיימים ב-V1.

מדוע docker compose restart לא מזהה שינויים בתצורה שלי?

הפקודה restart עוצרת ומפעילה מחדש את הקונטיינר הקיים עם התצורה ששימשה ליצירתו, והיא לעולם לא קוראת מחדש את compose.yaml. כל שינוי במשתני סביבה, פורטים, כרכים (volumes) או תגית ה-image מחייב את docker compose up -d, שמשווה כל שירות מול הקונטיינר הרץ שלו ויוצר מחדש את אלו ששונים. הוסיפו את --force-recreate כאשר ברצונכם שההחלפה תתבצע גם אם לא חל שינוי בקובץ.

כיצד מעדכנים שירות ל-image חדש יותר?

הריצו את docker compose pull, ולאחר מכן את docker compose up -d. ה-pull מושך את ה-image העדכני עבור כל תגית בקובץ, ו-up -d יוצר מחדש כל שירות שמזהה ה-image שלו כבר אינו תואם לזה של הקונטיינר. הרצת up -d לבדה פועלת לפי מדיניות ה-pull: מדיניות ברירת המחדל missing עושה שימוש חוזר ב-images שנשמרו ב-cache, למעט עבור latest, שנמשך תמיד.

אילו פקודות ניקוי בטוחות לשימוש בשרת פעיל?

הפקודה docker system df מציגה את ניצול הדיסק מבלי למחוק דבר; docker image prune -a ו-docker builder prune מסירות images שאינם בשימוש ו-cache של בנייה, כך ששירותים רצים ממשיכים לעבוד וכרכים בעלי שם (named volumes) נותרים ללא שינוי. הצמד המסוכן הוא docker compose down -v, שמוחק את הכרכים בעלי השם שהוגדרו בפרויקט (שאינם חיצוניים) וכרכים אנונימיים מחוברים ללא התראה, ו-docker volume prune --all, שמוחק כרכים מקומיים שאינם בשימוש, כולל כאלו בעלי שם, לאחר אישור y/N בודד, או ללא אישור כלל עם -f. הריצו את docker compose config --volumes תחילה כדי לדעת מה נמצא בסיכון.

האם ניתן להריץ פקודה אחת מבלי להפעיל את כל ה-stack?

כן. docker compose run --rm --no-deps web sh מפעילה קונטיינר בודד מתוך הגדרת השירות web, מדלגת על התלויות שלו, ומסירה את הקונטיינר ביציאה. השתמשו ב-exec במקום זאת כאשר הקונטיינר כבר רץ, כיוון ש-exec מריצה את הפקודה שלכם בתוך הקונטיינר החי ומציגה לכם את המצב שבו השירות נמצא בפועל.

האם המאמר הזה היה מועיל?