اگر همان فایل Compose لپتاپ را روی سرور اجرا کنید، ممکن است source با bind mount جای image را بگیرد، debugger عمومی شود، دیتابیس روی همه interfaceها باز باشد یا رمز آزمایشی در production بماند. برعکس، اگر تنظیمات سختگیرانه production را بدون تغییر به توسعه ببرید، چرخه ویرایش و تست کند میشود. تفاوت این دو محیط فقط مقدار یک متغیر ENV نیست؛ هدف عملیاتیشان متفاوت است.
پاسخ سریع: در Development دسترسی محلی، بازسازی سریع، hot reload، داده آزمایشی و debug کنترلشده اولویت دارد. در Production باید image آزموده و ثابت، پورتهای محدود، secret محافظتشده، داده ماندگار، health، monitoring، backup و مسیر rollback داشته باشید. منطق سرویس و نسخه نرمافزار تا حد ممکن مشترک بماند، ولی config نهایی هر محیط جداگانه بازبینی شود.
بهجای دو جهان جدا، یک قرارداد مشترک بسازید
نام سرویسها، پروتکل ارتباط، مسیرهای داده، health endpoint و dependencyهای اصلی بهتر است بین محیطها قابلتشخیص باشند. تفاوت لازم را در فایلهای محیطی یا override تعریف کنید. اگر محیط توسعه همه dependencyها را mock میکند ولی production به دیتابیس و queue واقعی متکی است، آزمون یکپارچگی در staging ضروری میشود. هدف یکسانسازی صددرصدی نیست؛ هدف کاهش غافلگیری هنگام انتقال artifact است.
چرخه کد: bind mount یا image نسخهدار؟
در توسعه، bind mount source و Compose Watch میتوانند تغییر کد را سریع به container برسانند. در production، کد باید در image ساخته و آزموده شده باشد؛ bind mount کل repository باعث میشود محتوای host و permission آن نتیجه اجرا را تغییر دهد. برای release، همان image digest که در staging تأیید شده را promote کنید. راهنمای Dockerfile production مراحل ساخت artifact قابلتکرار را پوشش میدهد.
فایل پایه و override را چطور جدا کنیم؟
فایل پایه میتواند تعریف سرویس، network داخلی و volume را نگه دارد. فایل توسعه build محلی، mount source و debug port فقط روی loopback را اضافه کند. فایل production image digest، منابع، policy restart و اتصال proxy را مشخص کند. نام compose.override.yaml در اجرای معمول Compose ممکن است خودکار خوانده شود؛ برای استقرار تولیدی فایلها را صریح با -f انتخاب کنید و خروجی ادغامشده را بررسی کنید.
قواعد merge همه فیلدها یکسان نیست: بعضی مقدارها جایگزین میشوند و بعضی فهرستها ادغام میشوند. فرض نکنید تعریف دوباره ports در فایل تولیدی، پورت debug فایل پایه را حذف میکند. برای همین، تنظیمات اختصاصی توسعه را در فایل پایه قرار ندهید. مسیرهای نسبی در ترکیب چند فایل نیز نسبت به فایل پایه تفسیر میشوند؛ این نکته در monorepo خطای خاموش ایجاد میکند.
خروجی نهایی را پیش از اجرا ببینید
docker compose -f compose.yaml -f compose.prod.yaml config
این فرمان فقط config مؤثر را نمایش میدهد و service را deploy نمیکند. آن را برای بررسی ports، mount، image، env، network و secret استفاده کنید. خروجی میتواند مقدار متغیرهای حساس را نشان دهد؛ آن را در log عمومی CI یا تیکت بدون پالایش کپی نکنید. اعتبار YAML به معنی درستبودن عملیات نیست؛ آزمون staging هنوز لازم است.
Image و dependency در دو محیط
در توسعه میتوانید target مخصوص ابزار debug یا watch بسازید. در production از target سبکتر و non-root استفاده کنید؛ runtime باید با dependency واقعی سازگار باشد. نسخه dependency باید با lockfile مشخص باشد. ساخت مجدد image روی سرور production بهجای دریافت artifact آزمودهشده، فاصله محیطها را زیاد میکند. tag شناور مانند latest برای audit و rollback کافی نیست.
متغیر محیطی یا secret؟
مقدار عمومی مانند نام محیط با متغیر محیطی مناسب است؛ password، token و private key به کنترل بیشتری نیاز دارند. فایل .env در Compose لزوماً secret store نیست و ممکن است در repository، shell یا خروجی config لو برود. برای secret runtime از مکانیزم secret یا فایل با مالکیت و مجوز محدود استفاده کنید و گردش/تعویض آن را در runbook بنویسید. توسعه هم نباید credential production را کپی کند؛ داده و حساب آزمایشی مستقل بهتر است.
پورتها و مرز شبکه
در لپتاپ ممکن است دیتابیس برای ابزار توسعه روی 127.0.0.1 publish شود. در production، دیتابیس و cache معمولاً فقط در network داخلی Compose لازماند و تنها reverse proxy پورت عمومی دارد. expose را با ports اشتباه نگیرید: اولی مستندسازی/دسترسی داخلی است، دومی میتواند پورت host را منتشر کند. firewall host، شبکه Docker و دسترسی cloud را با هم بررسی کنید.
داده آزمایشی در برابر داده قابلبازیابی
در توسعه پاککردن دیتابیس آزمایشی ممکن است پذیرفته باشد. در production، volume باید مالک، backup، retention و Restore Test داشته باشد. از دستورهای حذف volume یا reset محیط توسعه برای server زنده استفاده نکنید. migration schema بخشی از release است؛ snapshot بهتنهایی بدون سازگاری با فایلهای upload یا زمان ازدسترفتن تراکنشها کافی نیست. RPO و RTO را با واقعیت کسبوکار تطبیق دهید.
Healthcheck و dependency
در توسعه ممکن است منتظر آمادهشدن سرویس بمانید یا container را دستی restart کنید. در production، healthcheck، retry کنترلشده و alert ضروری است. depends_on ترتیب شروع را بهتر میکند و با شرط مناسب میتواند منتظر سلامت dependency بماند، اما تضمین نمیکند آن dependency بعداً خراب نشود. برنامه باید خطاهای موقت دیتابیس، DNS و API را با timeout و backoff مدیریت کند.
Logging و observability
log پرجزئیات توسعه برای عیبیابی خوب است، ولی در production میتواند داده حساس و حجم Disk بسازد. سطح log، rotation، retention، request ID و دسترسی اپراتور باید مشخص باشد. stdout/stderr را به جمعآوری متمرکز وصل کنید و بیرون از host نیز دسترسی کاربر را پایش کنید. راهنمای مانیتورینگ سرور توضیح میدهد چرا سلامت container بهتنهایی کافی نیست.
محدودیت منابع و رفتار در کمبود ظرفیت
لپتاپ و سرور production حافظه و CPU متفاوت دارند. محدودیتها باید از اندازهگیری workload بیایند، نه عدد کپیشده از نمونه اینترنتی. OOM و restart loop را Alert کنید. worker، connection pool و cache را با ظرفیت host هماهنگ کنید. محدودیت منابع اشتباه میتواند سرویس سالم را مرتب kill کند؛ نبود محدودیت هم ممکن است همسایههای همان host را تحت فشار قرار دهد.
امنیت و مجوزها
debugger، endpoint توسعه، hot reload و mount Docker socket در production ریسک بزرگی دارند. process تا حد امکان non-root باشد، فایلها کمترین مجوز لازم را داشته باشند و image و Engine patch شوند. اجرای توسعه با root برای راحتی، خطای permission را تا لحظه release پنهان میکند؛ smoke test با user واقعی runtime این فاصله را آشکار میکند.
Release و Rollback
در توسعه میتوانید container را مرتب recreate کنید؛ در production تغییر باید به نسخه، زمان، اپراتور و نتیجه health مرتبط باشد. قبل از rollout، backup و سازگاری migration را بررسی کنید. توقف container قبلی و ساخت نمونه جدید با Compose لزوماً zero downtime نیست. اگر قطعی پذیرفته نیست، معماری blue/green یا چند replica با proxy و health gate نیاز دارید؛ ارزیابی Compose برای production معیار انتخاب را باز میکند.
چکلیست تفاوتها
- Development: source mount و watch؛ Production: image ثابت و digest ثبتشده.
- Development: داده آزمایشی و reset مجاز؛ Production: backup و Restore Test.
- Development: debug محلی؛ Production: حداقل پورت و log پالایششده.
- Development: credential آزمایشی؛ Production: secret محدود و قابلچرخش.
- Development: مشاهده دستی؛ Production: health، monitoring و on-call.
- Development: restart سریع؛ Production: release و rollback تعریفشده.
اشتباههای رایج
شایعترین خطا این است که debug port یا bind mount بهطور ناخواسته پس از merge در production باقی بماند. پس از آن، تصور اینکه .env محرمانه است، فرض اینکه up -d سلامت برنامه را ثابت میکند، و اتکا به volume بدون backup قرار میگیرد. همه اینها با review خروجی config، آزمون staging و runbook قابلکاهشاند.
اگر فاصله محیطها زیاد است
وقتی برنامه فقط روی لپتاپ توسعهدهنده کار میکند، ابتدا تفاوت image، config، داده و شبکه را فهرست کنید؛ مهاجرت عجولانه به ابزار بزرگتر مشکل را حل نمیکند. خدمت داکرایز اپلیکیشن میتواند فایلهای Compose، pipeline و قرارداد داده را برای محیطهای قابلتکرار بازطراحی کند.
پرسشهای متداول
آیا باید دو Dockerfile جدا داشته باشیم؟
نه لزوماً؛ یک Dockerfile چندمرحلهای با target توسعه و runtime تولیدی میتواند کافی باشد، به شرط اینکه خروجی هر دو آزموده شود.
آیا فایل override خودکار خوانده میشود؟
در اجرای معمول Compose نام پیشفرض override میتواند خودکار اعمال شود؛ برای production مجموعه فایلها را صریح اعلام و خروجی را بازبینی کنید.
آیا staging باید کپی کامل production باشد؟
از نظر مسیر release و dependencyهای حیاتی نزدیک باشد؛ داده و secret واقعی را بدون ضرورت و حفاظت مناسب کپی نکنید.
آیا docker compose config کافی است؟
خیر؛ ساختار ادغامشده را نشان میدهد، نه سلامت برنامه، مجوز volume یا موفقیت rollback.