דילוג לתוכן
כלי פיתוח

Docker למתחילים: אימג׳, קונטיינר ו־docker compose בלי לבנות הכול מחדש

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

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

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

מה צריך להכין מראש

לפני שמתחילים, צריך התקנה פעילה של Docker במחשב. במערכות Linux ההתקנה נעשית בדרך כלל דרך מנהל החבילות של ההפצה. ב־macOS וב־Windows מקובל להשתמש ב־Docker Desktop. התיעוד הרשמי נקרא Docker Docs, ואפשר למצוא בו הוראות התקנה לפי מערכת הפעלה, אבל כאן לא נקשר החוצה.

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

bash
docker --version
docker compose version

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

  • Linux/macOS: הדוגמאות במאמר כתובות ל־bash.
  • Windows: אפשר להריץ את רוב הפקודות מתוך PowerShell, אבל הדוגמאות עם cat <<EOF מיועדות ל־bash. ב־Windows נוח להשתמש ב־WSL אם עובדים הרבה עם כלי פיתוח.
  • גישה לאינטרנט: בהרצות הראשונות Docker יוריד אימג׳ים מוכנים, למשל python:3.12-alpine או nginx:alpine.

אימג׳ וקונטיינר: ההבדל שבאמת חשוב להבין

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

מושג מה זה אומר בפועל דוגמה
image תבנית מוכנה להרצה: קבצים, תלויות, פקודת התחלה והגדרות. python:3.12-alpine
container מופע רץ או מופסק שנוצר מתוך אימג׳. תהליך פייתון שרץ כרגע מתוך האימג׳.
Dockerfile קובץ הוראות לבניית אימג׳ משלכם. העתקת קובצי פרויקט והגדרת פקודת הרצה.
compose.yaml קובץ שמגדיר שירות אחד או יותר להרצה יחד. אפליקציה, מסד נתונים, שרת סטטי.

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

Docker בפועל: הרצה ראשונה של קונטיינר

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

bash
# Linux/macOS (bash)
docker run --rm python:3.12-alpine python -c "print('hello from docker')"

מה קורה כאן? docker run יוצר קונטיינר מתוך האימג׳ python:3.12-alpine. אם האימג׳ עדיין לא קיים במחשב, Docker יוריד אותו. הדגל --rm אומר להסיר את הקונטיינר אחרי שהוא מסיים לרוץ. הפלט הצפוי הוא:

text
hello from docker

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

בניית אימג׳ משלכם עם Dockerfile

עכשיו נבנה אימג׳ קטן שמכיל קובץ Python משלנו. הדוגמה הבאה יוצרת תיקייה זמנית, כותבת קובץ app.py, כותבת Dockerfile, בונה אימג׳ ומריצה אותו. זו דוגמה מלאה שאפשר להריץ כמו שהיא ב־Linux/macOS עם bash.

python
# Linux/macOS (bash)
set -e

mkdir -p docker-python-demo
cd docker-python-demo

cat > app.py <<'PY'
import platform

def main():
    print("app is running")
    print(f"python version: {platform.python_version()}")

if __name__ == "__main__":
    main()
PY

cat > Dockerfile <<'DOCKER'
FROM python:3.12-alpine
WORKDIR /app
COPY app.py .
CMD ["python", "app.py"]
DOCKER

docker build -t local-python-demo .
docker run --rm local-python-demo

הדוגמה עושה כמה דברים: FROM בוחר אימג׳ בסיס, WORKDIR קובע תיקיית עבודה בתוך הקונטיינר, COPY מעתיק את הקובץ מהמחשב לתוך האימג׳, ו־CMD מגדיר מה יקרה כשמריצים קונטיינר מהאימג׳. הפלט הצפוי ייראה בערך כך, כאשר גרסת פייתון עשויה להשתנות לפי האימג׳:

bash
app is running
python version: 3.12.x

שימו לב לשם האימג׳: local-python-demo. זה שם מקומי בלבד. לא העלינו שום דבר לרישום חיצוני ולא פרסמנו אותו. כדי לראות אימג׳ים מקומיים אפשר להריץ docker images. כדי למחוק את האימג׳ בהמשך אפשר להריץ docker rmi local-python-demo, כל עוד אין קונטיינרים שתלויים בו.

מה באמת קורה בזמן build

כשמריצים docker build, Docker קורא את ההוראות ב־Dockerfile לפי הסדר. כל הוראה יוצרת שכבה. אם מריצים שוב את הבנייה ולא השתנה כלום, Docker יכול להשתמש במטמון במקום לבנות הכול מחדש. זה אחד ההבדלים בין עבודה מסודרת עם Docker לבין התקנה ידנית בתוך מכונה.

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

הרצת שירות עם פורט: שרת HTTP קטן

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

bash
# Linux/macOS (bash)
set -e

docker run -d --rm --name tiny-web -p 8080:8000 python:3.12-alpine python -m http.server 8000

sleep 2
curl http://localhost:8080/

docker stop tiny-web

הדגל -d מריץ את הקונטיינר ברקע. הדגל --name tiny-web נותן לו שם נוח. המיפוי -p 8080:8000 אומר: פורט 8080 במחשב המקומי יפנה לפורט 8000 בתוך הקונטיינר. הפלט מ־curl יהיה רשימת קבצים או דף HTML בסיסי ששרת Python מחזיר עבור תיקיית העבודה שלו. בסוף, docker stop tiny-web עוצר את הקונטיינר, ובגלל --rm הוא גם נמחק.

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

docker compose: כשפקודת run כבר לא מספיק נוחה

docker compose נועד להגדיר הרצה של שירותים בקובץ אחד. גם אם יש רק שירות אחד, Compose יכול להיות נוח כי הוא שומר את כל ההגדרות במקום ברור: שם השירות, אימג׳, פורטים, משתני סביבה, volumes ועוד.

הדוגמה הבאה יוצרת אתר סטטי מינימלי ומריצה אותו דרך Nginx בעזרת compose.yaml. היא מלאה ואפשר להריץ אותה כפי שהיא ב־Linux/macOS עם bash.

bash
# Linux/macOS (bash)
set -e

mkdir -p compose-nginx-demo/site
cd compose-nginx-demo

echo "hello from docker compose" > site/index.html

cat > compose.yaml <<'YAML'
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./site:/usr/share/nginx/html:ro
YAML

docker compose up -d
sleep 2
curl http://localhost:8080/
docker compose down

הקובץ compose.yaml מגדיר שירות בשם web. הוא משתמש באימג׳ nginx:alpine, ממפה את פורט 8080 המקומי לפורט 80 בקונטיינר, ומחבר את התיקייה המקומית site לתיקיית ההגשה של Nginx במצב קריאה בלבד באמצעות :ro. הפלט הצפוי מהפקודה curl הוא:

text
hello from docker compose

הפקודה docker compose up -d מפעילה את השירותים ברקע. הפקודה docker compose down עוצרת ומסירה את הקונטיינרים והרשת ש־Compose יצר עבור הפרויקט. היא לא מוחקת אוטומטית אימג׳ים שהורדו, וזה בדרך כלל טוב: בהרצה הבאה לא צריך להוריד אותם מחדש.

מתי להשתמש ב־Dockerfile ומתי ב־Compose

יש נטייה לחשוב ש־Dockerfile ו־docker compose מתחרים זה בזה. בפועל הם פותרים בעיות שונות.

  • Dockerfile: מגדיר איך לבנות אימג׳ של האפליקציה שלכם.
  • docker build: בונה אימג׳ מתוך Dockerfile.
  • docker run: מריץ קונטיינר אחד, בדרך כלל לפעולה ממוקדת או בדיקה מהירה.
  • compose.yaml: מגדיר איך להריץ שירות אחד או יותר יחד.
  • docker compose up: מפעיל את כל מה שמוגדר בקובץ Compose.

בפרויקט פייתון טיפוסי, למשל, אפשר להחזיק Dockerfile שבונה את האפליקציה, ו־compose.yaml שמריץ אותה עם מסד נתונים מקומי לצורכי פיתוח. אם אתם עוד בשלב לימוד השפה עצמה, מדריך פייתון יכול לעזור להשלים פערים לפני שמוסיפים שכבת קונטיינרים.

פקודות בסיסיות שכדאי לזכור

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

פקודה למה היא משמשת
docker ps מציגה קונטיינרים רצים.
docker ps -a מציגה גם קונטיינרים שכבר נעצרו.
docker logs NAME מציגה לוגים של קונטיינר לפי שם או מזהה.
docker stop NAME עוצרת קונטיינר רץ.
docker rm NAME מוחקת קונטיינר עצור.
docker images מציגה אימג׳ים מקומיים.
docker rmi IMAGE מוחקת אימג׳ מקומי.
docker compose logs מציגה לוגים של שירותי Compose.

טעויות נפוצות והודעות שגיאה אמיתיות

Cannot connect to the Docker daemon

הודעה נפוצה:

text
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

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

port is already allocated

הודעה נפוצה:

output
Error response from daemon: driver failed programming external connectivity on endpoint ... Bind for 0.0.0.0:8080 failed: port is already allocated

המשמעות: כבר יש תהליך אחר שתופס את הפורט המקומי. הפתרון הכי פשוט הוא לבחור פורט אחר בצד שמאל של המיפוי. למשל במקום -p 8080:80 להשתמש ב־-p 8081:80. אם אתם רוצים לדעת מי תופס את הפורט, אפשר לבדוק בכלי מערכת של מערכת ההפעלה, אבל למתחילים לרוב מספיק להחליף פורט.

pull access denied

הודעה נפוצה:

text
pull access denied for local-python-demo, repository does not exist or may require 'docker login'

המשמעות: Docker חיפש אימג׳ בשם הזה ברישום חיצוני כי הוא לא מצא אותו מקומית. בדרך כלל זה קורה כששוכחים לבנות את האימג׳ לפני ההרצה, או כשיש שגיאת כתיב בשם. הפתרון: להריץ שוב docker build -t local-python-demo . מתוך התיקייה שבה נמצא Dockerfile, ואז להריץ docker run --rm local-python-demo.

no configuration file provided

הודעה נפוצה ב־Compose:

text
no configuration file provided: not found

המשמעות: הרצתם docker compose up מתיקייה שאין בה compose.yaml או docker-compose.yml. עברו לתיקייה הנכונה עם cd, או ציינו קובץ במפורש בעזרת -f.

ניקוי סביבת העבודה בלי למחוק בטעות דברים חשובים

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

  • docker container prune מוחקת קונטיינרים עצורים.
  • docker image prune מוחקת אימג׳ים לא בשימוש.
  • docker volume prune מוחקת volumes לא בשימוש — כאן צריך להיזהר במיוחד אם שמרתם נתונים מקומיים.
  • docker system prune מנקה כמה סוגים של משאבים לא בשימוש, אבל כדאי לקרוא את הודעת האישור לפני שמאשרים.

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

שאלות שקוראים באמת שואלים

האם Docker הוא מכונה וירטואלית?

לא בדיוק. קונטיינרים מבודדים תהליכים וסביבת קבצים, אבל בדרך כלל הם קלים יותר ממכונה וירטואלית מלאה. ב־macOS וב־Windows יש שכבת וירטואליזציה מאחורי הקלעים כדי להריץ קונטיינרים של Linux, אבל מבחינת העבודה היומיומית אתם עובדים עם פקודות Docker.

האם צריך Docker כדי ללמוד פייתון, SQL או JavaScript?

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

האם לשמור סיסמאות בתוך Dockerfile?

לא. לא שמים סיסמאות, טוקנים או מפתחות בתוך Dockerfile, בתוך אימג׳, או בתוך קובץ שמעלים למאגר קוד. משתמשים במשתני סביבה, בקבצי הגדרה מקומיים שלא נכנסים ל־Git, או במנגנון ניהול סודות מתאים לסביבה שבה מריצים את המערכת. בדוגמאות לימוד משתמשים תמיד בערכים ברורים כמו PLACEHOLDER_TOKEN, לא בערכים אמיתיים.

סיכום: להתחיל קטן, להבין מה רץ

Docker למתחילים לא צריך להתחיל ממערכות מורכבות. מספיק להבין שאימג׳ הוא תבנית, קונטיינר הוא מופע רץ או עצור, Dockerfile בונה אימג׳, ו־docker compose מארגן הרצה של שירותים בקובץ אחד. משם אפשר להתקדם בהדרגה: פורטים, volumes, משתני סביבה, לוגים וניקוי סביבת עבודה.

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