Docker Compose میں .env، env_file اور environment کا فرق
Docker Compose میں .env، env_file اور environment ایک جیسے نہیں۔ جانیں placeholders، container variables اور secrets کے درست استعمال، نیز precedence میں کون سی value جیتتی ہے۔
ماحول کی فائل کہلانے والی تین چیزیں
Docker Compose میں تین الگ mechanisms ہیں جن کے نام حیرت انگیز طور پر ایک جیسے ہیں۔ .env فائل compose.yaml کے اندر موجود ${VARIABLE} placeholders کو values فراہم کرتی ہے، اس سے پہلے کہ Compose اس فائل کو parse بھی کرے۔ env_file: attribute key/value pairs والی فائل کو container کے environment میں load کرتا ہے۔ environment: attribute variables کو براہِ راست container پر set کرتا ہے، اور یہ compose file میں لکھے جاتے ہیں۔ یہ ایک دوسرے کے متبادل نہیں ہیں۔ جب ان میں سے دو ایک ہی key set کریں تو فیصلہ documented precedence order کے مطابق ہوتا ہے۔
یہ guide ہر mechanism کو عملی طور پر دکھاتی ہے، ایسی command کے ذریعے precedence ثابت کرتی ہے جسے آپ خود چلا سکتے ہیں، اور پھر زیادہ اہم نکتے پر آتی ہے: جو بھی docker inspect چلا سکتا ہے، وہ environment variables پڑھ سکتا ہے۔ اس لیے passwords کو ان میں نہیں رکھنا چاہیے۔ اگر آپ compose files کے عمومی استعمال میں نئے ہیں تو VPS پر Docker Compose کی بنیادی باتیں سے شروع کریں اور configuration کے لیے یہاں واپس آئیں۔
.env فائل compose file کے لیے ہوتی ہے، container کے لیے نہیں
ایک directory بنائیں اور اس میں دو files رکھیں۔
mkdir -p ~/envdemo && cd ~/envdemo
printf 'ALPINE_TAG=3.20\n' > .envservices:
demo:
image: alpine:${ALPINE_TAG}
command: printenv ALPINE_TAGاب Compose سے پوچھیں کہ اس نے حقیقت میں کیا parse کیا ہے۔
docker compose configOutput میں image: alpine:3.20 دکھائی دیتا ہے۔ Placeholder ختم ہو چکا ہے، کیونکہ interpolation parse کے وقت ہو گئی تھی۔ Compose project directory میں .env تلاش کرتا ہے۔ یہ وہ directory ہوتی ہے جس میں compose file موجود ہوتی ہے۔ پھر اسے ملنے والی ہر ${NAME} value سے replace کر دیتا ہے۔
اب service چلائیں۔
docker compose run --rm demoprintenv ALPINE_TAG status 1 کے ساتھ exit ہوتا ہے اور کچھ print نہیں کرتا۔ یہ variable container کے اندر موجود نہیں ہے۔ یہی سب سے عام غلط فہمی ہے: .env نے compose file کو configure کیا تھا، process کو نہیں۔ .env فائل میں POSTGRES_PASSWORD=hunter2 شامل کرنے سے database پر کوئی اثر نہیں پڑتا، جب تک compose file کا کوئی حصہ اس فائل کا reference نہ دے۔
${NAME:-default} اس وقت fallback value فراہم کرتا ہے جب variable unset یا empty ہو۔ ${NAME:?message} Compose کو start ہونے سے روک کر آپ کا message print کرتا ہے۔ ایسی value کے لیے یہی درست انتخاب ہے جس کا کوئی محفوظ default موجود نہ ہو۔
env_file متغیرات کو container میں load کرتا ہے
env_file: attribute ایک یا زیادہ ایسی files کے نام بتاتا ہے جن کا content container کے environment variables بن جاتا ہے۔
printf 'GREETING=from_env_file\nAPP_MODE=production\n' > app.envservices:
demo:
image: alpine:3.20
command: printenv GREETING
env_file:
- ./app.envdocker compose run --rm demoیہ from_env_file print کرتا ہے۔ File format سادہ KEY=value lines پر مشتمل ہوتا ہے، ہر line الگ ہوتی ہے، اور # سے comment شروع ہوتا ہے۔ یہ shell format نہیں ہے۔ زیادہ تر صورتوں میں quotes value کا حصہ برقرار رہتے ہیں، اور export prefixes کی ضرورت نہیں ہوتی۔ = sign کے اردگرد spaces نہ دیں، کیونکہ KEY = value ایسی variable بناتا ہے جس کا نام literally KEY ہوتا ہے اور اس کی value کے شروع میں space شامل ہوتا ہے۔
env_file path موجود نہ ہو تو error پیدا ہوتا ہے اور Compose رک جاتا ہے۔ اگر file کا موجود نہ ہونا جائز ہو سکتا ہے تو اسے optional بنائیں:
env_file:
- path: ./app.env
required: falseماحول متغیرات inline طور پر set کرتا ہے
services:
demo:
image: alpine:3.20
command: printenv GREETING
environment:
GREETING: from_environmentاوپر دی گئی mapping form اور - GREETING=from_environment استعمال کرنے والی list form، دونوں syntaxes قابل قبول ہیں۔ دونوں ایک ہی طرح کام کرتی ہیں۔ list form میں ایک اضافی سہولت ہے: بغیر value والی bare key، اس shell سے variable کو pass through کرتی ہے جہاں آپ نے docker compose چلایا تھا۔
environment:
- GREETINGGREETING=from_my_shell docker compose run --rm demoیہ from_my_shell print کرتا ہے۔ shell میں GREETING set کیے بغیر اسے چلانے پر Compose کچھ بھی set نہیں کرتا اور کوئی warning بھی نہیں دکھاتا۔ خاموشی سے ہونے والی pass-through failures کو سمجھنا ضروری ہے، کیونکہ empty password variable کے ساتھ start ہونے والی service اکثر کامیابی سے start ہو جاتی ہے اور اس کی رسائی کھلی رہتی ہے۔
کون سی قدر غالب ہوتی ہے
Docker ترجیح کی ترتیب دستاویز کرتا ہے، جس میں سب سے زیادہ ترجیح پہلے آتی ہے: کمانڈ لائن پر docker compose run -e، پھر environment یا env_file، جن کی قدر آپ کے shell یا env file سے interpolate ہوتی ہے، پھر compose file میں سادہ environment، اس کے بعد env_file، اور آخر میں image میں شامل ENV directive۔
روزمرہ کام کے لیے مختصر اصول یہ ہے: environment:، env_file: پر غالب ہوتی ہے، جبکہ کمانڈ لائن پر -e دونوں پر غالب ہوتی ہے۔ اسے ایک ہی file میں ثابت کریں۔
services:
demo:
image: alpine:3.20
command: printenv GREETING
env_file:
- ./app.env
environment:
GREETING: from_environmentdocker compose run --rm demo
docker compose run --rm -e GREETING=from_cli demo printenv GREETINGپہلی command from_environment دکھاتی ہے، اس لیے environment: نے app.env میں موجود قدر کو override کر دیا۔ دوسری command from_cli دکھاتی ہے۔ compose file میں کوئی چیز کمانڈ لائن کی قدر کو override نہیں کرتی۔
اگر container اس طرح کام کر رہا ہو جیسے آپ کی configuration لاگو ہی نہیں ہوئی، تو اندازہ نہ لگائیں۔ docker compose config مکمل طور پر resolved file دکھاتی ہے، جبکہ docker compose config --environment وہ interpolation variables دکھاتی ہے جن سے Compose کام کر رہا ہے۔ زیادہ تر "میری env file نظرانداز ہو رہی ہے" والی رپورٹس میں اصل مسئلہ یہ ہوتا ہے کہ قدر دو مختلف سطحوں پر دو مرتبہ set کی گئی ہوتی ہے۔
ماحول کے متغیرات کیسے افشا ہوتے ہیں
environment: میں password مقرر کرنے سے یہ container کی configuration میں disk پر محفوظ ہو جاتا ہے، اور docker group کا ہر user اسے دیکھ سکتا ہے۔
docker compose run -d --name leaky -e DB_PASSWORD=hunter2 demo sleep 300
docker inspect leaky --format '{{json .Config.Env}}'Output میں "DB_PASSWORD=hunter2" سادہ متن کی صورت میں شامل ہوتا ہے۔ مزید تین paths بھی یہی value ظاہر کرتے ہیں۔ docker compose config اسے terminal پر print کرتا ہے، جس کے نتیجے میں یہ support forum میں paste ہو جاتا ہے۔ container کے اندر موجود کوئی بھی process /proc/1/environ پڑھ سکتا ہے، اور ہر child process یہ variable inherit کرتا ہے۔ اس کے علاوہ application کے crash handlers اکثر پورا environment log یا error report میں dump کر دیتے ہیں۔
docker group کی membership میزبان پر عملاً root کے برابر ہے، اس لیے اسے ایسی privilege boundary نہ سمجھیں جس پر انحصار کیا جا سکے۔ VPS پر least privilege user accounts کی guide وضاحت کرتی ہے کہ shared server پر اس group کی membership محدود رکھنا کیوں ضروری ہے۔
Compose secrets قدر کو فائل میں رکھتے ہیں
Compose فائل پر مبنی secrets کو support کرتا ہے۔ قدر کو environment میں شامل کرنے کے بجائے container کے اندر ایک فائل کے طور پر mount کیا جاتا ہے۔
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./db_password.txtsecret کو container کے اندر /run/secrets/db_password پر mount کیا جاتا ہے۔ slash کے بعد موجود نام top-level secrets: block سے لیا گیا secret name ہے۔
_FILE suffix Docker Official Images میں استعمال ہونے والا ایک convention ہے، جس میں postgres، mysql اور mariadb شامل ہیں۔ ان images کے entrypoint scripts VARNAME_FILE کو check کرتے ہیں، فائل پڑھتے ہیں، اور اس کے contents استعمال کرتے ہیں۔ یہ Docker feature نہیں ہے، اس لیے صرف وہاں کام کرتا ہے جہاں image اسے implement کرتی ہو۔ یہ فرض کرنے سے پہلے کہ SOMETHING_FILE کو honour کیا جائے گا، image documentation دیکھیں۔ جو applications اسے support نہیں کرتیں، وہ اکثر startup کے وقت خود فائل پڑھ سکتی ہیں۔ متبادل طور پر path pass کریں اور اپنے entrypoint کو یہ کام کرنے دیں۔
چلتے ہوئے container کے اندر سے تصدیق کریں:
docker compose exec db cat /run/secrets/db_password
docker compose exec db printenv POSTGRES_PASSWORDپہلی command password print کرتی ہے۔ دوسری command کچھ print نہیں کرتی، کیونکہ قدر environment میں شامل ہی نہیں ہوئی۔ یہی اس کا مقصد ہے: اس container پر docker inspect صرف بے ضرر path دکھاتا ہے۔
Host پر source file کو محفوظ رکھیں، کیونکہ secret کی رازداری اس کے پیچھے موجود file جتنی ہی ہوتی ہے:
chmod 600 db_password.txtVPS پر عملی درمیانی راستہ
بہت سی self-hosted images _FILE variables کو support نہیں کرتیں، اس لیے داخل ہونے کا واحد طریقہ environment variables ہیں۔ ایک ہی administrator VPS پر حقیقت پسندانہ مقصد یہ ہے کہ values آپ کے project directory میں موجود ایسی file میں نہ رہیں جسے تمام users پڑھ سکتے ہوں، اور انہیں 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.envinstall -m 600 file بناتے وقت ہی اس کا mode مقرر کر دیتا ہے، اس لیے کوئی ایسا وقفہ نہیں آتا جس میں اسے ہر user پڑھ سکے۔ اس file کا مالک root ہوتا ہے، لہٰذا machine پر موجود non-root user اسے نہیں پڑھ سکتا؛ تاہم جو بھی docker چلا سکتا ہو، وہ container سے value پھر بھی پڑھ سکتا ہے۔ *.env اور .env کو .gitignore میں شامل کریں، اور اس کے بجائے ایک app.env.example commit کریں جس میں key names ہوں اور values خالی ہوں۔ commit کیا گیا password تبدیل کرنا ضروری ہوتا ہے۔
کسی value کو rotate کرنے کا مطلب service کو restart کرنا ہے۔ Environment variables container process شروع ہوتے وقت صرف ایک بار پڑھے جاتے ہیں، اس لیے file میں ترمیم کرنے سے کچھ تبدیل نہیں ہوتا جب تک آپ docker compose up -d --force-recreate db نہ چلائیں۔ یہی طریقہ VPS پر HTTPS کے پیچھے n8n گائیڈ میں استعمال کیا گیا ہے، جہاں encryption key compose file سے باہر رکھی جاتی ہے۔
ماحول کے لحاظ سے configuration الگ کرنا
Compose پہلے سے project directory سے .env پڑھتا ہے۔ اسے کسی دوسری جگہ سے پڑھانے کے لیے --env-file استعمال کریں۔
docker compose --env-file .env.staging configمتعدد files ترتیب سے پڑھی جاتی ہیں، اور بعد والی files پہلے والی settings کو override کرتی ہیں۔ secret کے بغیر defaults کو ایک committed file میں رکھیں، جبکہ secrets ایسی file میں رکھیں جو کبھی server سے باہر نہ جائے۔ یہی اصول env_file: پر بھی لاگو ہوتا ہے؛ duplicate key کی صورت میں فہرست میں آخری file مؤثر ہوتی ہے۔
FAQ
میرے .env فائل کو container کے اندر نظر انداز کیوں کیا جا رہا ہے؟
اسے نظر انداز نہیں کیا جا رہا۔ .env فائل صرف compose فائل میں موجود ${NAME} placeholders کو substitute کرتی ہے۔ یہ کبھی بھی container کے اندر variables set نہیں کرتی۔ value کو container تک پہنچانے کے لیے اس کا حوالہ دیں: environment: { KEY: "${NAME}" }، یا اس کے بجائے env_file: ./that-file.env استعمال کریں۔
کیا environment، env_file کو override کرتا ہے، یا اس کے برعکس؟
environment: کو ترجیح حاصل ہے۔ Docker کی دستاویزی ترجیحی ترتیب میں environment attribute، env_file attribute سے اوپر ہے، جبکہ دونوں command line پر docker compose run -e سے نیچے ہیں۔ اگر کوئی key دونوں جگہ set ہو تو env_file کی value خاموشی سے استعمال نہیں کی جاتی۔
Compose کی استعمال ہونے والی حتمی value کیسے دیکھوں؟
مکمل طور پر resolved compose فائل دیکھنے کے لیے docker compose config چلائیں، جس میں تمام interpolation لاگو ہو چکی ہو۔ پہلے سے چلتے ہوئے container کے لیے docker inspect <container> --format '{{json .Config.Env}}' بالکل وہی value دکھاتا ہے جو اس کے process کو موصول ہوئی۔
کیا Compose secrets encrypted ہوتے ہیں؟
نہیں۔ File-based secret کو /run/secrets/<name> پر plain file کے طور پر container میں mount کیا جاتا ہے، جبکہ source file host disk پر بغیر encryption کے موجود رہتی ہے۔ فائدہ encryption نہیں بلکہ scope ہے: value container environment سے باہر رہتی ہے، docker inspect output میں شامل نہیں ہوتی، اور ان crash dumps سے بھی باہر رہتی ہے جو environment print کرتے ہیں۔
کیا میں env فائل میں quotes اور spaces استعمال کر سکتا ہوں؟
KEY=value with spaces استعمال کریں اور quotes نہ لگائیں۔ Compose پوری باقی line کو value سمجھتا ہے، اس لیے quotes عموماً value میں literal characters کے طور پر شامل ہو جاتے ہیں۔ = کے اردگرد spaces کبھی نہ رکھیں، کیونکہ اس صورت میں key کے آخر میں trailing space شامل ہو جاتی ہے اور کوئی value اس سے match نہیں کرتی۔