29/04/2025

מדריך דוקר למתחילים בעברית חלק 5 - איך כותבים DockerFile?


 
אהלן וברוכים הבאים לחלק החמישי במדריך "דוקר למתחילים בעברית"!

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


נבין מה זה Dockerfile ולמה הוא כל כך חשוב, נעבור על כל הפקודות המרכזיות כמו FROM, WORKDIR, COPY, RUN, CMD, EXPOSE ועוד – ונתרגל איך לכתוב קובץ Dockerfile נכון מאפס.


נלמד גם איך לבדוק שהקונטיינר שלנו פועל כמו שצריך עם HEALTHCHECK, איך לבנות אימג'ים בצורה מסודרת עם docker build, ואיך להתעלם מקבצים מיותרים עם .dockerignore כדי לשמור על אימג'ים קטנים ונקיים.


¿?רגע - לפני שאתם ממשיכים קראתם את ארבעת החלקים הראשונים!!!¿?

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

ניתן לעבור על כל החלקים בעמוד המיועד לדוקר בבלוג: מדריך דוקר למתחילים בעברית - כל החלקים




מדריך דוקר למתחילים בעברית חלק 5 – איך כותבים Dockerfile?

1) מה זה Dockerfile ולמה צריך אותו?

2) המבנה הכללי של Dockerfile

3)איך לקבוע את הבסיס שעליו נבנה את האימג' – FROM

4)איך לקבוע את התיקייה שבתוכה ירוצו הפקודות – WORKDIR

5)איך להעתיק קבצים מהמחשב שלנו לתוך האימג'– COPY

6) איך להריץ פקודות במהלך הבנייה של האימג'– RUN

7) איך להגדיר מה הקונטיינר יעשה כשהוא יתחיל לרוץ – CMD

8) איך לציין איזה פורט האפליקציה שלנו תשתמש בו – EXPOSE

9) איך להריץ את הקוד תחת משתמש רגיל ולא תחת Root

10) איך לבדוק אם הקונטיינר באמת חי ופועל כמו שצריך – HEALTHCHECK

11) איך לבנות אימג' בדוקר - Docker Build.

12) איך להתעלם מקבצים\תיקיות בניה של אימג'? - docker ignore

1. מה זה בעצם Docker file ולמה צריך אותו?

1.א. מה זה Docker File?

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

1.ב מה מכיל Docker file?
הקובץ הזה מכיל את הפרטים הבאים (סך הכל יש 17 סעיפים):
  • מאיזה בסיס להתחיל? זאת אומרת על איזו מערכת הפעלה נריץ את הקונטיינר? (למשל: ubuntu, alpine, node, python)

  • אילו קבצים ותיקיות להעתיק פנימה לתוך הקונטיינר?

  • נגיד ויש סקריפטים, אפליקציות, תיקיות קוד – מה צריך להיכנס לתוך ה־Image?

  • אילו פקודות להריץ בתוך הקונטיינר בזמן הבנייה? התקנת תוכנות, יצירת תיקיות, הרשאות, עדכונים וכו’

  • מה להריץ כשהקונטיינר עולה? איזו פקודה צריכה לרוץ אוטומטית כשהקונטיינר מופעל?

  • איזו תיקיית עבודה להגדיר כברירת מחדל בתוך הקונטיינר? איפה תתבצע העבודה? (למשל ‎/app)

  • האם צריך להגדיר יוזר מיוחד להרצה? או שהכול יתבצע כ-root?

  • האם יש משתני סביבה שצריך להגדיר? לדוגמה: ENV NODE_ENV=production

  • האם ליצור רשת חדשה או לחבר לרשת קיימת? תלוי אם אתה רוצה בידוד או אינטגרציה עם קונטיינרים אחרים

  • האם צריך לפתוח פורטים מסוימים? לדוגמה: 80, 443, 3000, 8080 וכו’

  • האם יש Volume שצריך לחבר? כדי שהמידע לא ייעלם כשמכבים את הקונטיינר

  • האם צריך לבדוק שהקונטיינר בריא? באמצעות פקודת HEALTHCHECK לבדיקת תקינות (למשל HTTP 200)

  • האם יש צורך להגדיר איך לעצור את הקונטיינר בצורה נקייה? הגדרת STOPSIGNAL

  • האם להשתמש ב־Shell מיוחד להרצת פקודות RUN? לדוגמה Bash לעומת sh

  • האם צריך להוסיף תיוגים או תיאור (LABEL)? למשל: מחבר, גרסה, תיאור של האימג’

  • האם צריך לבנות את הקובץ עם פרמטרים (ARG)? למשל: גרסה, סוג אפליקציה, שם תיקייה

  • האם צריך להכין פעולות שיתבצעו רק כשמישהו יבנה Image חדש מה־Image הזה? באמצעות ONBUILD


1.ג למה צריך Docker File?


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

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

בנוסף, חשוב להבין:

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

  • בנייה זהה בכל מקום: בזכות Dockerfile, לא משנה איפה מריצים את הבנייה – יוצא בדיוק אותו אימג', בלי הפתעות.

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

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

  • בסיס לעבודה מתקדמת: בעתיד, Dockerfile הופך להיות חלק מפרויקטים יותר גדולים עם Docker Compose,  Kubernetes ועוד. 


(לידע כללי - על Docker compose אנחנו נדבר בחלק 6)

2. המבנה הכללי של Dockerfile

תכלס, הדבר היחיד שחובה כשיוצרים אימג', זה להשתמש רק בפקודה from, שבעצם המשמעות שלה זה "מאיזה סוג של מערכת הפעלה לבנות את האימג'" - יענו מה אתה רוצה להתקין? לאחר מכן אפשר להוסיף עוד דברים (אנחנו נעבור על רוב הדברים שאפשר לשים בקובץ Docker file).

ה docker file נראה ככה:





וזהו, מה שזה יעשה, זה להוריד אימג' מבוסס אובונטו, לאחר מכן יבצע התקנה של דברים: apt update && apt install -y htop, ואז בסוף יריץ את הפקודה htop (מי שלא יודע מה זה, יש לנו הסבר על זה במדריך לינוקס למתחילים: כאן).

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

לכן במקרה שלי יצרתי את התיקיות שאני רוצה בנתיב שאני רוצה, לאחר מכן יצרתי עם nano קובץ בשם Dockerfile, כדי מאוד להשתמש בקובץ עם אות גדולה), קודם כל זה מוסכמות, דבר שני ברגע שכותבים docker build, המערכת אוט' מחפשת את הקובץ Dockerfile עם אות גדולה, וכידוע, לינוקס מסתכל על אותיות קטנות וגדולות, מבחינתו זה לא אותו דבר.


3.איך לקבוע את הבסיס שעליו נבנה את האימג' – FROM

כשרוצים להשתמש ב "from" ניתן לבחור כמה אופציות של בניה:

  • שם של מערכת הפעלה:
    FROM ubuntu:20.04
    FROM debian:latest
    FROM alpine:3.18

  • שם של אימג' מוכן:
    FROM python:3.12
    FROM node:20

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

4.איך לקבוע את התיקייה שבתוכה ירוצו הפקודות – WORKDIR

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

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

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





5.איך להעתיק קבצים מהמחשב שלנו לתוך האימג'– COPY

נגיד ואני צריך להעתיק את הקובץ lev1.txt לתוך תיקייה בשם lev5 בקונטיינר, אשתמש ב copy בקובץ:



חשוב לזכור - בשביל שהמערכת תעתיק את lev1.txt לתוך הקונטיינר, הקובץ lev1.txt חייב להיות באותו המקום עם ה dockerfile.

6.איך להריץ פקודות במהלך הבנייה של ה-Image – RUN

לצורך הרצת פקודה נשתמש בפרמטר RUN ב Docker file כפי שראינו בדוגמא הקודמת:



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

ניתן גם לשרשר פקודות: RUN apt update && apt install -y nginx curl

7. איך להגדיר מה הקונטיינר יעשה כשהוא יתחיל לרוץ – CMD (כמו AUTOSTART בוינדוס)

במידה ואני רוצה שלאחר שהקונטיינר נבנה, הוא יריץ פקודות אוט' אני אוסיף את הפרמטר CMD, אך יש לו הגבלות, הוא יכול להריץ רק פקודה אחת בכל פעם, זאת אומרת אי אפשר לרשום לדוגמא:
"CMD "htop
"CMD "ifconfig

כי מבחינת המערכת היא תריץ רק את ה CMD האחרון, לכן יש צורך בשרשור של פקודות, נגיד ואני רוצה להריץ:
  • HTOP
  • IFCONIFG
  • ping
  • ls-l
בשביל שזה ירוץ אני צריך להגיד למערכת "תריץ ב BASH את הפקודות הללו", לכן לצורך זה נשתמש בסינטקס "&&" שהוא שרשור של פקודות (רק אם הראשונה הצליחה, תריץ את הבאה ניתן להשתמש בכל צורת שרשור, אני בחרתי דווקא את זה כי אני רגיל וזה עניין של בטיחות) בצורה הזאת:

CMD ["bash", "-c", "htop && ifconfig && ping -c 4 8.8.8.8 && ls -l"]

בעיקרון הדבר היחיד שלא ברור כאן זה "c-" והמשמעות שלו ה "Command" זאת אומרת "bash -command" ואז כל השאר.




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

CMD ["python3", "app.py"]

8.איך לציין איזה פורט האפליקציה שלנו תשתמש בו – EXPOSE

ברגע שיש צורך להגדיר פורטים לקונטיינר (8080, 443) וכד', נשתמש ב EXPOSE, בעצם זה אומר לדוקר, תשמע תפתח בקונטיינר את הפורטים הנ"ל, את התהליך של חיבור הפורטים מהקונטיינר למחשב שלנו, נעשה במהלך docker run.

מבחינת הסדר, את החלק של EXPOSE, נכתוב לפני ה CMD.

9. איך להריץ את הקוד תחת משתמש רגיל ולא תחת - Root

באופן עקרוני, בתור ברירת מחדל, שקונטיינר רץ, כל הפקודות מתבצעות תחת המשתמש root.

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

לצורך כך נשתמש בפרמטר "USER" ונרשום את שם משתמש שנרצה ליצור USER leidertech1



10) איך לבדוק אם הקונטיינר באמת חי ופועל כמו שצריך – HEALTHCHECK


נניח שאתם מריצים אפליקציה שהיא שרת WEB, ופתאום יש תקלות.
היה נחמד אם אפשר היה לדעת בזמן אמת מה קורה, נכון?
בדיוק בשביל זה יש את HEALTHCHECK.
הוא אמנם לא מציג לוגים מפורטים, אבל הוא מאפשר לדעת אם משהו השתבש, ומסמן שהקונטיינר לא תקין (unhealthy).

בפקודה הזאת יש כמה וכמה פרמטרים חשובים:

להלן הפקודה עם ההסברים של הפרמטרים:

HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3   CMD ping -c 1 localhost || exit 1

  • --interval=TIME - כל כמה זמן לבצע בדיקה. - 30 שניות (ברירת מחדל 30 שניות)
  • --timeout=TIME - כמה זמן לחכות מקסימום לתוצאה של בדיקה אחת. - 30 שניות (ברירת מחדל 30 שניות)
  • --start-period=TIME - זמן חסד בהתחלה – כמה זמן לתת לקונטיינר "להתחמם" לפני שבודקים. - 0 שניות (ברירת מחדל 0 שניות)
  • --retries=3 - אחרי כמה כישלונות רצופים ייחשב שהקונטיינר unhealthy. - 3 (ברירת מחדל 3 נסיונות)

דברים חשובים על HEALTHCHECK:

  • HEALTHCHECK הוא אופציונלי.
    לא חייבים לשים אותו בכל קונטיינר. אם לא שמתם, דוקר פשוט יחשוב שהקונטיינר תמיד תקין (healthy).

  • HEALTHCHECK עובד רק על קונטיינרים חיים.
    אם הקונטיינר כבר נפל (Exited), אין בדיקה. HEALTHCHECK רץ רק על קונטיינר שמצבו running.

  • סטטוסים אפשריים לקונטיינר אחרי HEALTHCHECK:
    starting – בזמן תקופת החסד (start-period).
    healthy – הבדיקות מצליחות.
    unhealthy – יותר מדי בדיקות נכשלו.
    none – אין בכלל הגדרת HEALTHCHECK.

  • HEALTHCHECK לא מתקן שום דבר בעצמו.
    הוא רק בודק ומסמן מצב (healthy או unhealthy). אם קונטיינר unhealthy – הוא לא ייעצר ולא יאתחל לבד (אלא אם תוסיפו מערכת חיצונית שתטפל בזה).

  • HEALTHCHECK משפיע על מערכות ניהול.
    למשל: Kubernetes או Docker Swarm יכולות להסתמך על סטטוס unhealthy ולהחליף קונטיינר אוטומטית.

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


11. איך לבנות אימג' בדוקר - Docker Build.


לאחר שבעצם יצרנו את הקובץ, ושמנו אותו בתיקייה שבה יש את כל הקבצים שאנחנו צריכים (במידה וצריך להעתיק קבצים לתוך הקונטיינר וכד'), נעבור ליצירת ה Image שלנו: 

  • הסינטקס: docker build -t image-name path

  • במידה ואנחנו בתוך התיקייה עצמה - . docker build -t Image_Name 

  • במידה ו Docker file נמצא במקום אחר: docker build -t image_name /full/path/to/folder

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

חשוב מאוד לשים לב שבתוך התיקייה שבה נמצא קובץ ה-Dockerfile לא יהיו קבצים מיותרים.
ברגע שמתחילים לבנות (docker build), דוקר סורק את כל הקבצים בתיקייה ומכניס אותם אוטומטית לתהליך הבנייה – גם את מה שצריך וגם את מה שלא.

אם במקרה השארתם שם, למשל, סרטון של 3 גיגה מהבר מצווה של החתול שלכם – הקובץ הזה ייכנס לבנייה!
הוא לא יפגע באימג', אבל:

  • האימג' יהיה הרבה יותר גדול,

  • תהליך הבנייה יהיה יותר איטי.

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

להלן דוגמא לבניית אימג' מ docker file שכתבתי - 

התחלת התהליך:



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


נבדוק שהאימג' באמת קיים בעזרת docker images:



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

נריץ את הקונטיינר ונתחבר אליו בעזרת:

docker run -it --name leidertech_test_container leidertech_test_image bash

וניתן לראות ישר שאנחנו במשתמש שיצרנו בתוך התיקייה שיצרנו גם כן בתוך ה docker file:


עכשיו נבדוק מה יש בתיקייה שאנחנו נמצאים בה:


כמו שכתבנו ב docker file - יש קובץ test1.sh:


ונבדוק מה יש בתוך ה test1.sh (נבדוק שזה באמת הקובץ שלנו):



כפי שניתן לראות הכל כפי שיצרנו בקובץ docker file.

ומה קורה עם רוצים ליצור 6 אימג'ים או 20? - אז בשביל זה יש דבר כזה שנקרא docker-compose - עליו נלמד בפרק הבא.

12. איך להתעלם מקבצים\תיקיות בניה של אימג'? - docker ignore

מידה ויש קבצים או תיקיות שאנחנו לא רוצים שייכנסו אל תוך ה-Image,
ניצור קובץ בשם .dockerignore (שימו לב – עם נקודה בהתחלה).

דוקר מחפש את הקובץ הזה בזמן תהליך הבנייה.
אם הקובץ לא יתחיל בנקודה (כלומר ייקרא סתם dockerignore),
דוקר לא תזהה אותו ולא תשתמש בו בכלל.

בתוך הקובץ .dockerignore נרשום את כל הקבצים או התיקיות שאנחנו רוצים שדוקר יתעלם מהם.

איך רושמים נכון?

  • אם נרצה שדוקר יתעלם מתיקייה, נרשום את שם התיקייה עם / בסוף.

  • אם נרצה שדוקר יתעלם מקובץ, פשוט נרשום את שם הקובץ כולל הסיומת.

notes.txt
videos/
logs/


וזהו, פשוט נשמור את הקובץ, ואז בהרצה, המערכת תתעלם מכל מה שכתבנו פה.

זה הכל להפעם

המייל שלי לכל שאלה levl@leidertech.co.il.

מדריך לינוקס למתחילים: כאן

חלק 6 במדריך דוקר: כאן

כל החלקים של המדריך על דוקר: כאן

מדריך PowerShell למתחילים: כאן


להלן מדריך מצולם:

אין תגובות:

הוסף רשומת תגובה

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

תודה :)