SSD Nodes Learn RAM 8GB — $66/ปี
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-01

Docker Compose หลายไฟล์: override, merge และ include

เรียนรู้ว่า compose.override.yaml โหลดเองอย่างไร ลำดับไฟล์รวมค่าจริงแบบใด เหตุใด ports จึงยังเปิดค้าง และใช้ include แยก dev กับ prod อย่างถูกต้อง

Compose ทำงานอย่างไรเมื่อมีไฟล์มากกว่าหนึ่งไฟล์

Docker Compose สามารถสร้างโปรเจกต์หนึ่งจากหลายไฟล์ได้ โดยจะอ่านไฟล์ตามลำดับที่ได้รับ แล้วรวมเป็นโมเดลเดียวกัน ดังนั้นไฟล์ที่อยู่ภายหลังจะมีผลเหนือกว่าค่าใด ๆ ที่ขัดแย้งกัน กลไกจากบรรทัดคำสั่งมี 2 แบบ ได้แก่ ไฟล์ override ที่ Compose โหลดโดยอัตโนมัติ และแฟล็ก -f ที่คุณระบุเอง อีกแบบหนึ่งอยู่ภายในไฟล์เอง คือองค์ประกอบ include ซึ่งทำงานแตกต่างจากทั้ง 2 แบบแรก

การรวมไฟล์ไม่ใช่การเขียนทับแบบตรงไปตรงมา Mapping จะถูกรวมทีละคีย์ ลำดับข้อมูลจะถูกต่อท้าย และฟิลด์บางส่วนจะถูกแทนที่ทั้งชุด ความแตกต่างนี้เป็นสาเหตุของผลลัพธ์ที่คาดไม่ถึง และรายการ ports เป็นส่วนที่ทำให้ผู้ใช้เกือบทุกคนพบปัญหา

เนื้อหาต่อไปนี้สมมติว่าใช้ Compose v2 และปลั๊กอิน docker compose แทนสคริปต์ docker-compose รุ่นเก่า เรียกใช้ docker compose version เพื่อตรวจสอบ หากคุณยังไม่ได้เขียนไฟล์ Compose ให้เริ่มจาก คู่มือพื้นฐาน Docker Compose แล้วกลับมาอ่านเนื้อหานี้

Compose โหลดไฟล์ override โดยไม่ต้องระบุ

เรียกใช้ 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 bind-mount ไดเรกทอรี source ที่ไม่มีใครตั้งใจนำไปใช้งาน หลังการ deploy ทุกครั้ง ให้เรียกใช้ docker compose config แล้วตรวจสอบผลลัพธ์ที่แสดงออกมา

การจัดลำดับด้วย -f และตำแหน่งที่พาธแบบสัมพันธ์ถูกแก้ไข

Compose จะสร้างการกำหนดค่าตามลำดับไฟล์ที่คุณระบุ ไฟล์ที่ตามมาจะเขียนทับและเพิ่มการกำหนดค่าจากไฟล์ก่อนหน้า โดยประมวลผลจากซ้ายไปขวา และให้ไฟล์สุดท้ายมีผลเหนือกว่า

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

ทุกคำสั่งในโปรเจกต์นั้นต้องใช้รายการไฟล์เดียวกัน หากเรียกใช้ up ด้วยไฟล์ 2 ไฟล์ แล้วเรียกใช้ logs ด้วยไฟล์เดียว คุณกำลังอ้างอิงโมเดลที่ผสานแล้วคนละชุด ซึ่งอาจทำให้ Compose แจ้งว่าไม่มี service นั้นได้อย่างรวดเร็ว ให้กำหนดรายการนี้เพียงครั้งเดียวด้วยตัวแปรสภาพแวดล้อม COMPOSE_FILE

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

ตัวคั่นคือ : บน Linux และ COMPOSE_PATH_SEPARATOR ใช้เปลี่ยนตัวคั่นนี้ได้ นอกจากนี้ยังสามารถกำหนด COMPOSE_FILE ไว้ในไฟล์โปรเจกต์ .env ได้ด้วย วิธีนี้ทำให้การกำหนดค่าเป็นส่วนหนึ่งของ checkout แทนที่จะอยู่ในประวัติ shell การกำหนดค่าที่ระบุอย่างชัดเจนบนบรรทัดคำสั่งจะมีผลเหนือกว่าตัวแปรสภาพแวดล้อม

ต่อไปคือกฎที่ทำให้ bind mount ทำงานผิดพลาด เมื่อใช้หลายไฟล์ร่วมกับ -f พาธแบบสัมพันธ์ทั้งหมดในไฟล์เหล่านั้นจะอ้างอิงกับไดเรกทอรีของไฟล์แรก ไม่ใช่ไฟล์ที่มีพาธนั้นอยู่ ให้เขียน ./data:/var/lib/postgresql/data ไว้ใน deploy/prod/compose.prod.yaml แต่ Compose จะยังค้นหา ./data ถัดจากไฟล์ฐาน Docker จึงสร้างไดเรกทอรีว่างที่พาธผิดนั้น แล้วคอนเทนเนอร์จะเริ่มทำงานโดยไม่มีข้อมูลอยู่ภายใน ทำให้ดูเหมือนข้อมูลสูญหาย ทั้งที่ไม่ได้สูญหายจริง ให้ส่ง --project-directory เพื่อกำหนดพาธฐานด้วยตนเอง หรือใช้ include ซึ่งจะแก้ไขพาธของแต่ละไฟล์โดยอ้างอิงกับไดเรกทอรีของไฟล์นั้นเอง

ชื่อโปรเจกต์มาจากไดเรกทอรีฐานเดียวกัน ดังนั้นการเปลี่ยนว่าไฟล์ใดเป็นไฟล์แรกอาจทำให้ชื่อโปรเจกต์เปลี่ยน ชื่อโปรเจกต์ที่เปลี่ยนจะทำให้ชื่อคอนเทนเนอร์และชื่อ volume ใหม่ตามไปด้วย ส่วน volume เดิมยังคงอยู่บนดิสก์ภายใต้ชื่อเดิม ให้กำหนดชื่อแบบตายตัวด้วย name: ระดับบนสุดในไฟล์ฐาน

name: myapp

ฟิลด์ใดรวมกัน และฟิลด์ใดถูกแทนที่

Compose จะรวมค่าตามชนิดของค่า ไม่ใช่ตามชื่อของฟิลด์

  • ฟิลด์ที่มีค่าเดียวจะถูกแทนที่ image, command, entrypoint และ mem_limit จะใช้ค่าจากไฟล์ภายหลังโดยตรง คุณไม่สามารถต่ออาร์กิวเมนต์เพิ่มเติมให้กับ command ได้ เนื่องจากการแทนที่จะเขียนทับทั้งบรรทัด
  • แมปปิงจะรวมกันทีละคีย์ environment, labels, volumes และ devices จะเก็บทุกคีย์จากทั้งสองไฟล์ และไฟล์ภายหลังจะมีผลเหนือกว่าสำหรับคีย์ที่ปรากฏในทั้งสองไฟล์ สำหรับ environment และ labels คีย์คือชื่อตัวแปรหรือชื่อป้ายกำกับ สำหรับ volumes และ devices คีย์คือพาธของคอนเทนเนอร์
  • ลำดับจะถูกต่อกัน dns, dns_search, expose, tmpfs และ external_links จะถูกนำมาต่อกัน หากไฟล์พื้นฐานมี expose: ["3000"] และไฟล์แทนที่มี ["4000", "5000"] ผลลัพธ์จะเป็น ["3000", "4000", "5000"]

ลำดับ 4 รายการมีคีย์ระบุเอกลักษณ์ ดังนั้นรายการที่ตรงกันตามคีย์ดังกล่าวจะถูกรวมกันแทนการนำมาต่อกัน volumes, secrets และ configs จะจับคู่ตาม target ส่วน ports จะจับคู่ตามชุดของ ip, target, published และ protocol

โปรดอ่านกฎ ports นี้ 2 ครั้ง เนื่องจากเป็นจุดที่มักเกิดข้อผิดพลาด รายการพอร์ต 2 รายการจะถือว่าเป็นรายการเดียวกันต่อเมื่อองค์ประกอบทั้ง 4 ส่วนตรงกันทั้งหมด หากเปลี่ยนส่วนใดส่วนหนึ่ง Compose จะมองว่าเป็นพอร์ตอีกรายการที่ไม่เกี่ยวข้องกัน ดังนั้นจึงเก็บทั้ง 2 รายการไว้

เหตุใด port ของคุณยังคงถูกเปิดเผยหลังใช้ override

ไฟล์พื้นฐานที่เผยแพร่ service บนทุก interface:

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 รายการเหล่านี้จึงเป็นคนละ port และการ bind แบบ public ที่คุณพยายามลบออกยังคงอยู่ใน model เรื่องนี้สำคัญกับ Docker มากกว่าระบบอื่น เนื่องจาก port ที่เผยแพร่จะถูกเขียนลงใน iptables ก่อนกฎ firewall ของคุณ กลไกนี้อธิบายไว้ใน เหตุใด port ของ Docker ที่เผยแพร่จึงข้าม ufw ได้

มีวิธีแก้ 2 วิธี วิธีที่ระบุอย่างชัดเจนคือ tag !override ซึ่งจะแทนที่ attribute ทั้งหมดและไม่ใช้กฎ merge:

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

!override ต้องใช้ Compose v2.24.4 หรือใหม่กว่า วิธีแก้ที่รองรับการใช้งานทั่วไปไม่ต้องใช้ tag ใด ๆ เพียงไม่นำ ports ไว้ในไฟล์พื้นฐาน และประกาศไว้เฉพาะในไฟล์ของแต่ละ environment เท่านั้น หากไม่มีข้อมูลให้ merge ก็ไม่มีข้อมูลรั่วไหล รูปแบบนี้ใช้ในตัวอย่างแบบลงมือทำด้านล่าง

การลบค่าที่กำหนดไว้ในไฟล์พื้นฐาน

!reset จะลบแอตทริบิวต์ โดยเปลี่ยนกลับเป็นค่าเริ่มต้นหรือเป็น null คำสั่งนี้รับค่าไว้แต่ไม่ใช้ค่านั้น ดังนั้นให้ระบุค่าที่ถูกต้องและเป็นค่าว่าง

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

!reset ต้องใช้ Compose v2.24 หรือใหม่กว่า ให้ใช้เมื่อคุณไม่สามารถแก้ไขไฟล์พื้นฐานได้ เช่น fragment จากผู้จำหน่ายที่คุณนำเข้ามาใช้งาน

include สำหรับสแตกที่ประกอบจากส่วนต่าง ๆ

include ดึงแอปพลิเคชัน Compose อื่นเข้ามาในโมเดลของคุณ องค์ประกอบนี้อยู่ในระดับบนสุด ไม่ใช่ flag

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

แต่ละพาธใน include จะถูกโหลดเป็นโมเดลแอปพลิเคชัน Compose แยกกัน โดยมีไดเรกทอรีโปรเจกต์ของตนเอง ดังนั้นพาธแบบสัมพัทธ์ภายในไฟล์นั้นจะอ้างอิงกับไดเรกทอรีของไฟล์นั้นเอง นี่คือความแตกต่างที่สำคัญจาก -f และเป็นเหตุผลที่ควรใช้ include เมื่อ fragment อยู่ในโฟลเดอร์อื่นหรือ repository อื่น

รูปแบบแบบยาวรองรับตัวเลือกย่อย

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

path รับค่าเป็นรายการ และไฟล์เหล่านั้นจะถูกผสานตามกฎปกติก่อนนำผลลัพธ์เข้ารวมกับโมเดลของคุณ project_directory กำหนดพาธพื้นฐานที่ใช้แก้ไขพาธแบบสัมพัทธ์ในไฟล์ที่ include env_file กำหนดตัวแปรของไฟล์ที่ include เองสำหรับการแทนค่าตัวแปร วิธีนี้ป้องกันไม่ให้ fragment ที่ใช้ร่วมกันอ่านค่า .env ของโปรเจกต์คุณโดยไม่ตั้งใจ include ต้องใช้ Compose v2.20.0 หรือใหม่กว่า

หากชื่อทรัพยากรในไฟล์ของคุณซ้ำกับชื่อในไฟล์ที่ include ระบบจะแจ้งข้อผิดพลาดแทนที่จะผสานให้โดยไม่แจ้ง เนื่องจากเป็นพฤติกรรมที่ตั้งใจไว้ หากต้องการเปลี่ยนแปลงสิ่งที่ไฟล์ที่ include ประกาศไว้ ให้ใส่การเปลี่ยนแปลงนั้นใน compose.override.yaml: ระบบจะใช้ override กับโมเดลที่ประกอบเสร็จแล้ว จึงสามารถแก้ไขทรัพยากรที่ include ได้โดยไม่เกิดชื่อซ้ำ

สรุปสั้น ๆ: include ใช้ประกอบแอปพลิเคชันแยกกัน ส่วน -f ใช้ซ้อนการกำหนดค่าลงบนแอปพลิเคชันเดียว

VPS เดียวที่แยกสภาพแวดล้อม dev และ prod

นี่คือรูปแบบทั้งหมดในไฟล์ 3 ไฟล์ ไฟล์พื้นฐานประกาศค่าที่เป็นจริงในทุกสภาพแวดล้อม และไม่มีการเผยแพร่พอร์ตใดเลย

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 ทำให้แอปรอฐานข้อมูลที่ตอบสนองได้ แทนที่จะรอเพียง container ที่มีอยู่ คำอธิบายอยู่ใน healthchecks และเงื่อนไข depends_on POSTGRES_PASSWORD จะถูกแทนค่าจากไฟล์ .env ของโปรเจกต์ ซึ่งไม่ควรอยู่ใน git โปรดดู ไฟล์ env และความลับของ Compose สำหรับรูปแบบที่ปลอดภัยกว่า

ถัดไปคือ 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"

บน laptop คำสั่ง docker compose up โดยไม่ระบุไฟล์จะรวมไฟล์ทั้ง 2 ไฟล์เข้าด้วยกัน command แทนค่าเริ่มต้นของ image เพราะเป็นค่าที่มีได้เพียงค่าเดียว LOG_LEVEL แทนที่ info เพราะ environment จะรวมค่าตาม key bind mount และพอร์ตที่เผยแพร่ 2 พอร์ตเป็นการเพิ่มเข้ามาเท่านั้น และพอร์ตของฐานข้อมูลจะ bind กับ localhost เพื่อไม่ให้ laptop บนเครือข่ายที่ใช้ร่วมกันเปิด PostgreSQL ให้เครื่องอื่นในบริเวณนั้นเข้าถึงได้

สุดท้ายคือ compose.prod.yaml ชื่อไฟล์นี้ไม่ใช่ชื่อที่ Compose ค้นหา ดังนั้นจึงไม่ถูกโหลดโดยไม่ได้ตั้งใจ

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

บน VPS ให้ระบุชื่อไฟล์ทั้ง 2 ไฟล์ และการระบุชื่อไฟล์นี้จะตัดไฟล์ 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 ควรแสดงว่าบริการทั้ง 2 รายการกำลังทำงาน โดย db แสดงค่า (healthy) เนื่องจากคุณส่ง -f ระบบจึงไม่อ่าน compose.override.yaml ดังนั้นคำสั่งสำหรับ dev, source bind mount และพอร์ตสาธารณะ 3000 จึงไม่สามารถเข้าถึง production ได้ แม้ไฟล์จะอยู่ในไดเรกทอรีเดียวกันก็ตาม พอร์ต 8000 เปิดให้ใช้งานผ่าน localhost เท่านั้น และพร้อมสำหรับ proxy โปรดดู การรันหลายแอปผ่าน Traefik เมื่อต้องเพิ่มบริการที่ 2

กำหนด COMPOSE_FILE=compose.yaml:compose.prod.yaml ใน .env ของเซิร์ฟเวอร์ แล้วคำสั่งอื่นๆ ของคุณจะกลับมาใช้ docker compose logs -f app แบบไม่ต้องระบุเพิ่มเติม

อ่านโมเดลที่ผสานแล้วก่อนเริ่มใช้งาน

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 แบบปกติจะแสดงค่าลับที่แก้ไขแล้วทั้งหมดเป็นข้อความแบบไม่เข้ารหัส --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. การแทนค่าจะอ้างอิงกับไฟล์โครงการ .env และสภาพแวดล้อมของ shell โดยไดเรกทอรีโครงการในที่นี้คือไดเรกทอรีของไฟล์ -f แรก การนำไปใช้งานจากไดเรกทอรีอื่นที่ไม่ใช่ไดเรกทอรีซึ่งมี .env จะทำให้พบคำเตือนนี้ และฐานข้อมูลจะปฏิเสธการเชื่อมต่อทุกครั้ง

การแก้ไข override ของคุณไม่ปรากฏใน docker compose config. คุณอาจส่ง -f ซึ่งจะปิดการโหลด override โดยอัตโนมัติ หรือ Compose พบ compose.yaml ในไดเรกทอรีแม่ และไฟล์ override ของคุณไม่ได้อยู่ถัดจากไฟล์ดังกล่าว การเรียกใช้ docker compose config โดยไม่มีอาร์กิวเมนต์อื่นจะแสดงให้ทราบว่า Compose กำลังสร้างโมเดลใดอยู่จริง

bind mount ว่างเปล่า และ Docker สร้างไดเรกทอรีที่คุณไม่ได้ร้องขอ พาธสัมพัทธ์จะอ้างอิงกับไดเรกทอรีของไฟล์แรก แก้ไขพาธ ส่ง --project-directory หรือย้าย fragment ไปไว้หลัง include

คอนเทนเนอร์กลับมาพร้อมชื่อใหม่ และ volume ดูเหมือนว่างเปล่า ชื่อโครงการเปลี่ยนไป เนื่องจากชื่อโครงการอ้างอิงตามไดเรกทอรีของไฟล์แรก เพิ่ม name: ระดับบนสุดลงในไฟล์ฐาน แล้วชื่อจะไม่เปลี่ยนตามไดเรกทอรีอีก volume เดิมยังคงอยู่ภายใต้ prefix เดิม และ docker volume ls จะแสดง volume ดังกล่าว

พอร์ตที่คุณลบออกใน override ยังคงเปิดอยู่ การ merge ด้วย ports ต่อรายการเพิ่มแทนที่จะแทนที่รายการเดิม ตรวจสอบด้วย docker compose config จากนั้นใช้ !override หรือย้าย ports ออกจากไฟล์ฐาน

FAQ

Compose โหลด compose.override.yaml โดยอัตโนมัติหรือไม่

ใช่ เมื่อเรียกใช้ docker compose โดยไม่ระบุ flag -f Compose จะค้นหาไดเรกทอรีทำงานและไดเรกทอรีแม่เพื่อหา compose.yaml หรือ docker-compose.yaml หากมีไฟล์ override อยู่ในไดเรกทอรีเดียวกัน Compose จะโหลดไฟล์นั้นเป็นลำดับที่สอง ชื่อที่รองรับคือ compose.override.yaml, compose.override.yml, docker-compose.override.yml และ docker-compose.override.yaml การระบุ -f รายการใดรายการหนึ่งจะปิดการทำงานนี้ ดังนั้น docker compose -f compose.yaml up จะอ่านไฟล์เพียงไฟล์เดียว

ไฟล์ -f หลายไฟล์จะถูกรวมตามลำดับใด

รวมจากซ้ายไปขวา Compose จะสร้าง configuration ตามลำดับไฟล์ที่ระบุ แต่ละไฟล์จะ override และเพิ่มค่าจากไฟล์ก่อนหน้า ดังนั้นไฟล์สุดท้ายในบรรทัดจะมีผลเมื่อเกิดความขัดแย้ง ต้องใช้รายการเดียวกันนี้กับทุก command ใน project นั้น ซึ่งเป็นหน้าที่ของ COMPOSE_FILE=compose.yaml:compose.prod.yaml

เหตุใด port ของฉันจึงยังถูก publish หลังจาก override แล้ว

เนื่องจากรายการ ports จะถูกระบุด้วยชุดค่าทั้งหมดของ ip, target, published และ protocol การ override 127.0.0.1:8080:80 โดยมีค่าพื้นฐานเป็น 8080:80 แตกต่างกันที่ส่วน ip ดังนั้น Compose จึงถือว่าเป็น port อีกหนึ่งรายการและคงไว้ทั้งสองรายการ เรียกใช้ docker compose config แล้วจะเห็นรายการทั้งสอง ใช้ ports: !override บน Compose v2.24.4 หรือใหม่กว่า หรือไม่นำ ports ไว้ในไฟล์ฐาน เพื่อไม่ให้มีค่าที่ต้องนำมา merge

include และ -f แตกต่างกันอย่างไร

-f จะนำหลายไฟล์มาซ้อนเป็น application เดียว และ relative path ในทุกไฟล์จะอ้างอิงกับไดเรกทอรีของไฟล์แรก include จะดึง Compose application แยกต่างหากเข้ามา และ path ของแต่ละไฟล์ที่ include จะคง project directory ของตนเอง ดังนั้น relative path จึงอ้างอิงกับไดเรกทอรีของไฟล์นั้น ใช้ -f สำหรับ environment layer ของ stack ที่ดูแลเอง และใช้ include สำหรับ fragment ที่ดูแลโดยแหล่งอื่น include ต้องใช้ Compose v2.20.0 หรือใหม่กว่า

จะลบค่าที่ไฟล์ฐานกำหนดไว้อย่างไร

ใช้ tag !reset บน Compose v2.24 หรือใหม่กว่า ในไฟล์ override ให้เขียน ports: !reset [] หรือ MY_VAR: !reset null แล้ว attribute จะกลับไปเป็นค่าเริ่มต้นหรือเป็น null ค่าที่ระบุให้ tag เป็นค่าที่จำเป็นต้องใส่ แต่จะไม่ถูกนำไปใช้ หากต้องการแทนที่ attribute แทนการล้างค่า !override จะทำหน้าที่นี้ และต้องใช้ v2.24.4 หรือใหม่กว่า