2 שלב הבסיס

התקנה והרצה ראשונה — Desktop, ה-CLI, וה-container הראשון שלך

עד עכשיו הכל היה תיאוריה: image זה מתכון, container זה מנה רצה, registry זה מחסן. בפרק הזה אנחנו יורדים לקרקע. תוך 30-40 דקות תעברו ממחשב נקי ל-container אמיתי שמגיש דף ב-browser שלכם, תכירו את 6 הפקודות היומיומיות שמכסות 90% מהעבודה, ותפתרו את המיתוס ש-Docker זה כלי יקר או מסובך. אם אתם על Windows — נדבר על WSL2, אם אתם על Mac — נדבר על OrbStack כאופציה קלה יותר. בסוף הפרק תהיה לכם שליטה אמיתית בפקודה docker run, וזה כל מה שצריך כדי להמשיך לפרק 3.

מה תוכלו לעשות אחרי הפרק הזה
לפני שמתחילים

הפרק הזה הוא הסף המעשי של הקורס. אחרי שתסיימו אותו, "רץ אצלי במחשב" יהפוך ל"רץ גם אצלי במחשב, בלי שאני אכתוב שורת קוד". בפרק 3 כבר נארוז את האפליקציה שלכם לתוך image, ובפרק 6 נעלה אותו לשרת אמיתי. אבל הבסיס מתחיל כאן, בפקודה אחת של docker run.

מתחיל 7 דקות התקנה Windows

התקנה על Windows — Docker Desktop דרך WSL2

על Windows, Docker Desktop לא רץ ישירות על הקרנל של Windows. הוא רץ בתוך מכונה וירטואלית קטנה שמבוססת על WSL2 (Windows Subsystem for Linux, גרסה 2) — שזה בעצם kernel של לינוקס אמיתי שמיקרוסופט בנו, ומשתלב בחלונות. למה זה חשוב? כי containers מעצם הגדרתם צריכים kernel של לינוקס (או Windows containers, אבל זה סיפור אחר לגמרי). בלי WSL2, Docker Desktop היה צריך להריץ VM כבד — איטי, זולל זיכרון, וחוסם אתכם מלהריץ קוד לינוקסאי מקומי. עם WSL2, ה-container שלכם רץ באותה סביבה שבה הוא היה רץ על שרת אמיתי, ואתם מקבלים ביצועים טובים בהרבה.

שלב 1: לוודא ש-WSL2 מותקן ומעודכן

ב-Windows 10/11 המודרני, WSL2 כבר מותקן, אבל לא תמיד בגרסה האחרונה. Docker Desktop דורש WSL בגרסה 2.1.5 ומעלה (עדיף עדכני). פתחו PowerShell או Terminal של Windows כמנהל (Run as Administrator) והריצו:

wsl --version
wsl --update

הפלט הראשון יראה לכם את הגרסה הנוכחית (למשל, "WSL version: 2.3.26.0"). השני יוריד ויתקין את הגרסה האחרונה. אחרי עדכון, הפעילו מחדש את Windows — לא מוותרים על זה. WSL2 הוא רכיב kernel; שינויים בו דורשים אתחול.

ודאו שהפצת לינוקס ברירת-מחדל מוגדרת ל-WSL2:

wsl --set-default-version 2
wsl --list --verbose

הפלט צריך להראות את ההפצה שלכם (Ubuntu היא ברירת המחדל) עם עמודת "VERSION" שמכילה "2". אם מופיע "1" — המירו עם wsl --set-version <DistroName> 2 (למשל, wsl --set-version Ubuntu 2).

שלב 2: הורדה והתקנה של Docker Desktop

היכנסו ל-docker.com/products/docker-desktop ולחצו "Download for Windows". הקובץ הוא Docker Desktop Installer.exe, שוקל כ-1.2 GB. הריצו אותו. ההתקנה לוקחת 2-5 דקות ותבקש מכם לסגור את כל החלונות הפתוחים בסוף (זה תוקף רכיבי מערכת, לא רק קבצים רגילים).

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

שלב 3: ההגדרות הראשונות ב-Docker Desktop

אחרי ההפעלה מחדש, Docker Desktop יפתח אוטומטית. בהפעלה הראשונה הוא יבקש:

תחת Settings → Resources → WSL Integration, ודאו שההפצה שלכם מסומנת. זה מה שמאפשר לכם להריץ docker מתוך ה-terminal של ההפצה (Ubuntu) בלי קונפיגורציה נוספת.

שלב 4: אימות ראשון

פתחו את ה-terminal של אובונטו (או PowerShell, אם הוספתם את Docker CLI ל-PATH), והריצו:

docker --version
docker run hello-world

הפלט הראשון יראה משהו כמו Docker version 27.x.x, build xxxxx — זה אומר שה-CLI מותקן. הפקודה השנייה תוריד image קטן בשם hello-world מ-Docker Hub, תריץ אותו, ותדפיס הודעת הצלחה. אם אתם רואים "Hello from Docker!" — סיימתם. המערכת שלכם מוכנה.

Do Now — 3 דקות (אימות התקנה)

אם עוד לא התקנתם: פתחו docker.com/products/docker-desktop, הורידו את הגרסה ל-OS שלכם, והתקינו. אם כבר התקנתם: פתחו terminal והריצו docker run hello-world. תוצאה צפויה: הודעה שמתחילה ב-"Hello from Docker!" ומסבירה בכמה משפטים מה קרה (Docker יצר קשר עם ה-daemon, משך את ה-image, הריץ אותו, והדפיס). אם אתם רואים את ההודעה — Docker מותקן ופועל. אם לא — חיזרו לסעיף הרלוונטי.

מתחיל 4 דקות מלכודת ביצועים

מלכודת מיקום הקבצים ב-WSL2 — לאן לשמור את הפרויקט

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

שתי מערכות קבצים, שתי ביצועים

ב-WSL2 יש שתי מערכות קבצים:

כשאתם עורכים קבצים בפרויקט שמקושר מ-WSL ל-Windows (למשל, פתחתם VSCode על C:\Users\me\myapp ומריצים docker build מתוך WSL שמסתכל על /mnt/c/Users/me/myapp), כל קריאה/כתיבה צריכה לעבור דרך גשר בין שתי מערכות הקבצים. זה מאוד איטי — במיוחד עבור file watching (המנגנון שבודק "האם קובץ השתנה?"). זה גם יוצר race conditions משונים שקשה לאבחן.

הכלל הפשוט

שמרו את קבצי הפרויקט בתוך מערכת הקבצים של לינוקס ב-WSL2, לא על C:. כלומר, עבדו עם ~/projects/myapp (או כל תיקייה בתוך ה-home של המשתמש באובונטו), ולא עם C:\Users\me\projects\myapp.

הדרך המעשית:

  1. פתחו את terminal של אובונטו.
  2. צרו תיקייה: mkdir -p ~/projects/myapp && cd ~/projects/myapp.
  3. את קוד הפרויקט שלכם — העתיקו לכאן (או git clone <url>).
  4. פתחו את VSCode דרך WSL: code . (הפקודה code מותקנת אוטומטית עם הרחבת "Remote - WSL" של VSCode).
  5. הריצו docker build ו-docker run מה-terminal של אובונטו. הכל ירוץ במהירות מלאה.

אבל אני רגיל לעבוד ב-C:

אם אתם חייבים לעבוד ב-C: (למשל, הפרויקט מסונכרן עם OneDrive, או יש לכם סקריפטים שמתעדכנים מ-Windows), עדיין אפשר — פשוט צפו לביצועים נמוכים יותר. ה-build יעבוד, ה-image ייווצר, ה-container ירוץ, אבל הזמן יהיה ארוך פי 5-10. ברגע שתרגישו "Docker זה איטי", תדעו לבדוק קודם את מיקום הקבצים — וברוב המקרים זה יפתור את התלונה.

Do Now — 2 דקות (מיקום הקבצים)

אם אתם על Windows, פתחו את terminal של אובונטו והריצו pwd. אם התשובה היא משהו כמו /home/yourname או /home/yourname/projects/myapp — אתם במקום הנכון. אם התשובה היא /mnt/c/Users/... — אתם עובדים מכונן C, וכדאי להזיז את הפרויקט לתוך ~/ לפני שממשיכים. תוצאה צפויה: נתיב שמתחיל ב-/home/ או /root/ בתוך WSL.

מתחיל 5 דקות התקנה Mac

התקנה על Mac — Docker Desktop והחלופות הקלות

על Mac ההתקנה פשוטה יותר, כי macOS מבוסס על Unix ו-Docker Desktop רץ בתוך VM קל (המקבילה ל-WSL2 ב-Windows, אבל אפשר להתקין אותו בלי להפעיל שום רכיב מערכת).

אפשרות 1: Docker Desktop (הברירה הסטנדרטית)

הורידו מ-docker.com/products/docker-desktop את הגרסה ל-Apple Silicon (M1/M2/M3/M4) או Intel, תלוי בדגם שלכם. תבדקו ב-"About This Mac" → "Chip" אם אתם לא בטוחים. רוב המקינטושים מ-2021 ואילך הם Apple Silicon.

ההתקנה: גררו את Docker.app ל-Applications. בהרצה הראשונה macOS יבקש אישור לגישה לרשת (אשרו), ו-Docker Desktop יציג את ה-Service Agreement. קחו כוס קפה — ההורדה הראשונית של ה-runtime כברידה אולי 1-2 דקות.

אחרי ש-Docker Desktop רץ (תראו אייקון של לוויתן בתפריט העליון), פתחו Terminal והריצו docker --version ו-docker run hello-world. אם ההודעה המוכרת מופיעה — סיימתם.

אפשרות 2: OrbStack — חלופה קלה ומהירה יותר

OrbStack הוא כלי שעושה בדיוק את אותו דבר כמו Docker Desktop (GUI + CLI + container engine), אבל עם שתי יתרונות משמעותיים למקינטוש:

התקנה: הורידו מ-orbstack.dev, גררו ל-Applications, הריצו. ה-CLI של OrbStack מתחזה בתור docker — כלומר, אחרי ההתקנה, docker run nginx עובד בדיוק אותו דבר. אין צורך לשנות שום סקריפט.

OrbStack הוא חינמי לשימוש אישי. לעסקים יש רישיון בתשלום, אבל ל-Vibe Coder סולו הוא בחינם.

אפשרות 3: Rancher Desktop (חינמי לכל שימוש מסחרי)

אם אתם עובדים בחברה שעוברת את הסף של Docker Desktop (250 עובדים או $10M הכנסה — נדבר על זה בסעיף הבא), Rancher Desktop של SUSE הוא תחליף מלא שתמיד חינמי, גם לשימוש מסחרי (רישיון Apache-2.0). הוא גם מגיע עם k3s (קוברנטיס קל) בנוסף ל-Docker Engine, אבל לא חייבים להשתמש בזה.

הורידו מ-rancherdesktop.io. ה-CLI שלו גם מתחזה בתור docker, כך שהפקודות בפרק הזה עובדות בדיוק אותו דבר.

אז מה לבחור?

המלצה מעשית: Docker Desktop הוא הבחירה הבטוחה ל-Vibe Coder סולו. הוא חינמי, הוא רשמי, התיעוד של Docker מתייחס אליו ישירות. התקינו אותו, המשיכו הלאה. OrbStack — אם המק שלכם חזק אבל הזיכרון צמוד, או אם אתם מתעצבנים מ-5 שניות boot. Rancher Desktop — אם המעסיק שלכם ביקש רישיון מסחרי.

Do Now — 2 דקות (בחירת כלי)

החליטו: Docker Desktop (ברירת מחדל), OrbStack (Mac, רוצים מהירות), או Rancher Desktop (צרכים מסחריים). התקינו, הריצו docker run hello-world. תוצאה צפויה: ההודעה המוכרת של Hello from Docker! — בלי קשר לאיזה כלי בחרתם.

מתחיל 4 דקות עלות רישוי

מיתוס העלות — מתי Docker Desktop חינמי ומתי לא

אחת השאלות שאני שומע הכי הרבה: "אבל Docker Desktop עולה כסף, נכון?" התשובה הקצרה: לא, לא בשבילכם. התשובה הארוכה דורשת להבין את הסף הרשמי.

הסף הרשמי (נכון ל-2026)

לפי docs.docker.com/subscription/desktop-license, Docker Desktop חינמי עבור:

הקריטי כאן הוא ה-וגם. אם לחברה שלכם יש 200 עובדים אבל $20M הכנסה — אתם מעל הסף, וצריך רישיון. אם יש 300 עובדים אבל $5M — גם מעל הסף. רק עסקים שמתחת לשתי הספים ביחד זכאים לחינם.

מה עולה וכמה

התוכניות המסחריות (מחירים ל-2026, לחודש, חיוב חודשי — שנתי זול יותר):

תוכנית מחיר למי מתאים
Personal חינם שימוש אישי, חינוך, open source
Pro $11 למשתמש לחודש פרילנסרים, סטארטאפים מעל הסף
Team $16 למשתמש לחודש צוותים קטנים, מעל הסף
Business $24 למשתמש לחודש ארגונים, governance ו-SSO

מה עם Vibe Coder סולו?

המצב הרגיל שלכם: אתם אדם אחד, אולי עם עוד חבר או שניים שעובדים אתכם. אתם רחוקים מאוד מ-250 עובדים, והכנסה של $10M שנתית זו חלום רחוק לרוב הפרויקטים האישיים. ברירת המחדל שלכם: Docker Desktop חינמי.

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

Docker Engine (בלי Desktop) הוא OSS תמיד

חשוב להפריד: Docker Engine (ה-daemon שמריץ containers, dockerd) הוא קוד פתוח תמיד, בנפרד מ-Docker Desktop. על Linux, אתם מתקינים רק את Docker Engine וזהו — חינמי לכל שימוש, תמיד. הרישוי של Docker Desktop קיים רק על המוצר הספציפי הזה (האפליקציה הגרפית ל-Windows/Mac).

בקיצור: ה-Vibe Coder הישראלי הממוצע לא ישלם על Docker לעולם. המיתוס ש-"Docker זה כלי יקר" הוא בעיקר חוסר היכרות עם הסף.

Framework — "האם Docker Desktop חינמי בשבילי?"

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

  1. האם אני משתמש ב-Docker לפרויקט אישי, חינוך, או open source לא-מסחרי?
    • כן → חינמי. התקינו Docker Desktop והמשיכו.
    • לא → עברו לשאלה 2.
  2. האם החברה שלי (או הסטארטאפ שלי) מתחת ל-250 עובדים וגם מתחת ל-$10M הכנסה שנתית?
    • כן לשניהם → חינמי. עומדים בסף המסחרי.
    • לא לפחות לאחד → עברו לשאלה 3.
  3. האם המעסיק שלי מוכן לשלם רישיון Pro/Team/Business?
    • כן → Docker Desktop בתשלום. תשלום של המעסיק, לא שלכם.
    • לא → התקינו Rancher Desktop (חינמי לכל שימוש מסחרי, Apache-2.0). הפקודות זהות, ה-CLI זהה.

איך להשתמש ב-Framework: ענו על השאלות בראש לפני ההתקנה. ב-95% מהמקרים של Vibe Coder סולו או סטארטאפ קטן, התשובה תהיה "חינמי" — והחלק הזה של הדאגה ייעלם.

מתחיל 3 דקות ניצחון ראשון CLI

הניצחון המיידי — docker run hello-world

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

מה קורה שלב אחר שלב

כשאתם מריצים docker run hello-world בפעם הראשונה, מאחורי הקלעים קורים ארבעה דברים:

  1. Docker בודק אם ה-image hello-world קיים מקומית. הוא לא (אין לכם image כזה במחשב), אז Docker ממשיך לשלב הבא.
  2. Docker פונה ל-Docker Hub (registry ציבורי ברירת מחדל) ומוריד את ה-image. הוא שוקל 13 KB — זה image של "Hello World" שעושה כלום חוץ מלהדפיס הודעה. ההורדה לוקחת פחות משנייה.
  3. Docker יוצר container מה-image ומריץ את הפקודה הראשית שלו (במקרה הזה, סקריפט שמדפיס את ההודעה).
  4. ה-container מסיים את עבודתו ויוצא. ה-image נשאר במחשב שלכם, מוכן לריצה חוזרת בלי הורדה.

הפלט אמור להיראות בערך כך:

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

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

אם אתם רואים את ההודעה הזו, זה אומר ש-4 דברים עובדים אצלכם במקביל:

  1. ה-CLI של Docker תקין — הפקודה זוהתה.
  2. ה-Docker daemon (השרת הפנימי) רץ — יש לכם "מנוע" שמריץ containers.
  3. הרשת שלכם פתוחה ל-Docker Hub — הורדה עברה.
  4. ה-registry פתוח — Docker Hub הגיב.

אם משהו נשבר, ההודעת השגיאה תספר לכם איפה. "Cannot connect to Docker daemon" → ה-daemon לא רץ, צריך להפעיל את Docker Desktop. "Timeout pulling image" → בעיית רשת, צריך לבדוק proxy או חומת אש. "Permission denied" → בלינוקס, צריך להוסיף את המשתמש לקבוצת docker.

Do Now — 2 דקות (הריצה הראשונה)

הריצו docker run hello-world ב-terminal. תוצאה צפויה: הודעה שמתחילה ב-"Hello from Docker!" ומסבירה את 4 השלבים ש-Docker עשה. אם קיבלתם את זה — אתם ב-1% הראשון של הקורס. אם קיבלתם שגיאה, חזרו לסעיף 1 או 3 לפי ה-OS שלכם.

מתחיל 5 דקות container אמיתי browser

ה-container הראשון שלכם — nginx עם port mapping

עכשיו, אחרי שה"Hello World" עבר, הגיע הזמן להריץ משהו אמיתי. לא סקריפט שמדפיס הודעה, אלא שרת web שמגיש דף אמיתי ב-browser. ה-image הזה נקרא nginx (מבוטא "engine-x") — שרת HTTP פופולרי שמשרת כ-30% מהאתרים בעולם.

הפקודה

docker run -p 8080:80 nginx

זה הכל. פקודה אחת. הפלט יראה הורדה של ה-image (כ-50 MB, לוקח 5-20 שניות תלוי ברשת), ואז הודעות של nginx שמתחיל לרוץ. ה-container לא יוצא — הוא ממשיך לרוץ ב-foreground, מדפיס לכם logs של בקשות HTTP. זה הסימן שהוא חי.

עכשיו: פתחו browser (Chrome, Firefox, Safari — מה שבא לכם), ובשורת הכתובת הקלידו:

http://localhost:8080

אם אתם רואים את הדף המפורסם של nginx ("Welcome to nginx!"), זה הרגע שבו הבנתם את Docker. הרצתם שרת web אמיתי, בלי להתקין שום דבר על המחשב שלכם, בלי להגדיר אף קובץ קונפיגורציה, בלי לפתוח פורט ב-firewall של המערכת. הכל קרה בתוך container סגור, מבודד מהמערכת שלכם.

למה -p 8080:80?

הפלאג -p הוא port mapping — זה החלק הכי חשוב בפרק הזה, ונחזור אליו בסעיף נפרד. בקצרה: ה-container של nginx מאזין על פורט 80 בתוך עצמו (כי כל שרת HTTP ברירת-מחדל). המכונה שלכם לא יכולה לגעת בפורט הזה ישירות — ה-container הוא מכונה וירטואלית מבודדת. -p 8080:80 אומר ל-Docker: "כל בקשה שמגיעה לפורט 8080 אצלי, תעביר לפורט 80 בתוך ה-container."

ה-8080 הוא הפורט הציבורי שלכם (אתם בחרתם 8080 כי הוא פנוי, וכי הוא לא דורש הרשאות admin ברוב המערכות). ה-80 הוא הפורט הפנימי של ה-container. שמאל=המארח שלכם, ימין=ה-container. נחזור לזה בהרחבה.

מה עכשיו?

ה-container רץ ב-foreground ב-terminal. כדי לעצור אותו: Ctrl+C בחלון ה-terminal. ה-container ייסגר, אבל ה-image יישאר במחשב. אם תריצו שוב את אותה פקודה, הורדה לא תקרה — ה-image כבר שם.

אם תרצו להריץ את ה-container ברקע (לא תופס את ה-terminal), הוסיפו -d (detached):

docker run -d -p 8080:80 nginx

הפלט יהיה מחרוזת ארוכה — זה ה-container ID. השתמשו בו כדי לעצור את ה-container: docker stop <container-id>. נלמד את זה בסעיף הבא.

Do Now — 5 דקות (ה-container הראשון ב-browser)

הריצו docker run -d -p 8080:80 nginx (ה--d שולח את ה-container לרקע ומחזיר לכם את ה-ID). פתחו http://localhost:8080 ב-browser. תוצאה צפויה: דף ה-Welcome של nginx. אם אתם רואים את זה — הכל עובד. אם לא — חזרו לסעיף על port mapping.

מתחיל 10 דקות CLI יומיומי כלים

6 הפעלים היומיומיים — run, ps, logs, stop, rm, exec

יש ~70 פקודות Docker שונות, אבל בפועל 6 פקודות מכסות 90% מהצרכים שלכם. הכירו אותן, השתמשו בהן, ותוכלו להריץ כל container שתרצו. נעבור עליהן אחת-אחת, בדיוק בסדר שבו תשתמשו בהן ביום עבודה רגיל.

1. docker run — להריץ container מ-image

כבר הכרתם: docker run -p 8080:80 nginx. הפקודה הזו עושה 4 דברים ברגע אחד:

הפלאגים הכי שימושיים:

2. docker ps ו-docker ps -a — מי רץ, מי עצר

docker ps מציג את ה-containers שרצים עכשיו. הפלט הוא טבלה עם 7 עמודות:

CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                  NAMES
a1b2c3d4e5f6   nginx     "/docker-entrypoint.…"   2 minutes ago   Up 2 minutes   0.0.0.0:8080->80/tcp   wonderful_elion

הסבר על העמודות:

docker ps -a (הדגל -a = all) מציג גם containers שעצרו. זה הכלי הראשון שתריצו כשמשהו "נעלם" — הוא יגיד לכם "Exited (0)" (יצא תקין) או "Exited (1)" (קרס עם שגיאה).

3. docker logs <id-or-name> — מה ה-container אומר

כש-container רץ ברקע (-d), אתם לא רואים את הפלט שלו. docker logs מציג אותו: כל שורה שה-container הדפיס ל-stdout/stderr.

docker logs a1b2c3d4e5f6

פלאגים שימושיים:

טיפ: אם container קרס ואתם רואים "Exited (1)", docker logs הוא הצעד הראשון שלכם. ברוב המקרים הודעת השגיאה האמיתית נמצאת שם.

4. docker stop <id-or-name> — לעצור בנימוס

docker stop שולח SIGTERM ל-container, נותן לו 10 שניות לסיים בנימוס, ואז שולח SIGKILL אם הוא לא מסיים. זו הדרך הנכונה לעצור container.

docker stop a1b2c3d4e5f6

אפשר לעצור כמה containers בבת אחת:

docker stop a1b2c3d4e5f6 f6e5d4c3b2a1 wonderful_elion

5. docker rm <id-or-name> — למחוק container שעצר

container שעצר לא נמחק אוטומטית. הוא נשאר ברשימה של docker ps -a, תופס מקום בדיסק, ומבלבל אתכם. docker rm מוחק אותו סופית.

docker rm a1b2c3d4e5f6

כדי למחוק את כל ה-containers שעצרו בבת אחת:

docker container prune

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

חשוב: docker rm מוחק container. docker rmi (עם i של image) מוחק image. אל תבלבלו. זו אחת הטעויות הכי שכיחות של מתחילים.

6. docker exec -it <id-or-name> sh — להיכנס פנימה

זו הפקודה הכי כיפית והכי מפחידה בו-זמנית. היא פותחת shell בתוך container רץ. אתם בתוך ה-container כאילו אתם SSH-ים לתוך מכונה קטנה.

docker exec -it a1b2c3d4e5f6 sh

הפירוט: -i = interactive (קלט מהמקלדת), -t = tty (terminal אמיתי), sh = ה-shell שתריצו. בתוך רוב ה-images (כולל nginx) זה shell קל (sh, לא bash). לצאת: exit או Ctrl+D.

למה זה שימושי? כי container הוא "קופסה שחורה" מבחוץ. docker exec מאפשר לכם:

אזהרה: שינויים שתעשו בתוך ה-container (עריכת קובץ, התקנת חבילה) יימחקו כשה-container ייעצר. ה-container הוא disposable — לא לערוך בפנים, אלא לתקן ב-image. נחזור לזה בפרק 4.

Do Now — 8 דקות (תרגול 6 הפעלים)

הריצו את 6 הפעלים ברצף, בדיוק בסדר הזה:

  1. docker run -d --name mynginx -p 8080:80 nginx — הריצו nginx ברקע, עם שם שתזכרו.
  2. docker ps — ראו שהוא רץ, שימו לב לעמודה PORTS.
  3. docker logs mynginx — ראו את הלוג של nginx.
  4. docker exec -it mynginx sh — נכנסתם פנימה? הריצו ls /usr/share/nginx/html ותראו את index.html של nginx. exit לצאת.
  5. docker stop mynginx — עצרתם אותו.
  6. docker rm mynginx — מחקתם אותו.

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

מתחיל 6 דקות networking

port mapping מפוענח — host:container

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

הרעיון: שתי מכונות, שני עולמות

container הוא כמו מכונה קטנה שרצה בתוך המחשב שלכם. היא:

-p הוא ה"גשר". הוא אומר ל-Docker: "תאזין בפורט 8080 אצלי במכונה האמיתית. כל בקשה שתגיע לשם — תעביר לפורט 80 בתוך ה-container."

התחביר: host:container

תמיד שמאל=מארח, ימין=container. זה החוק היחיד שצריך לזכור.

למה הכיוון מבלבל?

כי רוב האנשים חושבים "אני רוצה לחשוף את 80 של ה-container" — אז הם כותבים -p 80:something בלי לחשוב. אבל האסימטריה ברורה אם חושבים על זה ככה: ה-container כבר מאזין על 80 בפנים. השאלה היא איזה פורט במכונה שלי יחשוף אותו.

עוד דרך לחשוב על זה: -p הוא כמו מתאם לחשמל בנסיעה לחו"ל. ה-container זה המכשיר שלכם (תקע אירופאי, רץ על 220V). המארח זה הקיר המקומי (תקע אמריקאי, 110V). ה--p הוא המתאם: "תקע אמריקאי → תקע אירופאי". הוא לא משנה את המכשיר; הוא מאפשר לו לדבר עם הקיר.

מה קורה אם לא כותבים -p?

אם תריצו docker run nginx בלי -p, ה-container ירוץ, יאזין על 80 בתוך עצמו, אבל אף אחד מבחוץ לא יוכל להגיע אליו. זה שימושי לפעמים (למשל, כשה-container מתקשר עם containers אחרים ברשת פנימית), אבל לרוב תרצו גישה מהדפדפן שלכם.

אימות שהמיפוי עובד

הריצו:

docker run -d -p 8080:80 --name web1 nginx
docker ps

בעמודה PORTS תראו: 0.0.0.0:8080->80/tcp. המשמעות: Docker מאזין על 0.0.0.0:8080 (כל הממשקים, פורט 8080) במארח, ומעביר ל-80/tcp ב-container. פתחו http://localhost:8080 — תראו את ה-Welcome של nginx.

עכשיו הריצו:

docker run -d -p 9090:80 --name web2 nginx
docker ps

הוספתם container שני, על פורט שונה במארח (9090 במקום 8080) — אבל אותו פורט ב-container (80). עכשיו http://localhost:9090 יפתח את ה-container השני. שני containers, אותו image, שתי כתובות שונות. זו ההמחשה הכי טובה לכך ש-image ≠ container.

Do Now — 5 דקות (port mapping בפועל)

הריצו:

  1. docker run -d -p 8080:80 --name web1 nginx — בדקו http://localhost:8080, אתם אמורים לראות nginx.
  2. docker run -d -p 9090:80 --name web2 nginx — בדקו http://localhost:9090, אתם אמורים לראות nginx שוב.
  3. docker ps — ראו את שניהם ברשימה, עם PORTS שונים.
  4. docker stop web1 web2 && docker rm web1 web2 — נקו.

תוצאה צפויה: שני containers רצים במקביל, שני דפי nginx זמינים בשני ports שונים. אם אתם רואים את זה — אתם מבינים port mapping.

מתחיל 5 דקות networking מלכודת

מלכודת ה-0.0.0.0 — למה האפליקציה חייבת להאזין נכון

עד עכשיו השתמשנו ב-nginx, שמאזין על 0.0.0.0 כברירת מחדל. אבל כשתריצו את האפליקציה שלכם (Next.js, Flask, FastAPI, Express, Streamlit), אתם עלולים להיתקל בתופעה הזו:

זה הרגע שבו 50% מהמתחילים מוותרים על Docker ומחליטים שזה "לא עובד". הפתרון הוא הבנה של שני כתובות IP.

127.0.0.1 מול 0.0.0.0

שתי הכתובות האלה נראות דומות אבל מתנהגות הפוך:

המלכודת של אפליקציות AI

הרבה אפליקציות ש-AI כותב עובדות בריצה מקומית (npm run dev, flask run, uvicorn app:app). הן לא בנויות להיות בתוך container. הן מאזינות על 127.0.0.1 — כי ל-AI לא אכפת שהאפליקציה תהיה נגישה מבחוץ; הוא רק רוצה שהיא תעבוד על המכונה שלכם.

כשאתם עוטפים את האפליקציה ב-container, ה-127.0.0.1 הופך לבעיה: הוא אומר ל-container "אל תקבל חיבורים מהעולם החיצון" — וזה בדיוק מה שאתם כן רוצים כשאתם משתמשים ב--p.

הפתרון: האזינו על 0.0.0.0

הדרך הנכונה להריץ את האפליקציה שלכם ב-container (או בכל סביבה שרוצה גישה מבחוץ):

אם אתם בונים את האפליקציה שלכם ב-Dockerfile (פרק 3), הפקודה שתרוץ ב-CMD צריכה לכלול את 0.0.0.0. למשל:

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "3000"]

איך לאבחן את הבעיה

אם http://localhost:8080 לא עובד:

  1. docker ps — ה-container רץ?
  2. docker logs <id> — ראו על איזה address הוא מאזין. אם אתם רואים "127.0.0.1" במקום "0.0.0.0", זו הבעיה.
  3. אם זו הבעיה, תקנו את הפקודה שמריצה את האפליקציה (או את ה-Dockerfile בפרק 3).
  4. docker exec -it <id> sh ואז netstat -tlnp (או ss -tlnp) — ראו את כל ה-ports הפתוחים ב-container.

הכלל: ה-container חייב להאזין על 0.0.0.0 כדי ש--p יעבוד. ה--p פותח פורט במארח, אבל אם ה-container לא מאזין על הפורט הנכון בפנים — אין לו לאן להעביר.

מה לגבי EXPOSE?

תראו ב-Dockerfile של images רבים שורה כמו EXPOSE 80 או EXPOSE 3000. זו לא פקודה שמפרסמת את הפורט. זו רק תיעוד. היא אומרת ל-Docker "ה-container הזה מתכוון להאזין על פורט 80", אבל לא עושה כלום ברשת.

כדי שהפורט באמת יהיה נגיש מבחוץ, אתם תמיד צריכים -p host:container ב-docker run, או ports: ב-compose (פרק 5). EXPOSE זה כמו הערה בקוד — מתעדת כוונה, לא מבצעת.

אז אל תסתמכו על EXPOSE. תמיד כתבו -p בפקודה שלכם.

Framework — "למה זה לא עובד?" — סולם 5 השאלות

כש-container לא מגיב ב-browser, עלו בסולם הזה לפי הסדר. כל שלב לוקח 10 שניות ופותר 80% מהבעיות:

  1. האם ה-container רץ? docker ps — אם לא, docker ps -a כדי לראות למה הוא עצר (Exited (1) = קרס).
  2. האם יש לו port mapping? עמודה PORTS צריכה להיות לא ריקה. אם ריקה, הוספתם -p?
  3. מה ה-logs אומרים? docker logs <id>. האם יש שגיאה? האם הוא מאזין על 127.0.0.1 או 0.0.0.0? אם 127 — זו הבעיה.
  4. האם הדפדפן מנסה את הכתובת הנכונה? http://localhost:PORT — שימו לב שה-port הוא ה-host port (שמאל ב--p), לא ה-container port.
  5. האם הכלי (browser, curl, postman) מצליח להגיע? curl http://localhost:8080 מה-terminal עצמו. אם curl עובד אבל הדפדפן לא — בעיה בדפדפן (cache, extension). אם curl נופל — בעיה ב-container.

איך להשתמש ב-Framework: אל תקפצו לשלב 5. עברו שלב-שלב. רוב הבעיות נפתרות בשלב 2-3. אם הגעתם לשלב 5 ועדיין לא עובד, יש בעיה רשת עמוקה יותר (DNS, IPv6, firewall) — וזה כבר סיפור לפרק 6 או לקורס נפרד.

מתחיל 4 דקות תחזוקה

ניקיון וסדר — stop, rm, ps -a

אחרי שעבדתם קצת עם containers, תגלו שנוצר לכם "מחסן" של containers שעצרו, images שלא בשימוש, ו-volumes זמניים. Docker נותן לכם כלים לסדר את זה — אבל חשוב להבין מה כל אחד מוחק, כדי לא למחוק משהו חשוב.

שלוש פקודות הניקיון המרכזיות

docker container prune — מוחק את כל ה-containers העצורים. לא נוגע ברצים, לא נוגע ב-images, לא נוגע ב-volumes. זו הפקודה הבטוחה ביותר להריץ כשאתם רוצים לסדר.

docker image prune — מוחק images שאין להם שום container שמשתמש בהם ("dangling images"). שימושי כש-pull-יתם image חדש עם אותו שם, או כשבניתם image מקומי שכבר לא רלוונטי.

docker system prune — מוחק הכל: containers עצורים, images שלא בשימוש, networks לא בשימוש, ו-build cache. זו פקודה "גרעין" — שימושית אחרי ניסויים רבים, אבל מסוכנת אם לא זוכרים מה היה שם. תמיד תעברו על הפלט לפני שתקישו Y.

פקודת "הכל בבת אחת"

אם אתם רוצים לסגור הכל ולהתחיל מאפס:

docker stop $(docker ps -q)
docker rm $(docker ps -aq)

הסבר: docker ps -q מחזיר רק IDs של containers רצים. docker ps -aq מחזיר IDs של כל ה-containers (כולל עצורים). $(...) מחליף את הרשימה לפקודה. שימו לב: הפקודה השנייה תנסה למחוק גם containers רצים — לכן ה- stop לפני.

מה לא למחוק

volumes (פרק 4). docker volume prune מוחק volumes שאינם בשימוש — כלומר, volumes שאף container לא מצביע עליהם. אם הפעלתם מסד נתונים ב-container, הווליום שלו יישאר גם אחרי docker rm — וזה בכוונה, כי הוא מכיל את הנתונים שלכם. אל תריצו volume prune בלי לבדוק קודם.

images עם tag. docker image prune בלי דגלים ימחק רק dangling images. אם תריצו docker image prune -a — הוא ימחק גם images שיש להם tag אבל אף container לא משתמש בהם כרגע. זה הגיוני לפעמים (אם אתם יודעים שלא תצטרכו אותם), אבל זה גם ימחק לכם את ה-image של nginx שלקח לכם 20 שניות להוריד. היזהרו.

רשימת containers שעצרו

תריצו את זה מדי פעם כדי לראות מה תקוע:

docker ps -a --filter "status=exited"

הפלט יראה לכם רק containers שעצרו. אם יש שם משהו שאתם לא מזהים — זה הזמן לחקור. אם זה ניסוי ישן — docker rm <id> ולהמשיך.

Do Now — 3 דקות (ניקיון)

הריצו docker ps -a --filter "status=exited" כדי לראות מה תקוע אצלכם. אם יש משהו — מחקו אותו עם docker rm <id>. אם ריק — מצוין, התחלתם נקי. תוצאה צפויה: רשימה ריקה או רשימה שמתרוקנת אחרי הפקודה. אל תריצו system prune עדיין — תכירו קודם את הסביבה.

מתחיל 3 דקות אימות

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

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

4 הבדיקות לפני המעבר

  1. Docker Desktop רץ. האייקון של הלוויתן בתפריט (Mac) או ב-system tray (Windows) לא מציג שגיאה. אם הוא אדום/כתום/אפור — לחצו ובדקו מה חסר.
  2. docker --version עובד. פלט כמו Docker version 27.x.x, build xxxxx. אם לא — ה-CLI לא ב-PATH, צריך להפעיל מחדש את ה-terminal.
  3. docker run hello-world עובד. הודעת "Hello from Docker!" מופיעה. זה מאמת שיש לכם engine, רשת, ו-registry.
  4. docker run -p 8080:80 nginx + browser עובדים. ה-Welcome של nginx מופיע ב-localhost:8080. זה מאמת את כל המיומנויות של הפרק: image pull, container run, port mapping, ו-0.0.0.0.

אם כל 4 עובדים — אתם מוכנים לפרק 3. בו נלמד לארוז את האפליקציה שלכם לתוך image, לא רק להריץ images של אחרים.

מה לא צריך לבדוק (עדיין)

אל תבדקו את הדברים האלה בשלב הזה — הם לפרק 3+:

הפרק הזה הוא הבסיס. אם הוא יציב — השאר ייבנה עליו.

Do Now — 5 דקות (4 הבדיקות האחרונות)

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

Framework — "Two States": תחומו את העבודה שלכם

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

הכלל הפשוט: כל פקודה שאתם מריצים — שאלו "אני ב-building או ב-running?" אם אתם ב-building, הקובץ החשוב הוא Dockerfile. אם אתם ב-running, המקור אמת הוא ה-container.

דוגמה:

איך להשתמש ב-Framework: לפני כל פעולה, קבעו את ה-state. זה חוסך לכם חיפושים ארוכים במקום הלא נכון. רוב הבעיות של מתחילים נובעות מלבלבל בין שני ה-states — מנסים לתקן container רץ על-ידי עריכת Dockerfile, או מנסים לאבחן בעיית build בלוגים של container.

תרגיל 1 — יום שלם עם Docker (20 דקות)

המטרה: לעבור את כל 6 הפעלים ברצף, בלי להציץ בסעיף 7. אם אתם צריכים לחזור לסעיף — זה בסדר, המטרה היא לבנות שריר.

מה תעשו:

  1. פתחו terminal נקי (סגרו קודם, פתחו מחדש).
  2. הריצו docker run -d -p 8080:80 --name mysite nginx. אם ה-port תפוס, החליפו ל-8081, 8082 — מה שפנוי.
  3. פתחו http://localhost:8080 ב-browser. ודאו שאתם רואים את nginx.
  4. חיזרו ל-terminal: docker ps. ראו את mysite בטבלה.
  5. docker logs mysite — ראו את ה-logs.
  6. docker exec -it mysite sh — נכנסתם פנימה? הריצו ls /usr/share/nginx/html ואז cat /usr/share/nginx/html/index.html | head -5. תראו את ה-HTML של nginx. exit לצאת.
  7. docker stop mysite.
  8. docker rm mysite.
  9. docker ps -a — רשימה ריקה (או כל מה שלא היה קשור לתרגיל).

תוצאה צפויה: 9 פלטים נקיים אחד אחרי השני, בלי שגיאות. ה-browser מציג את nginx באמצע התרגיל. ה- docker exec מציג את הקבצים של ה-image. בסוף — רק containers זמניים (אם היו) נשארים. אם משהו נשבר — חזרו לסעיף 7 ובדקו איפה.

תרגיל 2 — שני containers, שני ports, שני שרתי web (10 דקות)

המטרה: להוכיח בעיניים ש-image ≠ container. אותו שימוש (הגשת דף), שתי מימושים שונים, שתי כתובות שונות.

מה תעשו:

  1. הריצו docker run -d -p 8080:80 --name nginx1 nginx — nginx על 8080.
  2. הריצו docker run -d -p 9090:80 --name apache1 httpd — Apache (httpd) על 9090. שימו לב: זה image אחר (httpd), אבל גם הוא מאזין על 80 בפנים. ה-port mapping הוא זה שמשתנה.
  3. הריצו docker ps — תראו שני containers ברשימה. שימו לב לעמודה IMAGE: nginx ו-httpd שונים, אבל PORTS: 0.0.0.0:8080->80 ו-0.0.0.0:9090->80 — אותו container port (80), שני host ports שונים.
  4. פתחו http://localhost:8080 — "Welcome to nginx!".
  5. פתחו http://localhost:9090 — "It works!" (של Apache).
  6. בדקו שה-logs נפרדים: docker logs nginx1 מראה רק בקשות ל-nginx, docker logs apache1 מראה רק בקשות ל-Apache.
  7. סיימתם? docker stop nginx1 apache1 && docker rm nginx1 apache1.

תוצאה צפויה: שני דפי HTML שונים בשני tabs של הדפדפן, שני containers רצים במקביל, שני stream-ים של logs. זו הוכחה ויזואלית ש-image הוא ה"מתכון" (כל image מגיש דף אחר), ו-container הוא ה"מנה הרצה" (כל אחד רץ בנפרד). אם אתם רואים את זה — אתם מבינים את ההבחנה.

תרגיל 3 — לתפוס את מלכודת ה-0.0.0.0 בידיים (15 דקות)

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

מה תעשו:

  1. צרו תיקייה זמנית: mkdir ~/docker-0-0-0-0-test && cd ~/docker-0-0-0-0-test.
  2. צרו קובץ app.py עם התוכן הבא (Flask server שמאזין על 127.0.0.1):
    from flask import Flask
    app = Flask(__name__)
    @app.route('/')
    def hello():
        return 'Hello from inside the container!'
    if __name__ == '__main__':
        app.run(host='127.0.0.1', port=3000)
  3. צרו requirements.txt עם שורה אחת: flask==3.0.0.
  4. הריצו:
    docker run -d -p 3000:3000 -v $(pwd):/app -w /app python:3.12-slim sh -c "pip install -q -r requirements.txt && python app.py"
  5. המתינו 5 שניות ואז curl http://localhost:3000 או פתחו ב-browser. מה אתם רואים? "Connection refused" או שגיאה דומה. זו המלכודת.
  6. עצרו ומחקו: docker stop $(docker ps -q) && docker rm $(docker ps -aq).
  7. עכשיו תקנו: שנו את app.py כך שיאזין על 0.0.0.0 במקום 127.0.0.1:
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=3000)
  8. הריצו שוב את אותה פקודה משלב 4.
  9. curl http://localhost:3000 — עכשיו אתם אמורים לראות "Hello from inside the container!".
  10. נקו: docker stop $(docker ps -q) && docker rm $(docker ps -aq).

תוצאה צפויה: בריצה הראשונה — שגיאה. בריצה השנייה (אחרי שינוי ל-0.0.0.0) — הודעת "Hello from inside the container!" ב-browser. זו ההוכחה המעשית: הקוד שלכם חייב להאזין על 0.0.0.0 כדי ש-port mapping יעבוד. אתם תתקלו בזה שוב ושוב, בכל אפליקציה ש-AI יבנה לכם; עכשיו אתם יודעים איך לזהות ולתקן ב-30 שניות.

טעות נפוצה: להפוך את כיוון ה-port mapping ולחשוב ש-Docker לא עובד

זו הטעות הראשונה שתעשו (אם עוד לא עשיתם). אתם כותבים -p 80:8080 כשאתם מתכוונים -p 8080:80. ה-container רץ. docker ps מראה PORTS. אבל localhost:8080 לא עובד. אתם פותחים גוגל, מחפשים "docker not working", ומבלים 20 דקות בפורומים.

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

התיקון: זכרו את הכלל: שמאל=מארח, ימין=container. אם האפליקציה ב-container מאזינת על 3000, אז הפורט הימני חייב להיות 3000. את הפורט השמאלי אתם בוחרים (8080, 9090, 3000 — מה שפנוי). אם אתם לא זוכרים, תחזרו לסעיף 8 ותקראו שוב את הדוגמאות.

טעות נפוצה: להשאיר את האפליקציה מאזינה על 127.0.0.1 ולהסיק ש-port mapping לא עובד

המלכודת הזו עוד יותר מתסכלת מהקודמת, כי היא נראית כאילו הכל בסדר: ה-container רץ, ה-port mapping מוגדר, אבל הדפדפן מציג "Connection refused" או נתקע. רוב האנשים מניחים ש-Docker בעייתי, ומוותרים.

הסיבה האמיתית: האפליקציה שלכם (Next.js, Flask, FastAPI, וכו') מאזינה בריצה מקומית על 127.0.0.1. זה עובד מצוין כשהיא רצה ישירות על המחשב שלכם — ה-browser פונה ל-localhost, האפליקציה עונה מ-localhost, הכל טוב. אבל בתוך container, 127.0.0.1 הוא ה-container עצמו, לא המארח. גם אם -p מעביר את הבקשה נכון, ברגע שהיא מגיעה לפנים — אין process שמקבל אותה.

התיקון: האזינו על 0.0.0.0. לכל framework זה קצת אחרת: flask run --host=0.0.0.0, uvicorn --host 0.0.0.0, next dev -H 0.0.0.0, וכו'. הריצו docker logs <id> כדי לוודא שאתם רואים "0.0.0.0" ולא "127.0.0.1" או "localhost" בפלט. אם רואים 127 — תקנו את הפקודה לפני שממשיכים.

טעות נפוצה: להימנע מ-Docker מחשש שזה עולה כסף

הפחד הזה עוצר אנשים לפני שהם בכלל מתקינים. הם שומעים "Docker Desktop Pro $11 לחודש" ומניחים שזה מה שהם צריכים. אז הם נשארים בלי Docker, מתעצבנים מ-"רץ אצלי במחשב", ומוותרים על deploy.

המציאות: Docker Desktop חינמי לכל Vibe Coder סולו, לכל סטארטאפ קטן, לכל חברה עם פחות מ-250 עובדים וגם פחות מ-$10M הכנסה שנתית. הסף הזה גבוה בהרבה מהמצב הרגיל שלכם. גם אם תגיעו לחברה שמעל הסף, המעסיק ישלם (או שתתקינו Rancher Desktop, שתמיד חינמי). אין סיבה להימנע מ-Docker בגלל עלות.

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

Work Routine — שגרת Foundation Phase (פרק 2)

יומי (10 דקות, 14 ימים ראשונים):

שבועי (20 דקות, יום ראשון): חזרה על הבדל בין image ל-container. רוצו 3 images שונים מ-Docker Hub (nginx, httpd (Apache), caddy) — כולם שרתי web — וראו את 3 הדפים השונים. זה מחזק את ההבנה ש-image ≠ container: אותו שימוש (הגשת דף), 3 מימושים שונים, אותה צורת עבודה.

לפני פרק 3 (סוף שבוע שני): ודאו ש-4 הבדיקות מסעיף 11 עוברות: Docker Desktop רץ, --version עובד, hello-world עובד, nginx ב-browser עובד. אם משהו נשבר, תקנו עכשיו. בפרק 3 נתחיל לבנות image של האפליקציה שלכם, ואתם צריכים סביבה יציבה.

ברגע שתסיימו את הפרק הזה — אתם מוכנים לפרק 3. המעבר הוא מ-"להריץ images של אחרים" ל-"לבנות image משלי". זה הצעד הגדול הראשון בקורס. אל תקפצו — ודאו ש-6 הפעלים ו-port mapping יציבים בראש לפני שממשיכים.

סיכום הפרק — 7 לקחים שייקחו אתכם הלאה
  1. ההתקנה של Docker שונה בין Windows ל-Mac, אבל התוצאה זהה. ב-Windows: Docker Desktop דרך WSL2 (kernel לינוקס אמיתי, גרסה 2.1.5+). ב-Mac: Docker Desktop, OrbStack (קל יותר), או Rancher Desktop (חינמי מסחרי). בשני המקרים, docker run hello-world מאמת שהכל עובד.
  2. ב-WSL2, שמרו קבצים בתוך ~/ (Linux filesystem), לא ב-C:. קבצים על C: שעוברים mount לתוך WSL גורמים לבנייה ול-file watching איטיים פי 5-10. הכלל: pwd צריך להתחיל ב-/home/ או /root/.
  3. Docker Desktop חינמי ל-Vibe Coder סולו. הסף הרשמי: פחות מ-250 עובדים וגם פחות מ-$10M הכנסה שנתית. Vibe Coder סולו, פרילנסר, וסטארטאפ קטן נופלים הרבה מתחת לסף. המיתוס "Docker זה כלי יקר" פשוט לא נכון לרוב המוחלט של הקורסים.
  4. 6 הפעלים מכסים 90% מהצרכים. run (להריץ), ps/ps -a (לראות מי רץ ומי עצר), logs (לראות פלט), stop (לעצור), rm (למחוק container שעצר), exec -it … sh (להיכנס לפנים). אלה הפקודות שתריצו שוב ושוב — לא 70 הפקודות האחרות.
  5. port mapping: שמאל=מארח, ימין=container. -p 8080:80 אומר "8080 במכונה שלי → 80 בתוך ה-container." הכיוון קבוע. אם התוצאה לא עובדת, בדקו שאתם לא הפכתם.
  6. ה-container חייב להאזין על 0.0.0.0, לא על 127.0.0.1. זו המלכודת הכי שכיחה של אפליקציות AI. הן רצות מקומית על 127.0.0.1, וברגע שעוטפים ב-container הן לא נגישות. הפתרון: --host 0.0.0.0 בכל framework.
  7. EXPOSE זה תיעוד, לא פקודה. EXPOSE 80 ב-Dockerfile לא פותח שום פורט. צריך -p host:container בכל docker run כדי שהפורט באמת יהיה נגיש מבחוץ. EXPOSE רק מתעד כוונה.
Just One Thing — אם תזכרו רק דבר אחד מהפרק הזה

אם תצאו מהפרק הזה עם דבר אחד בראש, שיהיה זה: docker run -p 8080:80 nginx ופתיחת http://localhost:8080 עובדים. זה הוכחה שהמערכת שלכם מוכנה: CLI תקין, engine רץ, רשת פתוחה, registry נגיש, port mapping תקין, ה-container מאזין נכון. כל אחד מ-6 הפעלים הוא כלי; הצירוף שלהם הוא היכולת להריץ כל container בעולם. אם הצלחתם להריץ את nginx ב-browser — אתם יודעים 80% ממה ש-Vibe Coder צריך לדעת על הרצת containers. ה-20% הנותרים זה אריזה של האפליקציה שלכם (פרק 3) ושמירת נתונים (פרק 4). אבל הבסיס — הרצה, מעקב, אבחון, ניקיון — זה כבר שלכם.

Check Yourself — 5 שאלות הבנה
  1. שאלה: הרצתם docker run -p 3000:80 myapp וה-container רץ, אבל http://localhost:3000 מציג "Connection refused." מה הסיבה הסבירה ביותר, ואיך תאבחנו אותה?
    תשובה: הסיבה הסבירה ביותר: האפליקציה מאזינה בתוך ה-container על port אחר (לא 80), או שהיא מאזינה על 127.0.0.1 במקום 0.0.0.0. האבחון: docker logs <id> — חפשו את השורה שאומרת על איזה host:port היא מאזינה. אם אתם רואים "127.0.0.1" או פורט אחר מ-80, תקנו את הפקודה (להוסיף --host 0.0.0.0 או לתקן את המיפוי ל-port הנכון).
  2. שאלה: אתם על Windows, וה-build של ה-image לוקח 12 דקות במקום דקה. ה-Workspace שלכם נמצא ב-C:\Users\me\projects\myapp. מה הסיבה, ומה הפתרון?
    תשובה: הסיבה: אתם עובדים על C: שמועבר mount לתוך WSL דרך /mnt/c/. כל קריאת קובץ עוברת גשר בין שתי מערכות קבצים, מה שהופך את הבנייה לאיטית פי 5-10. הפתרון: העתיקו את הפרויקט לתוך ~/projects/myapp ב-WSL, פתחו אותו מ-VSCode דרך WSL (code .), והריצו build מה-terminal של אובונטו. הזמן ירד לדקה או פחות.
  3. שאלה: הרצתם docker stop mycontainer, אבל אחר כך docker run mycontainer נותן שגיאה "No such image." למה, ואיך תתקנו?
    תשובה: docker stop עוצר container, לא מוחק image. הבעיה היא ש-mycontainer הוא שם של container, לא של image. docker run mycontainer מחפש image בשם הזה, לא container. התיקון: docker run -p 8080:80 nginx (או שם ה-image האמיתי שלכם). אם אתם רוצים להריץ מחדש את אותו container, תחילה docker start mycontainer (מתחיל אותו מחדש), לא docker run.
  4. שאלה: עמית שלכם עובד בסטארטאפ של 30 אנשים עם $4M הכנסה. הוא שואל אם הוא צריך לשלם על Docker Desktop. מה תענו לו?
    תשובה: לא, הוא לא צריך לשלם. הסף הוא פחות מ-250 עובדים וגם פחות מ-$10M הכנסה — הוא עומד בשניהם. Docker Desktop חינמי. אם יום אחד החברה תגיע ל-260 עובדים, הם יצטרכו להחליט בין Pro ($11/user/mo) לבין Rancher Desktop (חינמי, Apache-2.0).
  5. שאלה: למה EXPOSE 80 ב-Dockerfile לא מספיק כדי שהפורט יהיה נגיש מהדפדפן, ומה עוד צריך?
    תשובה: EXPOSE הוא instruction תיעודי בלבד — הוא אומר ל-Docker "ה-container הזה מתכוון להאזין על 80", אבל לא עושה שום דבר ברשת. כדי שהפורט באמת יהיה נגיש מהמארח, אתם חייבים להעביר -p host:container בפקודת docker run (למשל, docker run -p 8080:80 myapp), או ports: ב-compose. EXPOSE לבדו לא פותח כלום.
מה תפיקו בסוף הפרק
מה הלאה — פרק 3

בפרק 3 (לארוז את האפליקציה — Dockerfile, docker init, ו-images קטנים) נעבור מ-"להריץ images של אחרים" ל-"לבנות image משלי." תכירו את docker init — פקודה שמזהה את השפה של הפרויקט שלכם (Python, Node.js, Go, וכו') ויוצרת Dockerfile אוטומטית, מוכן ל-production. אחר כך תלמדו לקרוא ולתקן את ה-Dockerfile שורה-שורה: FROM (איזה base), WORKDIR (איפה הקוד נמצא), COPY (להעתיק פנימה), RUN (להתקין dependencies), EXPOSE (תיעוד), CMD (מה רץ). תלמדו להקטין את ה-image (base קטן במקום הדביאן המלא), לסדר את השכבות נכון (cache), ולוודא שהאפליקציה שלכם מאזינה על 0.0.0.0. הפרק הזה היה "להריץ"; פרק 3 הוא "לארוז".

Checklist — 12 פריטים לסיום הפרק