آموزش استفاده از چندین فایل در Docker Compose
با نحوه ادغام فایلهای compose.yaml و compose.override.yaml آشنا شوید. یاد بگیرید چگونه ترتیب فایلها، تداخل پورتها و دستور include را برای مدیریت محیطهای dev و prod کنترل کنید.
نحوه عملکرد Docker Compose با بیش از یک فایل
Docker Compose میتواند یک پروژه را از چندین فایل بسازد. این ابزار فایلها را به ترتیبی که دریافت میکند میخواند و آنها را در یک مدل واحد ادغام میکند، بنابراین در صورت بروز تضاد، مقادیر موجود در فایلهای بعدی جایگزین میشوند. دو مکانیزم برای انجام این کار از طریق خط فرمان وجود دارد: یک فایل override که Compose بهصورت خودکار بارگذاری میکند، و فلگ -f که شما بهصورت دستی ارسال میکنید. مکانیزم سوم درون خود فایل قرار دارد، یعنی عنصر include، که عملکرد آن با دو مورد دیگر متفاوت است.
این ادغام یک جایگزینی ساده نیست. نگاشتها (mappings) کلید به کلید ادغام میشوند، دنبالهها (sequences) به انتهای یکدیگر اضافه میشوند و مجموعه کوچکی از فیلدها بهطور کامل جایگزین میشوند. همین تفاوت منشأ غافلگیریهاست و لیست ports موردی است که تقریباً همه را به اشتباه میاندازد.
تمام موارد زیر فرض را بر استفاده از Compose نسخه 2 یا بالاتر، یعنی پلاگین docker compose بهجای اسکریپت قدیمی docker-compose میگذارند. نسخههای فعلی با شماره v5 منتشر میشوند و پلاگین به همان شیوه عمل میکند. برای بررسی، دستور docker compose version را اجرا کنید. اگر هنوز فایل Compose ننوشتهاید، با راهنمای مقدماتی Docker Compose شروع کنید و سپس به اینجا بازگردید.
فایل override که Compose بدون دستور خاصی بارگذاری میکند
اگر docker compose up را بدون هیچ پرچم -f اجرا کنید، Compose دایرکتوری جاری و سپس دایرکتوریهای والد آن را برای یافتن compose.yaml یا docker-compose.yaml جستجو میکند. اگر یک فایل override در کنار فایل پایه قرار داشته باشد، Compose آن را به صورت خودکار و به عنوان فایل دوم بارگذاری میکند.
ls compose.yaml compose.override.yaml
docker compose up -dهنگامی که هر دو فایل موجود باشند، نتیجه مشابه این است که آنها را بهصورت دستی در دستور وارد کرده باشید.
docker compose -f compose.yaml -f compose.override.yaml up -dنامهایی که Compose شناسایی میکند عبارتند از compose.override.yaml، compose.override.yml و نامهای قدیمیتر docker-compose.override.yml و docker-compose.override.yaml. هر نام دیگری، برای مثال compose.dev.yaml، تنها زمانی بارگذاری میشود که آن را با -f مشخص کنید.
به محض اینکه یک -f را وارد کنید، بارگذاری خودکار متوقف میشود. docker compose -f compose.yaml up دقیقاً همان یک فایل را میخواند و فایل override را نادیده میگیرد؛ این همان ویژگی است که الگوی توسعه (dev) و تولید (prod) در ادامه این راهنما بر پایه آن بنا شده است.
این موضوع در سرور میتواند هر دو نتیجه را داشته باشد. فایل override که در دایرکتوری deploy باقی مانده است، با هر فرمان بدون آرگومان docker compose که از همان دایرکتوری اجرا شود بارگذاری میشود؛ از جمله فرمانی که cron job شما اجرا میکند. به این ترتیب، یک stack production در نهایت دایرکتوری sourceای را با bind mount متصل میکند که قرار نبود کسی آن را منتشر کند. پس از هر deploy، docker compose config را اجرا کنید و خروجی آن را بخوانید. وقتی deploy بدون نظارت اجرا میشود، این بررسی فقط زمانی مفید است که چیزی به شما اطلاع دهد مشکلی رخ داده است. این وظیفه را یک کانال push مانند سرور ntfy خودمیزبان انجام میدهد که cron job یا یک unit از نوع systemd OnFailure میتواند به آن پیام ارسال کند.
ترتیب با -f و محل حل مسیرهای نسبی
Compose پیکربندی را به ترتیبی که فایلها را ارائه میدهید میسازد و فایلهای بعدی، فایلهای قبلی را بازنویسی کرده یا به آنها اضافه میشوند. از چپ به راست، آخرین فایل اولویت دارد.
docker compose -f compose.yaml -f compose.prod.yaml config
docker compose -f compose.yaml -f compose.prod.yaml up -dهر دستوری در آن پروژه به همان لیست فایل نیاز دارد. اگر up را با دو فایل و logs را با یک فایل اجرا کنید، در حال تعامل با یک مدل ادغامشدهٔ متفاوت هستید؛ این روشی سریع برای رسیدن به سرویسی است که Compose میگوید وجود ندارد. ریسک این کار در stackهایی که ارتقای آنها به صورت دستورات تکمرحلهای (one-off) انجام میشود، افزایش مییابد؛ برای مثال در مرحلهٔ مهاجرت دیتابیس در یک میز پشتیبانی Chatwoot خودمیزبان، اگر دستور docker compose run با لیست فایل اشتباه صادر شود، بیسروصدا مدلی متفاوت از آنچه سرویسهای شما در حال حاضر استفاده میکنند را هدف قرار میدهد. در عوض، لیست را یکبار با متغیر محیطی COMPOSE_FILE تنظیم کنید.
export COMPOSE_FILE=compose.yaml:compose.prod.yaml
docker compose config
docker compose up -dجداکننده در لینوکس : است و COMPOSE_PATH_SEPARATOR آن را تغییر میدهد. COMPOSE_FILE همچنین میتواند در فایل .env پروژه قرار بگیرد که باعث میشود بخشی از checkout باشد، نه بخشی از تاریخچهٔ shell شما. هر چیزی که صراحتاً در خط فرمان تنظیم شود، بر متغیر محیطی غلبه میکند.
حال قانونی که bind mountها را مختل میکند: هنگامی که از چندین فایل با -f استفاده میکنید، تمام مسیرهای نسبی در همهٔ آن فایلها نسبت به دایرکتوری اولین فایل حل میشوند، نه نسبت به فایلی که حاوی آنهاست. اگر ./data:/var/lib/postgresql/data را داخل deploy/prod/compose.prod.yaml بنویسید، Compose همچنان به دنبال ./data در کنار فایل پایه میگردد. سپس Docker یک دایرکتوری خالی در آن مسیر اشتباه ایجاد میکند و container بدون هیچ محتوایی شروع به کار میکند؛ این وضعیت شبیه به از دست رفتن داده است اما در واقع چنین نیست. برای تنظیم دستی مسیر پایه، --project-directory را ارسال کنید یا از include استفاده کنید که هر فایل را نسبت به دایرکتوری خودش حل میکند.
نام پروژه از همان دایرکتوری پایه گرفته میشود، بنابراین تغییر فایلی که در ابتدا قرار دارد میتواند نام پروژه را تغییر دهد. تغییر نام پروژه به معنای نامهای جدید برای containerها و volumeها است و volume قدیمی همچنان با نام قبلی روی دیسک باقی میماند. به جای آن، با استفاده از یک name: در سطح بالا در فایل پایه، آن را ثابت کنید.
name: myappکدام فیلدها ادغام و کدامیک جایگزین میشوند
Compose ادغام را بر اساس نوع مقدار انجام میدهد، نه نام فیلد.
- فیلدهای تکمقداری جایگزین میشوند.
image،command،entrypointوmem_limitمقدار بعدی را بهطور کامل جایگزین مقدار قبلی میکنند. شما نمیتوانید یک آرگومان را بهcommandاضافه کنید، زیرا override کل خط را بازنویسی میکند. - نگاشتها (Mappings) کلید به کلید ادغام میشوند.
environment،labels،volumesوdevicesتمام کلیدها را از هر دو فایل حفظ میکنند و در صورت وجود کلید مشترک در هر دو فایل، مقدار فایل دوم اولویت دارد. برایenvironmentوlabels، کلید همان نام متغیر یا برچسب (label) است. برایvolumesوdevices، کلید همان مسیر داخل container است. - دنبالهها (Sequences) به یکدیگر متصل میشوند.
dns،dns_search،expose،tmpfsوexternal_linksبه هم الحاق میشوند. یک فایل پایه که حاویexpose: ["3000"]است، پس از ادغام با یک override که حاوی["4000", "5000"]است، نتیجهای شامل["3000", "4000", "5000"]ایجاد میکند.
چهار دنباله دارای یک کلید شناسایی هستند، بنابراین ورودیهایی که با آن کلید مطابقت دارند، بهجای الحاق شدن، با هم ادغام میشوند. volumes، secrets و configs بر اساس target مطابقت داده میشوند. ports بر اساس ترکیب ip، target، published و protocol مطابقت داده میشود.
این قانون ports را دو بار بخوانید، زیرا این همان جایی است که ممکن است دچار اشتباه شوید. دو ورودی پورت تنها زمانی یک ورودی واحد محسوب میشوند که هر چهار بخش آنها با هم مطابقت داشته باشند. اگر حتی یکی از آنها را تغییر دهید، Compose آن را به عنوان یک پورت دوم و نامرتبط میبیند و هر دو را حفظ میکند.
چرا پورت شما پس از override همچنان منتشر میشود
یک فایل پایه که سرویس را روی تمام رابطها منتشر میکند:
services:
web:
image: nginx:1.27
ports:
- "8080:80"یک override که برای bind کردن آن فقط روی localhost نوشته شده است، زیرا قرار است یک reverse proxy جلوی آن قرار بگیرد:
services:
web:
ports:
- "127.0.0.1:8080:80"پیش از آنکه فرض کنید تنظیمات اعمال شده است، نتیجه را بررسی کنید.
docker compose -f compose.yaml -f compose.prod.yaml configهر دو ورودی در خروجی ظاهر میشوند. بخش ip متفاوت است، 0.0.0.0 در مقابل 127.0.0.1، بنابراین از نظر فرآیند ادغام (merge)، اینها دو پورت متفاوت هستند و binding عمومی که سعی داشتید حذف کنید، همچنان در مدل باقی مانده است. این موضوع در Docker اهمیت بیشتری نسبت به سایر موارد دارد، زیرا پورت منتشرشده پیش از قوانین فایروال شما در iptables نوشته میشود. این مکانیزم در چرا پورتهای منتشرشده Docker از ufw عبور میکنند پوشش داده شده است.
دو راه حل وجود دارد. راه حل صریح، استفاده از تگ !override است که کل ویژگی را جایگزین کرده و از قوانین ادغام صرفنظر میکند:
services:
web:
ports: !override
- "127.0.0.1:8080:80"!override به نسخه Compose v2.24.4 یا جدیدتر نیاز دارد. راه حل قابلحمل نیازی به هیچ تگی ندارد: ports را بهطور کامل از فایل پایه حذف کنید و آن را فقط در فایلهای مخصوص محیط (environment-specific) تعریف کنید. وقتی چیزی برای ادغام وجود نداشته باشد، چیزی هم نشت نمیکند. این همان الگویی است که در مثال عملی زیر استفاده شده است.
حذف یک مقدار از مجموعه فایل پایه
!reset یک ویژگی را حذف میکند و آن را به مقدار پیشفرض یا null بازمیگرداند. این دستور یک مقدار را میگیرد اما از آن صرفنظر میکند، بنابراین یک مقدار معتبر و خالی بنویسید.
services:
web:
ports: !reset []
environment:
DEBUG: !reset null!reset روی Compose v2.18.0 یا جدیدتر کار میکند، یعنی چندین نسخه پیش از آنکه !override ارائه شود. زمانی از آن استفاده کنید که فایل پایه متعلق به شما نیست و امکان ویرایش آن را ندارید؛ برای مثال، یک قطعهکد (fragment) از فروشنده که آن را دریافت میکنید. یک استک منتشرشده توسط توسعهدهنده اصلی دقیقاً همین مورد است: فایل Compose مربوط به یک فضای کاری AFFiNE خودمیزبان چهار کانتینر را تعریف میکند که شما آنها را ننوشتهاید، و !reset به شما اجازه میدهد یک ویژگی را در یکی از آنها پاک کنید، بدون اینکه نیاز باشد فایل را fork کنید و مسئولیت پیگیری تغییرات آن را بر عهده بگیرید.
استفاده از include برای پشتههایی که از بخشهای مختلف تشکیل شدهاند
include یک برنامه Compose دیگر را به مدل شما وارد میکند. این یک عنصر سطح بالا (top-level) است، نه یک flag.
include:
- path: ../commons/compose.yamlهر مسیر در include بهعنوان یک مدل برنامه Compose مستقل بارگذاری میشود که دایرکتوری پروژه خاص خود را دارد؛ بنابراین مسیرهای نسبی درون آن فایل، نسبت به دایرکتوری همان فایل حل میشوند. این تفاوت اصلی با -f است و به همین دلیل include ابزار مناسبی برای زمانی است که قطعه کد (fragment) در پوشه یا مخزن دیگری قرار دارد. این ساختار معمولاً برای پشتههای آماده (vendor stack) که خودتان ننوشتهاید استفاده میشود: فایل Compose چندسرویسی که در نصب Authentik SSO بهصورت self-hosted وجود دارد، میتواند در دایرکتوری خودش با مسیرهای نسبی دستنخورده باقی بماند، در حالی که فایل شما فقط بر سرویسهای خودتان تمرکز دارد.
شکل طولانی این دستور، زیرگزینههایی را میپذیرد.
include:
- path:
- ../monitoring/compose.yaml
- ../monitoring/compose.vps.yaml
project_directory: ../monitoring
env_file: ../monitoring/.envpath یک لیست را میپذیرد و آن فایلها طبق قوانین معمول با هم ادغام میشوند تا نتیجه به مدل شما اضافه شود. project_directory مسیر پایه مورد استفاده برای حل مسیرهای نسبی در فایل واردشده را تعیین میکند. env_file فایلی را مشخص میکند که فایل Compose واردشده، مقادیر پیشفرض interpolation خود را از آن میگیرد. این گزینه بهصورت پیشفرض از .env در دایرکتوری پروژه همان فایل استفاده میکند و محیط پروژه محلی شما همچنان بر آن اولویت دارد؛ این همان روشی است که میتوانید بدون ویرایش قطعه کد، یکی از متغیرهای آن را بازنویسی (override) کنید. include به نسخه Compose v2.20.0 یا جدیدتر نیاز دارد. همین گزینهها برای افزودن یک add-on تککانتینری به پشتهای که در حال حاضر اجرا میکنید مناسب هستند؛ برای مثال Halcyon که ظاهر کتابخانه Jellyfin را به یک فروشگاه کرایه فیلم دهه 90 تغییر میدهد: فایل آن، تگ image و env_file خاص خود را حفظ میکند، بنابراین ارتقای آن هرگز به معنای دستکاری فایلی که پشته رسانهای شما در آن قرار دارد، نیست.
مستندات Docker میگوید اگر نام یک منبع هم در فایل شما و هم در فایل واردشده اعلام شود، به دلیل تداخل رد میشود. اما loader در نسخه فعلی این کار را انجام نمیدهد: تا نسخه Compose v5.6.1، که در تاریخ 2026-10-27 بر اساس سورسکد loader بررسی شد، این دو تعریف را با هم ادغام میکند و در صورت وجود تداخل، مقدار موجود در فایل شما برنده میشود، بهجای اینکه با خطا متوقف شود. بنابراین روی این حساب نکنید که نام تکراری باعث بروز خطای واضح شود. برای تغییر چیزی که یک فایل واردشده اعلام کرده است، تغییر را در compose.override.yaml قرار دهید: این بازنویسی روی مدل نهایی اعمال میشود، بنابراین تغییر صریح است و به نحوه برخورد یک نسخه خاص با تداخلها بستگی ندارد. این عادت بهویژه برای پشتههایی که فایل upstream آنها در هر نسخه بازنویسی میشود، بسیار مفید است؛ مانند سرورهای عکس چندکانتینری که در مقایسه PhotoPrism و Immich بررسی شدند، جایی که binding روی localhost یا یک volume اضافی باید در فایل override شما باشد، نه در فایلی که در ارتقای بعدی جایگزین خواهد شد.
خلاصه مطلب: include برنامههای جداگانه را ترکیب میکند، -f پیکربندی را روی یک برنامه لایهبندی میکند.
جداسازی محیط توسعه و عملیاتی روی یک VPS
الگوی کامل این کار در سه فایل زیر آمده است. فایل پایه، آنچه را که در همه جا صادق است تعریف میکند و هیچ پورتی را منتشر نمیکند.
name: myapp
services:
app:
image: ghcr.io/example/app:1.4.2
environment:
DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@db:5432/app
LOG_LEVEL: info
depends_on:
db:
condition: service_healthy
restart: unless-stopped
db:
image: postgres:16
environment:
POSTGRES_USER: app
POSTGRES_DB: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
volumes:
db_data:شرط depends_on باعث میشود برنامه بهجای انتظار برای صرفاً وجود یک کانتینر، منتظر دیتابیسی بماند که واقعاً پاسخگو باشد؛ توضیحات بیشتر در healthchecks and depends_on conditions آمده است. مقدار POSTGRES_PASSWORD از فایل .env پروژه جایگذاری میشود که نباید هرگز در git قرار گیرد. برای روشهای امنتر، env files and Compose secrets را ببینید.
سپس فایل compose.override.yaml قرار دارد که Compose بهصورت خودکار آن را بارگذاری میکند. این فایل مخصوص توسعهدهنده است.
services:
app:
build: .
command: npm run dev
environment:
LOG_LEVEL: debug
ports:
- "3000:3000"
volumes:
- ./src:/app/src
db:
ports:
- "127.0.0.1:5432:5432"روی لپتاپ، یک دستور ساده docker compose up این دو فایل را با هم ادغام میکند. مقدار command جایگزین پیشفرض image میشود زیرا یک مقدار واحد است. مقدار LOG_LEVEL جایگزین info میشود زیرا environment بر اساس کلید ادغام میشود. bind mount و دو پورت منتشرشده، صرفاً افزودنی هستند و پورت دیتابیس به localhost محدود شده است تا لپتاپ در یک شبکه مشترک، سرویس PostgreSQL را در دسترس دیگران قرار ندهد.
در نهایت، فایل compose.prod.yaml قرار دارد. نام این فایل بهگونهای نیست که Compose بهطور خودکار آن را جستجو کند، بنابراین هرگز بهاشتباه بارگذاری نمیشود.
services:
app:
ports:
- "127.0.0.1:8000:3000"
deploy:
resources:
limits:
memory: 512Mروی VPS شما هر دو فایل را نام میبرید و همین نامگذاری دقیقاً باعث میشود فایل override نادیده گرفته شود.
docker compose -f compose.yaml -f compose.prod.yaml config
docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose -f compose.yaml -f compose.prod.yaml psدستور ps باید هر دو سرویس را در حال اجرا نشان دهد و db مقدار (healthy) را نمایش دهد. از آنجا که شما -f را ارسال کردید، فایل compose.override.yaml خوانده نشد؛ بنابراین دستور توسعه، source bind mount و پورت عمومی 3000 نمیتوانند به محیط عملیاتی نفوذ کنند، حتی اگر فایل در همان دایرکتوری موجود باشد. پورت 8000 فقط روی localhost در دسترس است و برای یک پروکسی آماده است: هنگام افزودن سرویس دوم، running several apps behind Traefik را ببینید.
مقدار COMPOSE_FILE=compose.yaml:compose.prod.yaml را در فایل .env سرور تنظیم کنید تا بقیه دستورات شما دوباره به حالت ساده docker compose logs -f app بازگردند.
یک استک تکسرویسی نیز همین ساختار را میطلبد، زیرا a self-hosted openGym workout tracker باید پیش از ثبت اولین passkey، از طریق TLS و پشت یک پروکسی پاسخگو باشد. یک فایل پایه بدون ports در آن، همان چیزی است که مانع از آن میشود که یک binding عمومی ناخواسته، پیش از پروکسی، درخواستها را دریافت کند.
پیش از استقرار، مدل ادغامشده را مطالعه کنید
docker compose config مدل کاملاً ادغامشده و درونیابیشده را چاپ میکند. این یک پیشنمایش نیست. این دقیقاً همان ورودی است که Compose بر اساس آن عمل خواهد کرد؛ بنابراین اگر خروجی با انتظارات شما مغایرت دارد، خروجی صحیح است.
docker compose -f compose.yaml -f compose.prod.yaml config
docker compose -f compose.yaml -f compose.prod.yaml config --no-interpolate
docker compose -f compose.yaml -f compose.prod.yaml config --services--no-interpolate باعث میشود ${VAR} گسترش نیابد. پیش از کپی کردن خروجی در هر جایی از این گزینه استفاده کنید، زیرا config ساده، تمام secretهای حلشده را به صورت متن ساده (clear text) چاپ میکند. --services فقط نام سرویسها را فهرست میکند که روشی سریع برای تأیید این است که یک include، آنچه انتظار داشتید را فراخوانی کرده است.
حالتهای شکست و آنچه مشاهده خواهید کرد
no configuration file provided: not found. ابزار Compose فایلی برای خواندن پیدا نکرد. شما خارج از دایرکتوری پروژه هستید یا COMPOSE_FILE به مسیری اشاره میکند که وجود ندارد. Compose برای یافتن فایل پایه پیشفرض، دایرکتوریهای والد را جستجو میکند، اما برای فایلی که خودتان نامگذاری کردهاید، هیچ جستجویی انجام نمیدهد.
WARN[0000] The "POSTGRES_PASSWORD" variable is not set. Defaulting to a blank string. درونیابی (Interpolation) بر اساس فایل .env پروژه و محیط shell انجام میشود و دایرکتوری پروژه در اینجا، همان دایرکتوری اولین فایل -f است. استقرار از دایرکتوری متفاوت با دایرکتوری حاوی .env، این هشدار را به شما میدهد و در نتیجه دیتابیسی خواهید داشت که تمام اتصالات را رد میکند.
ویرایش override شما در docker compose config نمایش داده نمیشود. یا شما فلگ -f را ارسال کردهاید که بارگذاری خودکار override را غیرفعال میکند، یا Compose فایل compose.yaml را در یک دایرکتوری والد پیدا کرده و فایل override شما در کنار آن قرار ندارد. اجرای docker compose config بدون هیچ آرگومان دیگری به شما میگوید که Compose واقعاً در حال ساخت چه مدلی است.
یک bind mount خالی است و Docker دایرکتوریای ایجاد کرده که شما درخواست نکردهاید. مسیر نسبی بر اساس دایرکتوری اولین فایل حل شده است. مسیر را اصلاح کنید، --project-directory را ارسال کنید یا قطعه کد را به پشت include منتقل کنید.
کانتینرها با نامهای جدید بازمیگردند و یک volume خالی به نظر میرسد. نام پروژه تغییر کرده است، زیرا نام پروژه از دایرکتوری اولین فایل پیروی میکند. یک name: در سطح بالا به فایل پایه اضافه کنید تا نامگذاری ثابت بماند. volume قدیمی همچنان با پیشوند قبلی موجود است و docker volume ls آن را نشان خواهد داد.
پورتی که در override حذف کردهاید همچنان باز است. ادغام ports به جای جایگزینی، عمل الحاق (append) را انجام داده است. با docker compose config تأیید کنید، سپس یا از !override استفاده کنید یا ports را از فایل پایه خارج کنید.
FAQ
آیا Compose فایل compose.override.yaml را بهطور خودکار بارگذاری میکند؟
بله، زمانی که docker compose را بدون هیچ فلگ -f اجرا میکنید. Compose در دایرکتوری جاری و دایرکتوریهای والد آن به دنبال compose.yaml یا docker-compose.yaml میگردد و اگر یک فایل override در کنار آن وجود داشته باشد، آن فایل به عنوان دومین فایل بارگذاری میشود. نامهای شناختهشده عبارتند از compose.override.yaml، compose.override.yml، docker-compose.override.yml و docker-compose.override.yaml. ارسال هرگونه -f این قابلیت را غیرفعال میکند، بنابراین docker compose -f compose.yaml up فقط یک فایل را میخواند.
فایلهای چندگانه -f با چه ترتیبی ادغام میشوند؟
از چپ به راست. Compose پیکربندی را به ترتیبی که فایلها را ارائه میدهید میسازد و هر فایل، تنظیمات فایلهای قبلی را بازنویسی یا به آنها اضافه میکند؛ بنابراین آخرین فایل در خط دستور، در صورت بروز تداخل، اولویت دارد. برای هر دستور در آن پروژه باید از همان لیست استفاده شود که هدف اصلی COMPOSE_FILE=compose.yaml:compose.prod.yaml نیز همین است.
چرا پورت من پس از override کردن همچنان منتشر (publish) است؟
زیرا ورودیهای ports توسط مجموعه کامل ip، target، published و protocol شناسایی میشوند. یک override برای 127.0.0.1:8080:80 در برابر یک پایه 8080:80، در بخش ip تفاوت دارد؛ بنابراین Compose آن را به عنوان یک پورت دوم در نظر میگیرد و هر دو را حفظ میکند. دستور docker compose config را اجرا کنید تا هر دو ورودی را مشاهده کنید. در نسخه Compose v2.24.4 یا جدیدتر از ports: !override استفاده کنید، یا ports را از فایل پایه حذف کنید تا چیزی برای ادغام وجود نداشته باشد.
تفاوت بین include و -f چیست؟
-f چندین فایل را روی یک برنامه لایهبندی میکند و تمام مسیرهای نسبی در هر فایل، نسبت به دایرکتوری اولین فایل حل میشوند. include یک برنامه Compose مجزا را فراخوانی میکند و هر مسیرِ include شده، دایرکتوری پروژه مخصوص به خود را حفظ میکند؛ بنابراین مسیرهای نسبی آن نسبت به خودش حل میشوند. برای لایههای محیطیِ استک خود از -f و برای قطعهکدهایی که در جای دیگری نگهداری میشوند از include استفاده کنید. include به نسخه Compose v2.20.0 یا جدیدتر نیاز دارد.
چگونه مقداری را که فایل پایه تنظیم کرده است حذف کنم؟
در نسخه Compose v2.18.0 یا جدیدتر از تگ !reset استفاده کنید. در فایل override عبارت ports: !reset [] یا MY_VAR: !reset null را بنویسید تا ویژگی مورد نظر به مقدار پیشفرض یا null بازگردد. مقداری که به تگ میدهید الزامی است اما نادیده گرفته میشود. اگر میخواهید به جای پاک کردن یک ویژگی، آن را جایگزین کنید، !override این کار را انجام میدهد و به نسخه v2.24.4 یا جدیدتر نیاز دارد.