SSD Nodes Learn Hosting plans →
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-07

ההבדלים בין env_file, environment ו-env ב-Docker Compose

מבולבלים בין env_file, environment וקובץ .env ב-Docker Compose? במדריך זה נסביר את סדר הקדימויות המדויק, נציג דוגמאות קוד ונלמד היכן באמת כדאי לשמור סיסמאות וסודות רגישים.

שלושת הדברים שאנשים מכנים קובץ env

ל-Docker Compose יש שלושה מנגנונים נפרדים בעלי שמות דומים ומבלבלים. הקובץ .env ממלא מצייני מיקום מסוג ${VARIABLE} בתוך ה-compose.yaml עצמו, עוד לפני ש-Compose מנתח את הקובץ. המאפיין env_file: טוען קובץ של זוגות מפתח/ערך לתוך סביבת העבודה של המכולה. המאפיין environment: מגדיר משתנים ישירות על המכולה, כשהם כתובים בתוך קובץ ה-compose. הם אינם ניתנים להחלפה, וכאשר שניים מהם מגדירים את אותו המפתח, המנצח נקבע לפי סדר קדימויות מתועד.

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

קובץ ה-env מיועד ל-compose file, לא למכולה

צרו ספרייה והניחו בתוכה שני קבצים.

mkdir -p ~/envdemo && cd ~/envdemo
printf 'ALPINE_TAG=3.20\n' > .env
services:
  demo:
    image: alpine:${ALPINE_TAG}
    command: printenv ALPINE_TAG

כעת בדקו מול Compose מה הוא ניתח בפועל.

docker compose config

הפלט מציג את image: alpine:3.20. מציין המקום נעלם, כיוון שהאינטרפולציה התבצעה בזמן הניתוח. Compose מחפש את .env בספריית הפרויקט, שהיא הספרייה המכילה את ה-compose file, ומחליף כל ${NAME} שהוא מוצא.

לאחר מכן, הריצו את השירות.

docker compose run --rm demo

printenv ALPINE_TAG מסתיים בסטטוס 1 ולא מדפיס דבר. המשתנה אינו קיים בתוך המכולה. זוהי אי-ההבנה הנפוצה ביותר: .env הגדיר את ה-compose file, לא את התהליך. קובץ .env המכיל POSTGRES_PASSWORD=hunter2 אינו עושה דבר עבור מסד הנתונים שלכם, אלא אם כן חלק כלשהו ב-compose file מפנה אליו.

${NAME:-default} מספק ערך ברירת מחדל כאשר המשתנה אינו מוגדר או ריק. ${NAME:?message} גורם ל-Compose לסרב להתחיל ולהדפיס את ההודעה שלכם, וזו הבחירה הנכונה עבור ערך שאין לו ברירת מחדל בטוחה.

המאפיין env_file טוען משתנים לתוך המכולה

המאפיין env_file: מציין קובץ אחד או יותר שתוכנם הופך למשתני סביבה בתוך המכולה.

printf 'GREETING=from_env_file\nAPP_MODE=production\n' > app.env
services:
  demo:
    image: alpine:3.20
    command: printenv GREETING
    env_file:
      - ./app.env
docker compose run --rm demo

פעולה זו מדפיסה from_env_file. פורמט הקובץ הוא שורות KEY=value פשוטות, משתנה אחד בכל שורה, כאשר # מסמן תחילת הערה. זהו אינו shell. במרבית המקרים, מרכאות נשמרות כחלק מהערך, ואין צורך בתחיליות export. אל תוסיפו רווחים סביב סימן ה-=, כיוון ש-KEY = value ייצור משתנה ששמו המילולי הוא KEY , הכולל רווח בתחילת הערך שלו.

נתיב env_file חסר גורם לשגיאה ו-Compose נעצר. סמנו את הקובץ כאופציונלי אם ייתכן שהוא לא יהיה קיים באופן תקין:

    env_file:
      - path: ./app.env
        required: false

הגדרת משתני סביבה בתוך שורת הפקודה

services:
  demo:
    image: alpine:3.20
    command: printenv GREETING
    environment:
      GREETING: from_environment

קיימים שני תחבירים מקובלים: צורת המיפוי שמוצגת לעיל וצורת רשימה המשתמשת ב-- GREETING=from_environment. שניהם מתנהגים באופן זהה. לצורת הרשימה יש יתרון נוסף: מפתח חשוף ללא ערך מעביר את המשתנה מה-shell שבו הרצת את docker compose.

    environment:
      - GREETING
GREETING=from_my_shell docker compose run --rm demo

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

מי מנצח

Docker מתעד את סדר הקדימויות, מהגבוה לנמוך: docker compose run -e בשורת הפקודה, לאחר מכן environment או env_file שהערך שלהם נשאב מה-shell או מקובץ env, לאחר מכן environment פשוט בקובץ ה-compose, לאחר מכן env_file, ולבסוף ההנחיה ENV שמוטמעת בתוך ה-image.

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

services:
  demo:
    image: alpine:3.20
    command: printenv GREETING
    env_file:
      - ./app.env
    environment:
      GREETING: from_environment
docker compose run --rm demo
docker compose run --rm -e GREETING=from_cli demo printenv GREETING

הראשון מדפיס from_environment, לכן environment: דרס את הערך ב-app.env. השני מדפיס from_cli. שום דבר בקובץ ה-compose לא דורס את שורת הפקודה.

כאשר מכולה מתנהגת כאילו התצורה שלך לא הוחלה, אל תנחש. הפקודה docker compose config מדפיסה את הקובץ לאחר פתרון מלא, ו-docker compose config --environment מדפיסה את משתני ה-interpolation ש-Compose עובד איתם. רוב הדיווחים על "קובץ ה-env שלי מתעלמים ממנו" מתבררים כערך שהוגדר פעמיים בשתי רמות שונות.

מדוע משתני סביבה דולפים

הגדרת סיסמה בתוך environment: גורמת לשמירתה בתצורת המכולה על הדיסק, שם היא גלויה לכל משתמש בקבוצת docker.

docker compose run -d --name leaky -e DB_PASSWORD=hunter2 demo sleep 300
docker inspect leaky --format '{{json .Config.Env}}'

הפלט מכיל את "DB_PASSWORD=hunter2" בטקסט גלוי. שלושה נתיבים נוספים חושפים את אותו הערך. docker compose config מדפיס אותו למסוף, וזו הדרך שבה הוא מגיע בסופו של דבר להדבקה בפורומי תמיכה. כל תהליך בתוך המכולה יכול לקרוא את /proc/1/environ וכל תהליך בן יורש את המשתנה. כמו כן, מנגנוני טיפול בקריסות של יישומים נוהגים להדפיס את כל הסביבה לקובץ לוג או לדוח שגיאות.

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

שימוש ב-Compose secrets לשמירת ערכים בקובץ

‏Compose תומך ב-secrets מבוססי קבצים. הערך ממופה (mounted) לתוך המכולה כקובץ, במקום שיוזרק למשתני הסביבה.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
secrets:
  db_password:
    file: ./db_password.txt

ה-secret ממופה בנתיב /run/secrets/db_password בתוך המכולה. השם המופיע אחרי הלוכסן הוא שם ה-secret כפי שהוגדר בבלוק ה-secrets: ברמה העליונה.

הסיומת _FILE היא מוסכמה המשמשת את ה-Docker Official Images, כולל postgres, mysql ו-mariadb. סקריפטים של entrypoint אלו בודקים את קיום הנתיב VARNAME_FILE, קוראים את הקובץ ומשתמשים בתוכנו. זו אינה תכונה מובנית של Docker, ולכן היא פועלת רק כאשר ה-image מיישם אותה. בדקו את התיעוד של ה-image לפני שתניחו ש-SOMETHING_FILE יכובד. יישומים שאינם תומכים בכך יכולים לרוב לקרוא את הקובץ בעצמם בעת העלייה, או שניתן להעביר את הנתיב ולתת ל-entrypoint שלכם לבצע את הקריאה.

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

docker compose exec db cat /run/secrets/db_password
docker compose exec db printenv POSTGRES_PASSWORD

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

הגנו על קובץ המקור במארח (host), שכן רמת הפרטיות של ה-secret היא כרמת הפרטיות של הקובץ שמאחוריו:

chmod 600 db_password.txt

דרך האמצע הפרגמטית בשרת VPS

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

sudo install -o root -g root -m 600 /dev/null /etc/myapp/app.env
sudo nano /etc/myapp/app.env
    env_file:
      - /etc/myapp/app.env

הפקודה install -m 600 יוצרת את הקובץ עם הרשאות מוגדרות מראש, כך שאין פרק זמן שבו הקובץ חשוף לקריאה על ידי כולם. הבעלות על הקובץ היא של root, לכן משתמש שאינו root בשרת לא יכול לקרוא אותו, אם כי כל מי שיכול להריץ docker עדיין יכול לקרוא את הערך מתוך המכולה. הוסיפו את *.env ואת .env לקובץ .gitignore, ובצעו commit לקובץ app.env.example המכיל את שמות המפתחות עם ערכים ריקים בלבד. סיסמה שבוצעה לה commit היא סיסמה שיש להחליף (rotate).

החלפת ערך מחייבת אתחול של השירות. משתני סביבה נקראים פעם אחת בלבד בעת עליית תהליך המכולה, לכן עריכת הקובץ לא תשנה דבר עד להרצת docker compose up -d --force-recreate db. זהו אותו דפוס שבו נעשה שימוש במדריך n8n מאחורי HTTPS בשרת VPS, שבו מפתח ההצפנה נמצא מחוץ לקובץ ה-compose.

פיצול הגדרות לפי סביבה

כברירת מחדל, Compose קורא את .env מתיקיית הפרויקט. ניתן להפנות אותו למיקום אחר באמצעות --env-file.

docker compose --env-file .env.staging config

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

FAQ

מדוע קובץ ה-env שלי מתעלם בתוך המכולה?

הוא אינו מתעלם. הקובץ .env מבצע החלפה של מצייני מיקום מסוג ${NAME} בתוך קובץ ה-compose בלבד. הוא לעולם אינו מגדיר משתנים בתוך המכולה. כדי להעביר את הערך לתוך המכולה, יש להפנות אליו באמצעות environment: { KEY: "${NAME}" }, או להשתמש ב-env_file: ./that-file.env במקום זאת.

האם environment דורס את env_file, או להפך?

environment: גובר. סדר הקדימויות המתועד של Docker מציב את המאפיין environment מעל המאפיין env_file, ושניהם נמצאים מתחת ל-docker compose run -e בשורת הפקודה. אם מפתח מוגדר בשני המקומות, הערך ב-env_file לא יהיה בשימוש ללא התראה.

כיצד אוכל לראות את הערך הסופי ש-Compose ישתמש בו?

הריצו את docker compose config כדי להדפיס את קובץ ה-compose לאחר שכל ה-interpolation יושם. עבור מכולה שכבר רצה, הפקודה docker inspect <container> --format '{{json .Config.Env}}' מציגה בדיוק מה התהליך שלה קיבל.

האם secrets ב-Compose מוצפנים?

לא. secret המבוסס על קובץ ממופה לתוך המכולה כקובץ רגיל בנתיב /run/secrets/<name>, וקובץ המקור נשמר על הדיסק של המארח ללא הצפנה. היתרון הוא בהיקף החשיפה, לא בהצפנה: הערך נשאר מחוץ לסביבת המכולה, מחוץ לפלט של docker inspect, ומחוץ לקובצי crash dump המדפיסים את הסביבה.

האם ניתן להשתמש במירכאות וברווחים בקובץ env?

השתמשו ב-KEY=value with spaces והימנעו משימוש במירכאות. Compose מתייחס לכל המשך השורה כאל הערך, לכן מירכאות בדרך כלל הופכות לתווים מילוליים בתוך הערך. לעולם אל תשימו רווחים סביב ה-=, שכן אז המפתח יכלול רווח בסופו ושום דבר לא יתאים לו.