SSD Nodes Learn Hosting plans →
تعلیمی Matt Connorتحریر: Matt Connor

Docker Compose میں متعدد فائلیں کیسے merge ہوتی ہیں؟

جانیں compose.override.yaml کب خود load ہوتی ہے، فائلوں کی ترتیب merge کو کیسے بدلتی ہے، ports list کے باعث پورٹ کیوں کھلا رہتا ہے، اور dev/prod split کے لیے include کب استعمال کریں۔

ایک سے زیادہ files کے ساتھ Compose کیا کرتا ہے

Docker Compose کئی files سے ایک project بنا سکتا ہے۔ یہ files کو موصول ہونے کی ترتیب سے پڑھتا ہے اور انہیں ایک model میں merge کرتا ہے، اس لیے بعد والی file ہر متصادم value پر ترجیح پاتی ہے۔ Command line سے ایسا کرنے کے دو mechanisms ہیں: ایک override file جسے Compose خود load کرتا ہے، اور -f flag جسے آپ خود فراہم کرتے ہیں۔ تیسرا mechanism خود file کے اندر موجود include element ہے، اور یہ دونوں سے مختلف طریقے سے کام کرتا ہے۔

Merge صرف سادہ overwrite نہیں ہوتا۔ Mappings key بہ key merge ہوتی ہیں، sequences میں items append ہوتے ہیں، اور چند مخصوص fields مکمل طور پر replace ہوتے ہیں۔ حیرت انگیز نتائج اسی فرق کی وجہ سے سامنے آتے ہیں، اور ports list وہ حصہ ہے جو تقریباً سب کو الجھا دیتا ہے۔

ذیل کی تمام باتیں Compose v2 یا اس کے بعد کے versions، یعنی پرانے docker-compose script کے بجائے docker compose plugin، کو فرض کرتی ہیں۔ موجودہ releases کو v5 کے طور پر number کیا جاتا ہے، اور plugin اسی طرح کام کرتا ہے۔ جانچنے کے لیے docker compose version چلائیں۔ اگر آپ نے ابھی تک Compose file نہیں لکھی تو Docker Compose کی بنیادیات کی رہنما سے شروع کریں اور پھر واپس آئیں۔

وہ override فائل جسے Compose بتائے بغیر load کرتا ہے

docker compose up کو -f flag کے بغیر چلانے پر Compose working directory اور پھر اس کی parent directories میں compose.yaml یا docker-compose.yaml تلاش کرتا ہے۔ اگر override فائل base فائل کے ساتھ موجود ہو تو Compose اسے خود بخود دوسری فائل کے طور پر load کر لیتا ہے۔

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، صرف اسی وقت load ہوتا ہے جب آپ اسے -f کے ذریعے نامزد کریں۔

جیسے ہی آپ ایک -f فراہم کرتے ہیں، خودکار loading رک جاتی ہے۔ docker compose -f compose.yaml up صرف اسی ایک فائل کو پڑھتا ہے اور override کو نظر انداز کرتا ہے۔ اسی خاصیت کی بنیاد پر اس guide میں بعد میں dev اور prod pattern بنایا گیا ہے۔

سرور پر اس کے دونوں طرح کے اثرات ہو سکتے ہیں۔ deploy directory میں موجود override فائل اس directory سے چلائے جانے والے ہر سادہ docker compose command کے ذریعے load ہوتی ہے، جس میں cron job چلانے والا command بھی شامل ہے۔ اسی طرح production stack میں ایسی source directory bind-mount ہو سکتی ہے جسے شامل کرنے کا کسی کا ارادہ نہیں تھا۔ ہر deploy کے بعد docker compose config چلائیں اور اس کا output پڑھیں۔ جب deploy unattended ہو تو یہ check صرف اسی صورت میں مفید ہے جب کوئی آپ کو خرابی سے آگاہ کرے۔ یہی کام self-hosted ntfy server جیسے push channel کا ہے، جس پر cron job یا systemd OnFailure unit post کر سکتی ہے۔

-f کے ساتھ ترتیب اور نسبتاً paths کے resolve ہونے کی جگہ

Compose configuration کو ان files کی فراہم کردہ ترتیب کے مطابق بناتا ہے۔ بعد والی files اپنی پیش رو files کی settings کو override کرتی ہیں اور نئی settings شامل کرتی ہیں۔ بائیں سے دائیں چلیں؛ آخری setting نافذ ہوتی ہے۔

docker compose -f compose.yaml -f compose.prod.yaml config
docker compose -f compose.yaml -f compose.prod.yaml up -d

اس project میں ہر command کو files کی یہی فہرست درکار ہوتی ہے۔ up کو دو files کے ساتھ اور logs کو ایک file کے ساتھ چلانے سے آپ ایک مختلف merged model کے ساتھ کام کر رہے ہوتے ہیں۔ یہ ایسی service حاصل کرنے کا تیز طریقہ ہے جس کے بارے میں Compose کہتا ہے کہ وہ موجود نہیں۔ مسئلہ اس stack میں زیادہ سنگین ہو جاتا ہے جس کی upgrades one-off commands کے ذریعے چلتی ہیں، مثلاً self-hosted Chatwoot support desk میں database migration step، جہاں غلط file list کے ساتھ جاری کیا گیا docker compose run خاموشی سے اس model کو target کرتا ہے جو آپ کی services پہلے سے استعمال نہیں کر رہیں۔ اس کے بجائے فہرست ایک بار COMPOSE_FILE environment variable کے ذریعے مقرر کریں۔

export COMPOSE_FILE=compose.yaml:compose.prod.yaml
docker compose config
docker compose up -d

Linux پر separator : ہے، جبکہ COMPOSE_PATH_SEPARATOR اسے تبدیل کرتا ہے۔ COMPOSE_FILE کو project کی .env file میں بھی رکھا جا سکتا ہے۔ اس طرح یہ آپ کی shell history کے بجائے checkout کا حصہ بن جاتا ہے۔ Command line پر واضح طور پر set کی گئی value environment variable پر فوقیت رکھتی ہے۔

اب اس rule پر غور کریں جو bind mounts کو خراب کر دیتا ہے۔ جب آپ -f کے ساتھ متعدد files استعمال کرتے ہیں تو ان تمام files میں موجود relative paths اس file والی directory کے مطابق resolve ہوتے ہیں جو فہرست میں پہلی ہے، نہ کہ اس file والی directory کے مطابق جس میں path لکھا گیا ہے۔ deploy/prod/compose.prod.yaml کے اندر ./data:/var/lib/postgresql/data لکھنے کے باوجود Compose ./data کو base file کے ساتھ والی directory میں تلاش کرتا ہے۔ Docker پھر اس غلط path پر ایک empty directory بنا دیتا ہے، اور container اس میں موجود data کے بغیر start ہوتا ہے۔ یہ data loss جیسا دکھائی دیتا ہے، لیکن data loss نہیں ہوتا۔ Base path خود مقرر کرنے کے لیے --project-directory دیں، یا include استعمال کریں، جو ہر file کو اس کی اپنی directory کے مطابق resolve کرتا ہے۔

Project name بھی اسی base directory سے حاصل ہوتا ہے۔ اس لیے پہلی file تبدیل کرنے سے project کا نام تبدیل ہو سکتا ہے۔ نئے project name کا مطلب نئے container names اور نئے volume names ہیں، جبکہ پرانا volume پرانے نام کے تحت disk پر موجود رہتا ہے۔ Base file میں top-level name: کے ذریعے project name کو مستقل مقرر کریں۔

name: myapp

کون سے fields merge ہوتے ہیں، اور کون سے replace ہوتے ہیں

Compose value کی type کے مطابق merge کرتا ہے، field کے نام کے مطابق نہیں۔

  • Single-valued fields replace ہوتے ہیں۔ image، command، entrypoint اور mem_limit بعد والی value کو مکمل طور پر اختیار کرتے ہیں۔ command میں ایک argument append نہیں کیا جا سکتا، کیونکہ override پوری line کو دوبارہ لکھ دیتا ہے۔
  • Mappings key کے لحاظ سے merge ہوتے ہیں۔ environment، labels، volumes اور devices دونوں files کی تمام keys برقرار رکھتے ہیں، اور جو key دونوں میں موجود ہو اس کے لیے بعد والی file کی value استعمال ہوتی ہے۔ environment اور labels میں key variable یا label کا نام ہوتی ہے۔ volumes اور devices میں key container path ہوتی ہے۔
  • Sequences append ہوتے ہیں۔ dns، dns_search، expose، tmpfs اور external_links کو باہم جوڑا جاتا ہے۔ expose: ["3000"] رکھنے والی base file کو ["4000", "5000"] رکھنے والے override کے ساتھ merge کرنے سے ["3000", "4000", "5000"] حاصل ہوتا ہے۔

چار sequences میں identity key ہوتی ہے، اس لیے اس key سے match ہونے والی entries append ہونے کے بجائے merge ہوتی ہیں۔ volumes، secrets اور configs میں match target کی بنیاد پر ہوتا ہے۔ ports میں match ip، target، published اور protocol کے مجموعے کی بنیاد پر ہوتا ہے۔

اس ports rule کو دو بار پڑھیں، کیونکہ یہی عام غلطی کا مقام ہے۔ دو port entries اسی وقت ایک ہی entry سمجھی جاتی ہیں جب ان چاروں حصوں کی values یکساں ہوں۔ ان میں سے کسی ایک کو تبدیل کریں تو Compose اسے دوسری، غیر متعلقہ port سمجھتا ہے، اس لیے دونوں entries برقرار رہتی ہیں۔

اووررائٹ کے بعد بھی port شائع کیوں ہے

بنیادی file جو service کو ہر interface پر publish کرتی ہے:

services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"

ایسی override جو اسے صرف localhost پر bind کرنے کے لیے لکھی گئی ہے، کیونکہ اس کے سامنے reverse proxy کام کرے گا:

services:
  web:
    ports:
      - "127.0.0.1:8080:80"

یہ فرض کرنے سے پہلے کہ تبدیلی مؤثر ہو گئی ہے، نتیجہ چیک کریں۔

docker compose -f compose.yaml -f compose.prod.yaml config

آؤٹ پٹ میں دونوں entries موجود ہیں۔ ip والا حصہ مختلف ہے، یعنی 0.0.0.0 کے مقابلے میں 127.0.0.1، اس لیے merge کے لحاظ سے یہ دو مختلف ports ہیں، اور جس public binding کو آپ نے ہٹانے کی کوشش کی تھی وہ اب بھی model میں موجود ہے۔ Docker میں یہ مسئلہ دیگر صورتوں کے مقابلے میں زیادہ اہم ہے، کیونکہ published port آپ کے firewall rules سے پہلے iptables میں شامل کر دیا جاتا ہے۔ اس طریقۂ کار کی وضاحت published Docker ports، ufw سے آگے کیوں گزر جاتے ہیں میں کی گئی ہے۔

اس کے دو حل ہیں۔ واضح حل !override tag ہے، جو مکمل attribute کو replace کرتا ہے اور merge rules کو نظرانداز کرتا ہے:

services:
  web:
    ports: !override
      - "127.0.0.1:8080:80"

!override کے لیے Compose v2.24.4 یا اس کے بعد کا ورژن درکار ہے۔ portable حل کے لیے کسی tag کی ضرورت نہیں: ports کو base file سے مکمل طور پر خارج رکھیں اور اسے صرف environment-specific files میں declare کریں۔ Merge کرنے کے لیے کچھ موجود نہ ہو تو leak ہونے کے لیے بھی کچھ نہیں ہوتا۔ نیچے دی گئی عملی مثال میں یہی pattern استعمال کیا گیا ہے۔

بنیادی فائل میں متعین قدر حذف کرنا

!reset کسی attribute کو ہٹا کر اسے اس کی default قدر یا null پر واپس لے آتا ہے۔ یہ ایک قدر قبول کرتا ہے اور اسے نظرانداز کر دیتا ہے، اس لیے کوئی درست مگر خالی قدر لکھیں۔

services:
  web:
    ports: !reset []
    environment:
      DEBUG: !reset null

!reset Compose v2.18.0 یا اس کے بعد کے ورژنز پر کام کرتا ہے، جبکہ !override اس سے کئی releases بعد متعارف ہوا۔ اسے اس وقت استعمال کریں جب بنیادی فائل میں ترمیم کرنا آپ کے اختیار میں نہ ہو، مثلاً جب آپ کسی vendor fragment کو شامل کر رہے ہوں۔ شائع شدہ upstream stack اس کی واضح مثال ہے: self-hosted AFFiNE workspace کے پیچھے موجود Compose فائل میں چار ایسے containers متعین ہیں جو آپ نے نہیں لکھے۔ !reset کی مدد سے آپ فائل کو fork کیے بغیر ان میں سے کسی ایک کے کسی ایک attribute کو صاف کر سکتے ہیں، اور اس فائل کو track کرنے کی اضافی ذمہ داری بھی نہیں لینی پڑتی۔

اجزا سے تیار کردہ stacks کے لیے include

include ایک اور Compose application کو آپ کے model میں شامل کرتا ہے۔ یہ top-level element ہے، flag نہیں۔

include:
  - path: ../commons/compose.yaml

include میں موجود ہر path کو اپنی الگ Compose application model کے طور پر load کیا جاتا ہے، اور اس کی اپنی project directory ہوتی ہے۔ اس لیے اس file کے اندر relative paths اسی file کی اپنی directory کے مطابق resolve ہوتے ہیں۔ یہی -f کے ساتھ اصل فرق ہے، اور اسی وجہ سے include اس وقت درست tool ہے جب fragment کسی دوسرے folder یا repository میں موجود ہو۔ یہ عموماً ایسے vendor stack کی صورت ہوتی ہے جسے آپ نے خود نہیں لکھا: self-hosted Authentik SSO installation کے پیچھے موجود multi-service Compose file اپنی directory میں رہ سکتی ہے اور اس کے relative paths برقرار رہتے ہیں، جبکہ آپ کی file صرف آپ کی اپنی services سے متعلق رہتی ہے۔

Long form میں sub-options شامل ہوتے ہیں۔

include:
  - path:
      - ../monitoring/compose.yaml
      - ../monitoring/compose.vps.yaml
    project_directory: ../monitoring
    env_file: ../monitoring/.env

path ایک list قبول کرتا ہے، اور result کو آپ کے model میں شامل کرنے سے پہلے ان files کو معمول کے rules کے مطابق merge کیا جاتا ہے۔ project_directory شامل کی گئی file میں relative paths resolve کرنے کے لیے استعمال ہونے والا base path مقرر کرتا ہے۔ env_file اس file کا نام بتاتا ہے جس سے شامل کی گئی Compose file اپنے interpolation defaults حاصل کرتی ہے۔ یہ پہلے ہی اس file کی اپنی project directory میں موجود .env پر default ہوتا ہے، اور آپ کے local project کا environment پھر بھی اس پر ترجیح رکھتا ہے۔ اسی طرح آپ fragment میں ترمیم کیے بغیر اس کے کسی variable کو override کر سکتے ہیں۔ include کے لیے Compose v2.20.0 یا اس کے بعد کا version درکار ہے۔ یہی options کسی ایسے stack میں single-container add-on شامل کرنے کے لیے بھی موزوں ہیں جسے آپ پہلے سے چلا رہے ہوں، مثلاً Halcyon، جو Jellyfin library کو 90s کے rental store کی شکل دیتا ہے۔ اس کی file اپنا image tag اور اپنا env_file برقرار رکھتی ہے، اس لیے اسے upgrade کرنے کے لیے آپ کے media stack والی file میں ترمیم نہیں کرنی پڑتی۔

Docker کی documentation کے مطابق، اگر آپ کی file اور شامل کی گئی file دونوں میں ایک ہی resource name declare ہو تو اسے conflict کے طور پر reject کیا جاتا ہے۔ موجودہ release میں loader ایسا نہیں کرتا: Compose v5.6.0 کے مطابق، جسے 2026-10-11 کو check کیا گیا، یہ دونوں definitions کو merge کرتا ہے۔ کسی متصادم value کی صورت میں آپ کی file کو ترجیح ملتی ہے، اور loader error کے ساتھ رکنے کے بجائے آگے بڑھتا ہے۔ اس لیے duplicate name کے باعث واضح failure پر انحصار نہ کریں۔ شامل کی گئی file میں declared کسی چیز کو تبدیل کرنے کے لیے تبدیلی compose.override.yaml میں رکھیں۔ Override assembled model پر apply ہوتا ہے، اس لیے تبدیلی واضح رہتی ہے اور اس بات پر منحصر نہیں ہوتی کہ کوئی مخصوص release اس clash کو کیسے handle کرتا ہے۔ یہ طریقہ خاص طور پر ایسے stack کے ساتھ مفید ہے جس کی upstream file ہر release میں دوبارہ لکھی جاتی ہو، جیسے PhotoPrism بمقابلہ Immich میں زیرِ جائزہ multi-container photo servers۔ ایسی صورت میں localhost binding یا اضافی volume کو override میں رکھیں، اس file میں نہیں جسے اگلا upgrade replace کر دے گا۔

مختصر طور پر: include الگ applications کو compose کرتا ہے، جبکہ -f ایک application پر configuration کی تہیں چڑھاتا ہے۔

ایک VPS پر dev اور prod کی علیحدگی

یہ مکمل طریقہ کار 3 فائلوں میں ہے۔ base فائل ہر جگہ درست configuration بیان کرتی ہے، اور کوئی port publish نہیں کرتی۔

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 شرط کی وجہ سے app ایسے database کا انتظار کرتی ہے جو جواب دے رہا ہو، نہ کہ صرف موجود container کا۔ اس کی وضاحت healthchecks اور depends_on conditions میں ہے۔ POSTGRES_PASSWORD کو project کی .env فائل سے interpolate کیا جاتا ہے، اور یہ فائل کبھی git میں شامل نہیں ہونی چاہیے۔ محفوظ متبادل کے لیے env files اور Compose secrets دیکھیں۔

اس کے بعد compose.override.yaml ہے، جسے Compose خود load کرتا ہے۔ یہ developer کی فائل ہے۔

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"

laptop پر سادہ docker compose up ان دونوں فائلوں کو merge کرتا ہے۔ command image default کو replace کرتا ہے کیونکہ اس کی صرف ایک value ہوتی ہے۔ LOG_LEVEL، info کو replace کرتا ہے کیونکہ environment key کے لحاظ سے merge کرتا ہے۔ bind mount اور publish کیے گئے دونوں ports خالص اضافے ہیں، جبکہ database port کو localhost سے bind کیا گیا ہے تاکہ shared network پر موجود کوئی دوسرا laptop PostgreSQL کو network پر دستیاب نہ دیکھ سکے۔

آخر میں compose.prod.yaml ہے۔ اس کا نام ان ناموں میں شامل نہیں جنہیں Compose تلاش کرتا ہے، اس لیے یہ کبھی اتفاقاً load نہیں ہوتی۔

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 کو دونوں services کو running دکھانا چاہیے، اور db میں (healthy) نظر آنا چاہیے۔ چونکہ آپ نے -f دیا تھا، اس لیے compose.override.yaml نہیں پڑھی گئی۔ چنانچہ dev command، source bind mount اور public port 3000 production تک نہیں پہنچ سکتے، حالانکہ فائل اسی directory میں موجود ہے۔ Port 8000 صرف localhost پر ہے اور proxy کے لیے تیار ہے۔ دوسری service شامل کرتے وقت Traefik کے پیچھے متعدد apps چلانا دیکھیں۔

سرور کی .env میں COMPOSE_FILE=compose.yaml:compose.prod.yaml مقرر کریں۔ اس کے بعد آپ کے باقی commands دوبارہ سادہ docker compose logs -f app بن جائیں گے۔

Single-service stack بھی یہی ساخت اختیار کرتا ہے، کیونکہ self-hosted openGym workout tracker کو پہلے passkey کا اندراج کرنے سے پہلے proxy کے پیچھے TLS کے ذریعے جواب دینا ہوتا ہے۔ ایسی base فائل، جس میں ports نہ ہو، stray public binding کو proxy سے پہلے درخواستیں سنبھالنے سے روکتی ہے۔

تعیناتی سے پہلے merged model پڑھیں

docker compose config مکمل merged اور interpolated model دکھاتا ہے۔ یہ preview نہیں ہے۔ یہی وہ exact input ہے جس پر Compose عمل کرے گا، اس لیے جب output آپ کی توقع سے مختلف ہو تو درست output ہی ہے۔

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} unexpanded حالت میں چھوڑ دیتا ہے۔ output کو کہیں paste کرنے سے پہلے اسے استعمال کریں، کیونکہ سادہ config ہر resolved secret کو clear text میں دکھاتا ہے۔ --services صرف service names کی فہرست بناتا ہے۔ اس سے فوری طور پر تصدیق ہو جاتی ہے کہ include نے مطلوبہ configuration شامل کی ہے۔

خرابی کی صورتیں اور آپ کو کیا نظر آئے گا

no configuration file provided: not found۔ Compose کو پڑھنے کے لیے کچھ نہیں ملا۔ آپ project directory سے باہر ہیں، یا COMPOSE_FILE ایسے path کی نشاندہی کرتا ہے جو موجود نہیں۔ Compose default base file تلاش کرنے کے لیے parent directories میں دیکھتا ہے، لیکن آپ کے بتائے ہوئے file کو تلاش کرنے کے لیے کسی بھی جگہ نہیں دیکھتا۔

WARN[0000] The "POSTGRES_PASSWORD" variable is not set. Defaulting to a blank string. Interpolation project کی .env file اور shell environment کے مطابق حل ہوتی ہے، اور یہاں project directory پہلی -f file کی directory ہے۔ .env رکھنے والی directory سے مختلف directory میں deployment کرنے پر یہ warning ظاہر ہوتی ہے، اور پھر database کسی بھی connection کو قبول نہیں کرتا۔

آپ کی override میں کی گئی ترمیم docker compose config میں ظاہر نہیں ہوتی۔ یا تو آپ نے -f دیا ہے، جس سے automatic override loading بند ہو جاتی ہے، یا Compose کو parent directory میں compose.yaml مل گئی ہے اور آپ کی override file اس کے ساتھ موجود نہیں۔ docker compose config کو کسی دوسرے argument کے بغیر چلانے سے معلوم ہوتا ہے کہ Compose حقیقت میں کون سا model بنا رہا ہے۔

bind mount خالی ہے اور Docker نے ایسی directory بنا دی ہے جس کی آپ نے درخواست نہیں کی تھی۔ Relative path پہلی file کی directory کے مطابق resolve ہوا۔ Path درست کریں، --project-directory دیں، یا fragment کو include کے پیچھے منتقل کریں۔

Containers نئے ناموں کے ساتھ واپس آتے ہیں اور volume خالی دکھائی دیتا ہے۔ Project name تبدیل ہو گیا، کیونکہ project name پہلی file کی directory کے مطابق ہوتا ہے۔ Base file میں top-level name: شامل کریں؛ اس سے نام تبدیل ہونا بند ہو جائے گا۔ پرانا volume اب بھی پرانے prefix کے تحت موجود ہے، اور docker volume ls اسے دکھا دے گا۔

Override میں ہٹایا گیا port اب بھی کھلا ہے۔ ports merge نے اسے replace کرنے کے بجائے append کر دیا۔ docker compose config سے تصدیق کریں، پھر یا تو !override استعمال کریں یا ports کو base file سے باہر منتقل کریں۔

FAQ

کیا Compose خودکار طور پر compose.override.yaml لوڈ کرتا ہے؟

جی ہاں، جب آپ docker compose کو -f flag کے بغیر چلاتے ہیں۔ Compose working directory اور اس کی parent directories میں compose.yaml یا docker-compose.yaml تلاش کرتا ہے۔ اگر override file اس کے ساتھ موجود ہو تو وہ file دوسرے نمبر پر load ہوتی ہے۔ تسلیم شدہ نام compose.override.yaml، compose.override.yml، docker-compose.override.yml اور docker-compose.override.yaml ہیں۔ کوئی بھی -f دینے سے یہ عمل غیر فعال ہو جاتا ہے، اس لیے docker compose -f compose.yaml up صرف ایک file پڑھتا ہے۔

متعدد -f files کس ترتیب سے merge ہوتی ہیں؟

بائیں سے دائیں۔ Compose آپ کی فراہم کردہ files کی ترتیب سے configuration بناتا ہے۔ ہر file اس سے پہلے والی files کی settings کو override کرتی ہے اور نئی settings شامل کرتی ہے۔ اس لیے line میں آخر میں موجود file ہر conflict میں غالب آتی ہے۔ اس project کی ہر command کے لیے یہی list استعمال ہونی چاہیے؛ اسی مقصد کے لیے COMPOSE_FILE=compose.yaml:compose.prod.yaml ہے۔

override کرنے کے بعد بھی میرا port publish کیوں ہے؟

کیونکہ ports entries کی شناخت ip، target، published اور protocol کے مکمل مجموعے سے ہوتی ہے۔ 8080:80 کی بنیاد پر 127.0.0.1:8080:80 کا override ip حصے میں مختلف ہے۔ اس لیے Compose اسے دوسرے port کے طور پر سمجھتا ہے اور دونوں برقرار رکھتا ہے۔ docker compose config چلانے پر آپ کو دونوں entries نظر آئیں گی۔ Compose v2.24.4 یا اس کے بعد کے ورژن میں ports: !override استعمال کریں، یا base file سے ports نکال دیں تاکہ merge کرنے کے لیے کوئی entry موجود نہ ہو۔

include اور -f میں کیا فرق ہے؟

-f متعدد files کو ایک application پر layer کرتا ہے، اور ہر file میں موجود relative path پہلی file کی directory کے لحاظ سے resolve ہوتا ہے۔ include ایک الگ Compose application شامل کرتا ہے، اور شامل کی گئی ہر path اپنی project directory برقرار رکھتی ہے۔ اس لیے اس کی relative paths اسی application کے لحاظ سے resolve ہوتی ہیں۔ اپنے stack کی environment layers کے لیے -f استعمال کریں، اور کسی دوسرے مقام پر maintain کیے جانے والے fragment کے لیے include استعمال کریں۔ include کے لیے Compose v2.20.0 یا اس کے بعد کا ورژن درکار ہے۔

base file میں مقرر کی گئی value کیسے ہٹاؤں؟

Compose v2.18.0 یا اس کے بعد کے ورژن میں !reset tag استعمال کریں۔ overriding file میں ports: !reset [] یا MY_VAR: !reset null لکھیں۔ اس سے attribute اپنی default value یا null پر واپس آ جاتا ہے۔ Tag کو دی جانے والی value لازمی ہے، لیکن اسے نظرانداز کیا جاتا ہے۔ اگر آپ کسی attribute کو clear کرنے کے بجائے replace کرنا چاہتے ہیں تو !override یہ کام کرتا ہے، اور اس کے لیے v2.24.4 یا اس کے بعد کا ورژن درکار ہے۔