توی این درس یاد میگیری چطور یک image واحد را برای محیطهای مختلف تنظیم کنی، بدون اینکه آن را دوباره بسازی: متغیرهای محیطی (environment variables) را با -e و --env-file به کانتینر میدهی. میبینی image های رسمی (مثل MySQL) از چه متغیرهایی میخوانند (MYSQL_ROOT_PASSWORD و …)، چرا مقدار متغیرها در docker inspect دیده میشود (و چرا برای رازها کافی نیست)، و چرا تغییر متغیر نیاز به ساختن کانتینر جدید دارد.
تشبیه: برچسب روی لوازم
Section titled “تشبیه: برچسب روی لوازم”متغیر محیطی مثل برچسبهایی روی در اتاق است که برنامه موقع شروع میخواند: «رمز دیتابیس این است»، «حالت: تست». یک اتاق (image) ثابت است ولی هر بار که برچسبهای متفاوتی روی آن بچسبانی، رفتارش عوض میشود. برنامههایی که با اصل «config از محیط میآید» نوشته شدهاند (معروف به 12-factor app) برای هر محیط (توسعه، تست، production) فقط با متغیر تنظیم میشوند.
مسیر یک متغیر
Section titled “مسیر یک متغیر”مثالهای عملی
Section titled “مثالهای عملی”مثال ۱: اولین متغیر با -e
Section titled “مثال ۱: اولین متغیر با -e”docker run --rm -e GREETING=salam alpine sh -c 'echo "پیام: $GREETING"'docker run --rm -e A=1 -e B=2 alpine env | grep -E '^(A|B)='پیام: salamA=1B=2با -e نام=مقدار یک متغیر به کانتینر میدهی؛ میتوانی چند -e پشت هم بنویسی. دستور env داخل کانتینر همهی متغیرها را فهرست میکند و ما با grep فقط دو تایمان را بیرون کشیدیم.
مثال ۲: عبور از متغیر میزبان
Section titled “مثال ۲: عبور از متغیر میزبان”export TOKEN=abc123docker run --rm -e TOKEN alpine sh -c 'echo "داخل کانتینر: $TOKEN"'docker run --rm alpine sh -c 'echo "بدون -e: [${TOKEN}]"'داخل کانتینر: abc123بدون -e: []اگر فقط اسم را بنویسی (-e TOKEN بدون مقدار)، داکر مقدارش را از محیط shell خودت برمیدارد. بدون -e هیچ متغیری از میزبان به کانتینر نمیرسد؛ کانتینر محیط جدا دارد.
مثال ۳: فایل env (--env-file)
Section titled “مثال ۳: فایل env (--env-file)”وقتی متغیرها زیاد میشوند، آنها را در یک فایل میگذاری:
cat > app.env <<'LXEOF'# تنظیمات برنامهAPP_MODE=testDB_HOST=db.localDB_PORT=5432LXEOFdocker run --rm --env-file app.env alpine env | grep -E '^(APP_|DB_)'APP_MODE=testDB_HOST=db.localDB_PORT=5432قاعدهی فایل: هر خط KEY=VALUE، خطهای # توضیحاند و خطهای خالی نادیده گرفته میشوند. گیومه در فایل env معنی ندارد و جزو مقدار میشود (اشتباه ۲ را ببین). فایل را با .gitignore از git دور نگه دار، چون ممکن است رمز داشته باشد.
مثال ۴: image های رسمی از متغیر میخوانند (MYSQL_ROOT_PASSWORD)
Section titled “مثال ۴: image های رسمی از متغیر میخوانند (MYSQL_ROOT_PASSWORD)”image رسمی MySQL موقع شروع رمز root و تنظیمات اولیه را از متغیرها میخواند. اول سادهترین شکل (همان دستور سرفصل درس):
docker run -d --name lx-e1 -e MYSQL_ROOT_PASSWORD=secret mysql:8.4 >/dev/nullfor i in $(seq 1 40); do docker logs lx-e1 2>&1 | grep -q "ready for connections.*port: 3306" && break; sleep 2; donedocker exec -e MYSQL_PWD=secret lx-e1 mysql -uroot -N -e "SELECT 'اتصال با رمز secret موفق بود'" 2>&1 | grep -v Warningdocker rm -f lx-e1 >/dev/nullاتصال با رمز secret موفق بودحالا با فایل env و چند متغیر (تنظیم پایگاهداده و کاربر اختصاصی). متغیرهای رسمی این image: MYSQL_ROOT_PASSWORD (رمز root)، MYSQL_DATABASE (پایگاهدادهای که در شروع ساخته شود)، MYSQL_USER و MYSQL_PASSWORD (یک کاربر معمولی):
cat > db.env <<'LXEOF'MYSQL_ROOT_PASSWORD=rootpassMYSQL_DATABASE=shopMYSQL_USER=appMYSQL_PASSWORD=apppassLXEOFdocker run -d --name lx-e2 --env-file db.env mysql:8.4 >/dev/nullfor i in $(seq 1 40); do docker logs lx-e2 2>&1 | grep -q "ready for connections.*port: 3306" && break; sleep 2; donedocker exec -e MYSQL_PWD=apppass lx-e2 mysql -uapp -N -e "SHOW DATABASES" 2>&1 | grep -v Warninginformation_schemaperformance_schemashopکاربر app با رمز apppass وارد شد و پایگاهدادهی shop را میبیند (که فقط با متغیر MYSQL_DATABASE ساخته شد). هیچ دستور SQL ای ننوشتیم؛ فقط متغیر دادیم. این همان قدرت image های رسمی است؛ برای هر image فهرست متغیرها در صفحهی Docker Hub آن آمده.
رمز root در image رسمی MySQL با کدام متغیر تنظیم میشود؟
MYSQL_ROOT_PASSWORD رمز root است؛ MYSQL_USER و MYSQL_PASSWORD برای کاربر معمولیاند.
مثال ۵: متغیرهای پیشفرض image و override
Section titled “مثال ۵: متغیرهای پیشفرض image و override”image ها خودشان متغیر دارند (که سازنده با ENV در Dockerfile گذاشته). -e آنها را بازنویسی میکند:
docker run --rm nginx:alpine env | grep NGINX_VERSIONdocker run --rm -e NGINX_VERSION=fake nginx:alpine env | grep NGINX_VERSIONNGINX_VERSION=1.31.6NGINX_VERSION=fakeمثال ۶: متغیرها از نگاه سیستم
Section titled “مثال ۶: متغیرها از نگاه سیستم”docker run -d --name lx-e3 -e SECRET_KEY=abc123 alpine sleep 120 >/dev/nulldocker exec lx-e3 sh -c 'cat /proc/1/environ | tr "\0" "\n" | grep SECRET_KEY'docker inspect lx-e3 --format '{{range .Config.Env}}{{println .}}{{end}}' | grep SECRET_KEYdocker rm -f lx-e3 >/dev/nullSECRET_KEY=abc123SECRET_KEY=abc123متغیرهای محیطی در environment پروسهی شماره ۱ هستند (فایل مجازی /proc/1/environ) و در پیکربندی کانتینر هم ثبت میشوند؛ پس هر کس به docker inspect یا docker exec دسترسی دارد، مقدارشان را میبیند. نتیجهی امنیتی مهم: متغیر محیطی برای رازهای حساس (رمز production) راه ایدهآل نیست؛ در درس «امنیت پایه» با روشهای بهتر آشنا میشوی.
پشت پرده
Section titled “پشت پرده”متغیرهای محیطی سادهترین مکانیزم یونیکسی برای انتقال تنظیمات به یک پروسهاند: موقع شروع پروسه (exec) یک فهرست KEY=VALUE همراه آن میشود. داکر همین فهرست را از سه منبع میسازد، به این ترتیب اولویت:
ENVدر Dockerfile (پیشفرض image)--env-file-e(بالاترین اولویت؛ آخرین مقدار برنده است)
برنامهی داخل کانتینر با getenv (یا process.env، os.environ) آنها را میخواند. چون متغیرها فقط موقع شروع خوانده میشوند، عوض کردن آنها روی کانتینر موجود ممکن نیست (اشتباه ۴).
جدولهای مرجع
Section titled “جدولهای مرجع”| شکل | معنی |
|---|---|
-e KEY=value |
یک متغیر با مقدار مشخص |
-e KEY |
مقدار را از shell میزبان بردار |
--env-file FILE |
چند متغیر از فایل |
| متغیر | image | کار |
|---|---|---|
MYSQL_ROOT_PASSWORD |
mysql | رمز root (الزامی) |
MYSQL_DATABASE |
mysql | ساخت پایگاهدادهی اولیه |
MYSQL_USER / MYSQL_PASSWORD |
mysql | ساخت کاربر معمولی |
قواعد فایل env: KEY=VALUE در هر خط؛ # توضیح؛ بدون export؛ گیومه جزو مقدار است؛ فاصلهی دور = نمیگذاریم.
اشتباهات رایج
Section titled “اشتباهات رایج”۱) فراموش کردن متغیر الزامی
Section titled “۱) فراموش کردن متغیر الزامی”docker run --name lx-bad mysql:8.4docker rm -f lx-bad >/dev/null2026-10-03 10:30:33+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.4.11-1.el9 started.2026-10-03 10:30:33+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'2026-10-03 10:30:33+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.4.11-1.el9 started.2026-10-03 10:30:34+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified You need to specify one of the following as an environment variable: - MYSQL_ROOT_PASSWORD - MYSQL_ALLOW_EMPTY_PASSWORD - MYSQL_RANDOM_ROOT_PASSWORDimage MySQL بدون MYSQL_ROOT_PASSWORD (یا یکی از دو گزینهی دیگر که پیام میگوید) اجرا نمیشود و بلافاصله خارج میشود. راهحل: همیشه صفحهی Docker Hub یا docker logs را بخوان؛ پیام خطا دقیقاً میگوید چه متغیری لازم است.
۲) گیومه در فایل env
Section titled “۲) گیومه در فایل env”printf 'NAME="ali"\n' > quote.envdocker run --rm --env-file quote.env alpine sh -c 'echo "مقدار: [$NAME]"'مقدار: ["ali"]گیومهها جزو مقدار شدند ("ali" با گیومه). راهحل: در فایل env بدون گیومه بنویس: NAME=ali.
۳) فاصله در مقدار روی خط فرمان
Section titled “۳) فاصله در مقدار روی خط فرمان”docker run --rm -e MSG=hello world alpine echo okdocker run --rm -e "MSG=hello world" alpine sh -c 'echo "[$MSG]"'Unable to find image 'world:latest' locallydocker: Error response from daemon: pull access denied for world, repository does not exist or may require 'docker login'
Run 'docker run --help' for more information[hello world]بدون گیومه، world مثل یک دستور جداگانه (نام image) تعبیر شد و خطا گرفتی. راهحل: کل KEY=مقدار با فاصله را در گیومه بگذار.
۴) تغییر متغیر روی کانتینر موجود
Section titled “۴) تغییر متغیر روی کانتینر موجود”docker run -d --name lx-e3 -e MODE=old alpine sleep 120 >/dev/nulldocker stop -t 1 lx-e3 >/dev/null; docker start lx-e3 >/dev/nulldocker exec lx-e3 sh -c 'echo "MODE=$MODE"'docker rm -f lx-e3 >/dev/nullMODE=oldحتی بعد از stop و start متغیر همان است. راهی برای عوض کردن متغیرهای یک کانتینر موجود نیست. راهحل: کانتینر را حذف و با -e جدید دوباره بساز (در Compose با up -d که آن را خودکار میسازد).
۵) گذاشتن رمز واقعی در فایل و commit کردنش
Section titled “۵) گذاشتن رمز واقعی در فایل و commit کردنش”فایل .env را به git اضافه نکن. راهحل: .gitignore و یک فایل نمونهی بیرمز (.env.example).
یک کانتینر alpine بساز که با دو متغیر NAME=ali و AGE=30 جملهی «ali is 30» را چاپ کند.
دیدن جواب
docker run --rm -e NAME=ali -e AGE=30 alpine sh -c 'echo "$NAME is $AGE"'ali is 30یک فایل web.env با دو متغیر COLOR=blue و SIZE=large بساز و با --env-file آن را به یک کانتینر بده؛ ثابت کن هر دو متغیر آنجا هستند.
دیدن جواب
printf 'COLOR=blue\nSIZE=large\n' > web.envdocker run --rm --env-file web.env alpine env | grep -E '^(COLOR|SIZE)='COLOR=blueSIZE=largeتمرین اصلی: یک دیتابیس MySQL با تنظیمات از فایل env اجرا کن (MYSQL_ROOT_PASSWORD=pw، MYSQL_DATABASE=blog). ثابت کن پایگاهدادهی blog ساخته شده، بعد با docker inspect نشان بده رمز در پیکربندی دیده میشود، و در آخر کانتینر را حذف کن.
دیدن جواب
printf 'MYSQL_ROOT_PASSWORD=pw\nMYSQL_DATABASE=blog\n' > blog.envdocker run -d --name lx-e1 --env-file blog.env mysql:8.4 >/dev/nullfor i in $(seq 1 40); do docker logs lx-e1 2>&1 | grep -q "ready for connections.*port: 3306" && break; sleep 2; donedocker exec -e MYSQL_PWD=pw lx-e1 mysql -uroot -N -e "SHOW DATABASES LIKE 'blog'" 2>&1 | grep -v Warningdocker inspect lx-e1 --format '{{range .Config.Env}}{{println .}}{{end}}' | grep MYSQL_ROOT_PASSWORDdocker rm -f lx-e1 >/dev/nullblogMYSQL_ROOT_PASSWORD=pwدیدی که رمز در docker inspect آشکار است؛ برای همین برای رازهای واقعی روشهای امنتر لازم است.
آزمونک
Section titled “آزمونک”متغیر محیطی چه کمکی میکند؟
یک image برای محیطهای مختلف با متغیرهای متفاوت اجرا میشود.
در -e TOKEN (بدون مقدار) مقدار از کجا میآید؟
داکر مقدار متغیر TOKEN را از shell خودت برمیدارد.
گیومه در فایل --env-file چه میشود؟
در فایل env گیومهی اضافه ننویس.
آیا متغیرهای محیطی کانتینر در docker inspect دیده میشوند؟
هر کس به inspect دسترسی دارد مقدار را میبیند.
چطور متغیرهای یک کانتینر موجود را عوض میکنی؟
متغیرها موقع شروع پروسه خوانده میشوند؛ restart آنها را عوض نمیکند.
جمعبندی
Section titled “جمعبندی”-e KEY=valueیا-e KEY(از shell) و--env-file FILEمتغیر محیطی را به کانتینر میدهند.- image های رسمی از متغیرها میخوانند (MySQL:
MYSQL_ROOT_PASSWORD،MYSQL_DATABASE،MYSQL_USER،MYSQL_PASSWORD). - در فایل env:
KEY=VALUE، بدون گیومه؛#توضیح. - متغیرها در
docker inspectو/proc/1/environدیده میشوند؛ برای رازها کافی نیستند. - متغیر کانتینر موجود عوض نمیشود؛ کانتینر را دوباره بساز.
| دستور | کاری که میکند |
|---|---|
docker run -e KEY=value IMG | یک متغیر |
docker run -e KEY IMG | مقدار از shell میزبان |
docker run --env-file .env IMG | متغیرها از فایل |
docker run -e MYSQL_ROOT_PASSWORD=secret mysql | رمز root برای MySQL |
docker exec N env | متغیرهای کانتینر |
docker inspect --format "{{.Config.Env}}" N | متغیرها در پیکربندی |
printf "KEY=value\n" > .env | ساختن فایل env |