SSD Nodes Learn 8GB RAM — $66/taon
Mga Gabay Matt ConnorNi Matt Connor · Na-update 2026-08-02

Docker Compose: Paano Gumagana ang Multiple Files

Alamin kung paano awtomatikong nilo-load ang compose.override.yaml, paano nagme-merge ang file order, bakit nananatiling bukas ang ports, at paano gamitin ang include.

Ano ang ginagawa ng Compose kapag higit sa isang file

Maaaring bumuo ang Docker Compose ng isang project mula sa ilang file. Binabasa nito ang mga ito ayon sa pagkakasunod-sunod ng pagtanggap nito at pinagsasama ang mga ito sa isang modelo. Kaya, nananaig ang isang value mula sa mas huling file kapag may conflict. May dalawang mekanismong gumagawa nito mula sa command line: isang override file na awtomatikong nilo-load ng Compose, at ang -f flag na manu-mano mong ipinapasa. May ikatlong mekanismo sa mismong file, ang include element, at iba ang paggana nito kaysa sa dalawang nauna.

Hindi simpleng overwrite ang merge. Pinagme-merge ang mappings key by key, idinadagdag ang mga sequence, at pinapalitan nang buo ang maliit na set ng mga field. Dito nagmumula ang mga hindi inaasahang resulta, at ang ports list ang karaniwang nagdudulot ng problema sa halos lahat.

Ipinapalagay ng lahat ng nasa ibaba na Compose v2 ang ginagamit, kasama ang docker compose plugin sa halip na ang lumang docker-compose script. Patakbuhin ang docker compose version para mag-check. Kung wala ka pang ginagawang Compose file, magsimula sa pangunahing gabay sa Docker Compose at bumalik dito.

Ang override file na awtomatikong nilo-load ng Compose

Patakbuhin ang docker compose up nang walang -f flag. Hahanapin ng Compose ang working directory, pagkatapos ang mga parent directory nito, para sa compose.yaml o docker-compose.yaml. Kung may override file sa tabi ng base file, awtomatikong ilo-load iyon ng Compose pagkatapos ng base file.

ls compose.yaml compose.override.yaml
docker compose up -d

Kapag parehong available ang dalawang file, katumbas ito ng manu-manong paglalagay ng dalawang file.

docker compose -f compose.yaml -f compose.override.yaml up -d

Ang mga pangalang kinikilala ng Compose ay compose.override.yaml, compose.override.yml, at ang mas lumang docker-compose.override.yml at docker-compose.override.yaml. Ang ibang pangalan, gaya ng compose.dev.yaml, ay nilo-load lamang kapag tinukoy mo ito gamit ang -f.

Kapag nagpasa ka ng kahit isang -f, hihinto ang awtomatikong pag-load. Binabasa ng docker compose -f compose.yaml up ang eksaktong file na iyon at binabalewala ang override. Ito ang property na ginagamit ng dev at prod pattern sa susunod na bahagi ng guide na ito.

May dalawang epekto ito sa isang server. Ang override file na naiwan sa deploy directory ay nilo-load ng bawat bare docker compose command na pinapatakbo mula sa directory na iyon, kasama ang command na pinapatakbo ng cron job. Dahil dito, maaaring mag-bind-mount ang isang production stack ng source directory na hindi dapat isinama sa release. Patakbuhin ang docker compose config pagkatapos ng bawat deploy at basahin ang output nito.

Pagkakasunod-sunod gamit ang -f, at kung saan nireresolba ang mga relative path

Binubuo ng Compose ang configuration ayon sa pagkakasunod-sunod ng mga file na ibinigay mo. Ino-override at dinaragdagan ng mga kasunod na file ang mga nauna. Mula kaliwa pakanan, ang huli ang mananaig.

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

Kailangang pareho ang listahan ng mga file sa bawat command para sa project na iyon. Kung patatakbuhin mo ang up gamit ang dalawang file at ang logs gamit ang isa, ibang pinagsamang model ang kinakausap mo. Mabilis itong humahantong sa service na sinasabing wala sa Compose. Itakda na lang nang isang beses ang listahan gamit ang environment variable na COMPOSE_FILE.

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

Ang separator ay : sa Linux, at binabago ito ng COMPOSE_PATH_SEPARATOR. Maaari ring ilagay ang COMPOSE_FILE sa project .env file. Sa ganitong paraan, bahagi ito ng checkout at hindi ng shell history mo. Ang tahasang itinakda sa command line ang mananaig laban sa environment variable.

Narito ang panuntunang nagdudulot ng problema sa bind mount. Kapag gumagamit ka ng maraming file kasama ang -f, ang lahat ng relative path sa lahat ng file ay nireresolba batay sa directory ng unang file, hindi sa file na naglalaman ng mga ito. Isulat ang ./data:/var/lib/postgresql/data sa loob ng deploy/prod/compose.prod.yaml, at hahanapin pa rin ng Compose ang ./data sa tabi ng base file. Pagkatapos, gagawa ang Docker ng walang-lamang directory sa maling path na iyon, at magsisimula ang container na walang laman ang directory. Maaari itong magmukhang pagkawala ng data, ngunit hindi ito ganoon. Ipasa ang --project-directory upang ikaw ang magtakda ng base path, o gamitin ang include, na nagre-resolve sa bawat file batay sa sarili nitong directory.

Mula sa base directory ding iyon kinukuha ang project name. Kaya maaaring mapalitan ang pangalan ng project kapag binago mo kung aling file ang mauuna. Ang pinalitang project name ay nangangahulugan ng mga bagong pangalan ng container at bagong pangalan ng volume. Nananatili sa disk ang lumang volume gamit ang lumang pangalan. I-pin ang pangalan gamit ang top-level name: sa base file.

name: myapp

Aling field ang pinagsasama, at alin ang pinapalitan

Pinagsasama ng Compose ang mga value batay sa uri ng value, hindi sa pangalan ng field.

  • Pinapalitan ang mga field na iisa ang value. image, command, entrypoint at mem_limit ay direktang kumukuha ng value mula sa mas huling file. Hindi ka maaaring magdagdag ng isang argument sa command, dahil muling isinusulat ng override ang buong linya.
  • Pinagsasama ang mga mapping batay sa bawat key. Pinananatili ng environment, labels, volumes at devices ang bawat key mula sa dalawang file, at ang mas huling file ang nananalo kapag nasa parehong file ang key. Para sa environment at labels, ang key ay ang pangalan ng variable o label. Para sa volumes at devices, ang key ay ang path ng container.
  • Idinadagdag ang mga sequence. Pinagdurugtong ang dns, dns_search, expose, tmpfs at external_links. Kapag ang base ay may expose: ["3000"] at ang override ay may ["4000", "5000"], nagiging ["3000", "4000", "5000"] ang resulta.

May identity key ang apat na sequence, kaya pinagsasama ang mga entry na magkatugma sa key na iyon sa halip na idagdag. Ang volumes, secrets at configs ay nagtutugma batay sa target. Ang ports ay nagtutugma batay sa kombinasyon ng ip, target, published at protocol.

Basahin nang dalawang beses ang panuntunang ports, dahil ito ang karaniwang pagkakamali. Magkapareho lamang ang dalawang port entry kapag nagtutugma ang lahat ng apat na bahaging iyon. Kapag binago ang alinman sa mga ito, itinuturing ng Compose na pangalawa at hiwalay na port ang entry, kaya pinananatili nito ang pareho.

Bakit naka-publish pa rin ang port mo pagkatapos ng override

Isang base file na nagpa-publish ng service sa bawat interface:

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

Isang override na nagbi-bind dito sa localhost lamang, dahil may reverse proxy na ilalagay sa harap nito:

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

Suriin ang resulta bago ipagpalagay na gumana ito.

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

Kapwa nasa output ang dalawang entry. Magkaiba ang bahaging ip, 0.0.0.0 kumpara sa 127.0.0.1, kaya itinuturing ang mga ito na dalawang magkaibang port sa proseso ng merge, at nananatili sa model ang public binding na sinubukan mong alisin. Mas mahalaga ito sa Docker kaysa sa ibang environment dahil isinusulat ang published port sa iptables bago ang iyong firewall rules. Ipinaliwanag ang mekanismong ito sa bakit nalalampasan ng published Docker ports ang ufw.

May dalawang paraan upang ayusin ito. Ang tahasang paraan ay ang !override tag, na nagpapalit sa buong attribute at nilalampasan ang mga panuntunan sa merge:

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

Kailangan ng !override ang Compose v2.24.4 o mas bago. Walang tag na kailangan sa portable na paraan: panatilihing wala ang ports sa base file at ideklara lamang ito sa mga file na partikular sa environment. Kung walang ime-merge, walang malalabas na setting. Ito ang pattern na ginamit sa kumpletong halimbawa sa ibaba.

Pagbura ng value na itinakda ng base file

Inaalis ng !reset ang isang attribute at ibinabalik ito sa default nito o sa null. Tumatanggap ito ng value pero binabalewala ito, kaya magsulat ng valid at walang laman na value.

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

Kailangan ng !reset ang Compose v2.24 o mas bago. Gamitin ito kapag hindi mo maaaring i-edit ang base file, halimbawa, isang vendor fragment na isinasama mo.

include, mga stack na binuo mula sa magkakahiwalay na bahagi

include kumukuha ng isa pang Compose application at isinasama ito sa iyong model. Isa itong top-level element, hindi flag.

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

Ang bawat path sa include ay nilo-load bilang sariling Compose application model, na may sariling project directory. Kaya ang mga relative path sa loob ng file ay nire-resolve batay sa directory ng mismong file. Ito ang tunay na pagkakaiba nito sa -f, at ito ang dahilan kung bakit include ang tamang tool kapag nasa ibang folder o ibang repository ang fragment.

May mga sub-option ang long form.

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

Tumatanggap ang path ng listahan. Pinagsasama ang mga file na iyon ayon sa karaniwang rules bago isama ang resulta sa iyong model. Itinatakda ng project_directory ang base path na ginagamit para i-resolve ang mga relative path sa included file. Binibigyan ng env_file ang included file ng sarili nitong variables para sa interpolation. Pinipigilan nito ang shared fragment na tahimik na gumamit ng .env ng iyong project. Kailangan ng include ang Compose v2.20.0 o mas bago.

Iniuulat bilang error ang magkakaparehong resource name sa iyong file at sa included file, sa halip na tahimik na pagsamahin. Sinadya ang ganitong behavior. Para baguhin ang dineklara ng included file, ilagay ang pagbabago sa compose.override.yaml. Inilalapat ang override sa assembled model, kaya maaari nitong baguhin ang mga resource na isinama nang hindi nagkakaroon ng conflict sa mga ito.

Sa madaling sabi: ang include ay bumubuo ng magkakahiwalay na application, habang ang -f ay naglalagay ng configuration layer sa isang application.

Paghihiwalay ng dev at prod sa isang VPS

Narito ang buong pattern sa tatlong file. Idinedeklara ng base file ang mga laging totoo sa lahat ng environment, at wala itong anumang ina-publish na port.

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:

Ang kondisyon na depends_on ang naghihintay sa app ng database na tumutugon, hindi ng container na umiiral lamang. Ipinaliwanag ito sa mga healthcheck at kondisyon ng depends_on. Ini-interpolate ang POSTGRES_PASSWORD mula sa file na .env ng project, na hindi kailanman dapat mapabilang sa git. Tingnan ang mga env file at Compose secret para sa mas ligtas na mga variant.

Sunod ang compose.override.yaml, na awtomatikong nilo-load ng Compose. Ito ang file para sa 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"

Sa laptop, pinagsasama ng isang walang argumentong docker compose up ang dalawang file na ito. Pinapalitan ng command ang default ng image dahil iisa lamang ang value nito. Pinapalitan ng LOG_LEVEL ang info dahil pinagsasama ng environment ang mga ito ayon sa key. Mga purong karagdagan ang bind mount at dalawang published port. Naka-bind sa localhost ang database port upang hindi mag-alok ang laptop ng PostgreSQL sa buong kuwarto kapag nasa shared network ito.

Panghuli, ang compose.prod.yaml. Hindi ito isa sa mga file na awtomatikong hinahanap ng Compose, kaya hindi ito aksidenteng nilo-load.

services:
  app:
    ports:
      - "127.0.0.1:8000:3000"
    deploy:
      resources:
        limits:
          memory: 512M

Sa VPS, pareho mong pinapangalanan ang dalawang file. Ang mismong pagtukoy sa mga file ang nagbubukod sa 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

Dapat ipakita ng ps na tumatakbo ang dalawang service, at dapat ipakita ng db ang (healthy). Dahil ipinasa mo ang -f, hindi binasa ang compose.override.yaml. Dahil dito, hindi makararating sa production ang dev command, ang source bind mount, at ang public port 3000 kahit nasa parehong directory ang file. Naka-bind lamang sa localhost ang port 8000 at handa ito para sa proxy. Tingnan ang pagpapatakbo ng ilang app sa likod ng Traefik kapag idinagdag mo ang ikalawang service.

Itakda ang COMPOSE_FILE=compose.yaml:compose.prod.yaml sa .env ng server, at babalik sa simpleng docker compose logs -f app ang iba mong command.

Basahin ang pinagsamang model bago mag-deploy

docker compose config ang nagpi-print ng ganap na pinagsama at ganap na na-interpolate na model. Hindi ito preview. Ito ang eksaktong input na gagamitin ng Compose, kaya kapag hindi tugma ang output sa inaasahan mo, tama ang 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

Hindi ine-expand ng --no-interpolate ang ${VAR}. Gamitin ito bago mag-paste ng output kahit saan, dahil pini-print ng plain na config ang lahat ng na-resolve na secret bilang clear text. Ang --services ay naglilista lamang ng mga pangalan ng service. Mabilis itong paraan para kumpirmahing ang isang include ay nag-load ng inaasahan mo.

Mga failure mode at kung ano ang makikita mo

no configuration file provided: not found. Walang nahanap na babasahin ang Compose. Nasa labas ka ng project directory, o ang COMPOSE_FILE ay tumutukoy sa path na hindi umiiral. Naghahanap ang Compose sa mga parent directory para sa default base file, pero hindi ito naghahanap kahit saan para sa file na ikaw mismo ang nagtakda.

WARN[0000] The "POSTGRES_PASSWORD" variable is not set. Defaulting to a blank string. Nire-resolve ang interpolation batay sa project .env file at shell environment. Ang project directory dito ay directory ng unang -f file. Kapag nag-deploy mula sa ibang directory kaysa sa directory na naglalaman ng .env, ipapakita sa iyo ang warning na ito, at magkakaroon ng database na tumatanggi sa bawat connection.

Hindi lumilitaw sa docker compose config ang iyong override edit. Maaaring ipinasa mo ang -f, na nag-o-off sa automatic override loading. Maaari ring nakita ng Compose ang compose.yaml sa isang parent directory at wala sa tabi nito ang iyong override file. Kapag pinatakbo ang docker compose config nang walang ibang argument, makikita mo kung anong model ang aktuwal na bina-build ng Compose.

Walang laman ang bind mount at gumawa ang Docker ng directory na hindi mo hiniling. Na-resolve ang relative path batay sa directory ng unang file. Ayusin ang path, ipasa ang --project-directory, o ilipat ang fragment sa likod ng include.

Bumabalik ang mga container na may bagong pangalan at mukhang walang laman ang isang volume. Nagbago ang project name dahil nakabatay ito sa directory ng unang file. Magdagdag ng top-level na name: sa base file upang hindi na magbago ang mga pangalan. Nandoon pa rin ang lumang volume sa ilalim ng lumang prefix, at ipapakita ito ng docker volume ls.

Bukas pa rin ang port na inalis mo sa override. Idinagdag ng ports merge ang entry sa halip na palitan ito. Kumpirmahin gamit ang docker compose config, pagkatapos ay gamitin ang !override o ilipat ang ports palabas ng base file.

FAQ

Awtomatikong nilo-load ba ng Compose ang compose.override.yaml?

Oo, kapag pinatakbo mo ang docker compose nang walang -f flag. Hinahanap ng Compose ang compose.yaml o docker-compose.yaml sa working directory at mga parent directory nito. Kung may override file sa tabi nito, nilo-load ang file na iyon bilang ikalawang file. Ang mga kinikilalang pangalan ay compose.override.yaml, compose.override.yml, docker-compose.override.yml at docker-compose.override.yaml. Kapag nagpasa ka ng anumang -f, hindi ito pinapagana, kaya isang file lang ang binabasa ng docker compose -f compose.yaml up.

Sa anong pagkakasunod-sunod pinagme-merge ang maraming -f file?

Mula kaliwa pakanan. Binubuo ng Compose ang configuration ayon sa pagkakasunod-sunod ng mga file na ibinigay mo. Bawat file ay nag-o-override at nagdaragdag sa mga file na nauna rito. Dahil dito, ang huling file sa command line ang nananalo sa anumang conflict. Dapat gamitin ang parehong listahan sa bawat command para sa project na iyon. Ito ang gamit ng COMPOSE_FILE=compose.yaml:compose.prod.yaml.

Bakit naka-publish pa rin ang port ko pagkatapos ko itong i-override?

Dahil tinutukoy ang mga entry na ports gamit ang buong set ng ip, target, published at protocol. Ang pag-override ng 127.0.0.1:8080:80 kapag ang base ay 8080:80 ay naiiba sa bahaging ip. Kaya itinuturing ito ng Compose bilang ikalawang port at pinananatili ang dalawa. Patakbuhin ang docker compose config para makita ang dalawang entry. Gamitin ang ports: !override sa Compose v2.24.4 o mas bago. Maaari mo ring alisin ang ports sa base file para walang pagme-merge na magaganap.

Ano ang pagkakaiba ng include at -f?

Ipinapatong ng -f ang maraming file sa isang application. Nire-resolve ang bawat relative path sa bawat file batay sa directory ng unang file. Kumukuha ang include ng hiwalay na Compose application. Pinananatili ng bawat included path ang sarili nitong project directory, kaya batay sa sarili nito ang pagre-resolve ng mga relative path. Gamitin ang -f para sa mga environment layer ng sarili mong stack. Gamitin ang include para sa fragment na pinapanatili sa ibang lugar. Kailangan ng include ang Compose v2.20.0 o mas bago.

Paano ko aalisin ang value na itinakda ng base file?

Gamitin ang !reset tag sa Compose v2.24 o mas bago. Isulat ang ports: !reset [] o MY_VAR: !reset null sa overriding file para ibalik ang attribute sa default nito o sa null. Kinakailangan ang value na ibinibigay mo sa tag, pero hindi ito ginagamit. Kung papalitan mo ang attribute sa halip na i-clear ito, !override ang gamitin. Kailangan nito ang v2.24.4 o mas bago.