Cara Docker Compose Menggabungkan Banyak Fail
Ketahui cara compose.override.yaml dimuat sendiri, aturan fail digabungkan, perangkap ports yang mengekalkan port terbuka dan penggunaan include untuk dev serta prod.
Perkara yang dilakukan oleh Compose dengan lebih daripada satu fail
Docker Compose boleh membina satu projek daripada beberapa fail. Compose membaca fail mengikut urutan yang diterimanya dan menggabungkannya menjadi satu model. Oleh itu, fail yang kemudian mengatasi sebarang nilai yang bercanggah. Terdapat dua mekanisme untuk tujuan ini dari baris perintah: fail penggantian yang dimuatkan sendiri oleh Compose, dan flag -f yang anda berikan secara manual. Mekanisme ketiga berada dalam fail itu sendiri, iaitu elemen include, dan cara operasinya berbeza daripada kedua-dua mekanisme tersebut.
Cantuman ini bukan penggantian biasa. Pemetaan digabungkan kunci demi kunci, jujukan ditambah pada hujung, dan sebilangan kecil medan digantikan sepenuhnya. Perbezaan ini menyebabkan kejutan, dan senarai ports ialah perkara yang mengelirukan hampir semua orang.
Semua perkara di bawah mengandaikan Compose v2, iaitu plugin docker compose dan bukannya skrip lama docker-compose. Jalankan docker compose version untuk membuat semakan. Jika anda belum menulis fail Compose, mulakan dengan panduan asas Docker Compose dan kembali ke sini.
Compose memuat fail override tanpa arahan khusus
Jalankan docker compose up tanpa flag -f. Compose akan mencari compose.yaml atau docker-compose.yaml dalam direktori kerja dan direktori induknya. Jika fail override berada di sebelah fail asas, Compose akan memuatkannya selepas itu secara automatik.
ls compose.yaml compose.override.yaml
docker compose up -dApabila kedua-dua fail tersedia, hasilnya sama seperti anda menulis kedua-dua fail itu secara manual.
docker compose -f compose.yaml -f compose.override.yaml up -dNama yang dikenali oleh Compose ialah compose.override.yaml, compose.override.yml, serta docker-compose.override.yml dan docker-compose.override.yaml yang lebih lama. Nama lain, contohnya compose.dev.yaml, hanya dimuatkan apabila anda menamakannya dengan -f.
Sebaik sahaja anda memberikan satu -f, pemuatan automatik dihentikan. docker compose -f compose.yaml up membaca fail yang dinyatakan itu sahaja dan mengabaikan fail override. Sifat ini menjadi asas corak dev dan prod yang diterangkan kemudian dalam panduan ini.
Keadaan ini boleh memberi kesan yang berbeza pada pelayan. Fail override yang tertinggal dalam direktori deploy akan dimuatkan oleh setiap arahan docker compose tanpa argumen yang dijalankan dari direktori itu, termasuk arahan yang dijalankan oleh tugas cron anda. Akibatnya, stack produksi boleh melakukan bind mount pada direktori sumber yang tidak sepatutnya dihantar. Jalankan docker compose config selepas setiap deploy dan semak hasilnya.
Susunan dengan -f dan lokasi penyelesaian laluan relatif
Compose membina konfigurasi mengikut susunan fail yang anda berikan. Fail berikutnya mengatasi dan menambah kandungan fail sebelumnya. Dari kiri ke kanan, fail terakhir mempunyai keutamaan.
docker compose -f compose.yaml -f compose.prod.yaml config
docker compose -f compose.yaml -f compose.prod.yaml up -dSetiap perintah dalam projek itu memerlukan senarai fail yang sama. Jalankan up dengan dua fail dan logs dengan satu fail, lalu anda menggunakan model gabungan yang berbeza. Ini boleh menyebabkan Compose melaporkan bahawa sesuatu perkhidmatan tidak wujud. Tetapkan senarai itu sekali sahaja dengan pemboleh ubah persekitaran COMPOSE_FILE.
export COMPOSE_FILE=compose.yaml:compose.prod.yaml
docker compose config
docker compose up -dPemisahnya ialah : pada Linux, manakala COMPOSE_PATH_SEPARATOR mengubahnya. COMPOSE_FILE juga boleh diletakkan dalam fail projek .env, supaya tetapan itu menjadi sebahagian daripada checkout dan bukan sejarah shell anda. Apa-apa tetapan yang dinyatakan secara jelas pada baris perintah akan mengatasi pemboleh ubah persekitaran tersebut.
Kini, peraturan yang menyebabkan bind mount gagal. Apabila anda menggunakan beberapa fail dengan -f, semua laluan relatif dalam semua fail itu diselesaikan berdasarkan direktori fail pertama, bukan fail yang mengandungi laluan tersebut. Tulis ./data:/var/lib/postgresql/data dalam deploy/prod/compose.prod.yaml, dan Compose tetap mencari ./data di sebelah fail asas. Docker kemudian mencipta direktori kosong pada laluan yang salah itu, lalu kontena bermula tanpa kandungan di dalamnya. Keadaan ini kelihatan seperti kehilangan data, tetapi sebenarnya bukan. Berikan --project-directory untuk menetapkan laluan asas sendiri, atau gunakan include, yang menyelesaikan setiap fail berdasarkan direktorinya sendiri.
Nama projek datang daripada direktori asas yang sama. Oleh itu, perubahan pada fail yang menjadi fail pertama boleh menamakan semula projek. Projek yang dinamakan semula akan menghasilkan nama kontena dan nama volum baharu. Volum lama masih berada pada cakera dengan nama lama. Tetapkan nama projek secara tetap dengan name: peringkat atas dalam fail asas.
name: myappMedan yang digabungkan dan yang digantikan
Compose menggabungkan medan berdasarkan jenis nilainya, bukan nama medan.
- Medan bernilai tunggal digantikan.
image,command,entrypointdanmem_limitterus menggunakan nilai yang kemudian. Anda tidak boleh menambahkan satu argumen padacommandkerana penggantian menulis semula keseluruhan baris. - Pemetaan digabungkan mengikut kunci.
environment,labels,volumesdandevicesmengekalkan setiap kunci daripada kedua-dua fail, dan fail yang kemudian diutamakan bagi kunci yang terdapat dalam kedua-duanya. Bagienvironmentdanlabels, kuncinya ialah nama pemboleh ubah atau label. Bagivolumesdandevices, kuncinya ialah laluan container. - Jujukan ditambahkan.
dns,dns_search,expose,tmpfsdanexternal_linksdigabungkan. Asas yang mengandungiexpose: ["3000"]dan digabungkan dengan penggantian yang mengandungi["4000", "5000"]menghasilkan["3000", "4000", "5000"].
Empat jujukan mempunyai kunci identiti, jadi entri yang sepadan berdasarkan kunci tersebut digabungkan dan bukannya ditambahkan. volumes, secrets dan configs dipadankan berdasarkan target. ports dipadankan berdasarkan gabungan ip, target, published dan protocol.
Baca peraturan ports itu dua kali kerana di situlah perangkapnya. Dua entri port ialah entri yang sama hanya apabila keempat-empat bahagian tersebut sepadan. Jika mana-mana satu daripadanya berubah, Compose menganggapnya sebagai port kedua yang tidak berkaitan, lalu mengekalkan kedua-duanya.
Mengapa port anda masih diterbitkan selepas penggantian
Fail asas yang menerbitkan perkhidmatan pada setiap antara muka:
services:
web:
image: nginx:1.27
ports:
- "8080:80"Penggantian yang ditulis untuk mengikatnya kepada localhost sahaja, kerana proksi terbalik akan diletakkan di hadapannya:
services:
web:
ports:
- "127.0.0.1:8080:80"Semak hasilnya sebelum menganggap bahawa konfigurasi itu berjaya.
docker compose -f compose.yaml -f compose.prod.yaml configKedua-dua entri terdapat dalam output. Bahagian ip berbeza, 0.0.0.0 berbanding 127.0.0.1, jadi kedua-duanya ialah port yang berbeza bagi proses penggabungan. Pengikatan awam yang cuba anda buang masih terdapat dalam model. Perkara ini lebih penting dalam Docker berbanding persekitaran lain kerana port yang diterbitkan ditulis ke dalam iptables sebelum peraturan tembok api anda. Mekanisme ini diterangkan dalam sebab port Docker yang diterbitkan memintas ufw.
Terdapat dua pembaikan. Cara yang jelas ialah teg !override, yang menggantikan keseluruhan atribut dan tidak menggunakan peraturan penggabungan:
services:
web:
ports: !override
- "127.0.0.1:8080:80"!override memerlukan Compose v2.24.4 atau lebih baharu. Pembaikan mudah alih tidak memerlukan sebarang teg: keluarkan ports sepenuhnya daripada fail asas dan isytiharkannya hanya dalam fail khusus persekitaran. Jika tiada apa-apa untuk digabungkan, tiada apa-apa yang boleh terdedah. Corak ini digunakan dalam contoh lengkap di bawah.
Memadam nilai yang ditetapkan oleh fail asas
!reset mengalih keluar atribut dan menetapkannya semula kepada nilai lalai atau null. Perintah ini menerima nilai tetapi mengabaikannya. Oleh itu, tulis nilai yang sah dan kosong.
services:
web:
ports: !reset []
environment:
DEBUG: !reset null!reset memerlukan Compose v2.24 atau lebih baharu. Gunakannya apabila anda tidak boleh mengedit fail asas, contohnya fragmen vendor yang anda sertakan.
include, untuk tindanan yang dibina daripada beberapa bahagian
include menarik aplikasi Compose lain ke dalam model anda. Ini ialah elemen peringkat atas, bukan flag.
include:
- path: ../commons/compose.yamlSetiap laluan dalam include dimuatkan sebagai model aplikasi Compose tersendiri, dengan direktori projeknya sendiri. Oleh itu, laluan relatif dalam fail tersebut diselesaikan berdasarkan direktori fail itu sendiri. Inilah perbezaan sebenar berbanding -f dan sebab include ialah alat yang sesuai apabila fragmen berada dalam folder lain atau repositori lain.
Bentuk panjang menerima subpilihan.
include:
- path:
- ../monitoring/compose.yaml
- ../monitoring/compose.vps.yaml
project_directory: ../monitoring
env_file: ../monitoring/.envpath menerima senarai, dan fail-fail tersebut digabungkan mengikut peraturan biasa sebelum hasilnya dimasukkan ke dalam model anda. project_directory menetapkan laluan asas yang digunakan untuk menyelesaikan laluan relatif dalam fail yang disertakan. env_file memberikan fail yang disertakan pembolehubahnya sendiri untuk interpolasi. Ini menghalang fragmen dikongsi daripada membaca .env projek anda secara senyap. include memerlukan Compose v2.20.0 atau lebih baharu.
Nama sumber pendua antara fail anda dengan fail yang disertakan dilaporkan sebagai ralat, bukannya digabungkan secara senyap. Ini memang disengajakan. Untuk mengubah sesuatu yang diisytiharkan oleh fail yang disertakan, letakkan perubahan itu dalam compose.override.yaml. Penggantian digunakan pada model yang telah dipasang, jadi penggantian itu boleh mengubah sumber yang disertakan tanpa bertindih dengannya.
Ringkasnya: include menggabungkan aplikasi berasingan, manakala -f melapiskan konfigurasi pada satu aplikasi.
Pecahan dev dan prod pada satu VPS
Berikut ialah keseluruhan corak dalam tiga fail. Fail asas mengisytiharkan perkara yang benar di semua persekitaran dan tidak menerbitkan sebarang 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:Syarat depends_on menyebabkan aplikasi menunggu pangkalan data yang memberikan respons, bukan bekas yang hanya wujud. Perkara ini diterangkan dalam pemeriksaan kesihatan dan syarat depends_on. POSTGRES_PASSWORD diinterpolasi daripada fail projek .env, yang tidak boleh dimasukkan ke dalam git. Lihat fail env dan rahsia Compose untuk varian yang lebih selamat.
Seterusnya, compose.override.yaml, yang dimuatkan oleh Compose secara automatik. Ini ialah fail pembangun.
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"Pada komputer riba, docker compose up tanpa argumen menggabungkan kedua-dua fail itu. command menggantikan nilai lalai imej kerana nilainya tunggal. LOG_LEVEL menggantikan info kerana environment digabungkan mengikut kunci. Lekapan bind dan dua port yang diterbitkan ialah penambahan semata-mata. Port pangkalan data diikat kepada localhost supaya komputer riba pada rangkaian dikongsi tidak mendedahkan PostgreSQL kepada rangkaian setempat.
Akhir sekali, compose.prod.yaml. Namanya bukan nama yang dicari oleh Compose, jadi fail itu tidak akan dimuatkan secara tidak sengaja.
services:
app:
ports:
- "127.0.0.1:8000:3000"
deploy:
resources:
limits:
memory: 512MPada VPS, anda menamakan kedua-dua fail. Tindakan menamakan itu mengecualikan override sepenuhnya.
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 psps sepatutnya menyenaraikan kedua-dua servis sebagai sedang berjalan, dengan db memaparkan (healthy). Oleh sebab anda menghantar -f, compose.override.yaml tidak dibaca. Oleh itu, arahan dev, lekapan bind sumber dan port awam 3000 tidak boleh sampai ke persekitaran production walaupun fail itu berada dalam direktori yang sama. Port 8000 hanya tersedia pada localhost dan sedia untuk proksi. Lihat menjalankan beberapa aplikasi di belakang Traefik apabila anda menambah servis kedua.
Tetapkan COMPOSE_FILE=compose.yaml:compose.prod.yaml dalam .env pelayan. Selepas itu, arahan anda yang lain kembali menggunakan docker compose logs -f app biasa.
Baca model yang telah digabungkan sebelum anda melakukan deployment
docker compose config mencetak model yang telah digabungkan dan diinterpolasi sepenuhnya. Ini bukan pratonton. Model ini ialah input tepat yang akan digunakan oleh Compose. Oleh itu, jika output berbeza daripada jangkaan anda, output tersebut adalah betul.
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 membiarkan ${VAR} tanpa pengembangan. Gunakannya sebelum menampal output di mana-mana, kerana config biasa mencetak setiap rahsia yang telah diselesaikan dalam teks jelas. --services hanya menyenaraikan nama perkhidmatan. Ini ialah cara pantas untuk mengesahkan bahawa include telah menarik perkara yang anda jangkakan.
Mod kegagalan dan perkara yang akan anda lihat
no configuration file provided: not found. Compose tidak menemui kandungan untuk dibaca. Anda berada di luar direktori projek, atau COMPOSE_FILE menamakan laluan yang tidak wujud. Compose mencari fail asas lalai dalam direktori induk, tetapi tidak mencari fail yang anda namakan sendiri di mana-mana lokasi lain.
WARN[0000] The "POSTGRES_PASSWORD" variable is not set. Defaulting to a blank string. Interpolasi diselesaikan berdasarkan fail projek .env dan persekitaran shell. Direktori projek di sini ialah direktori bagi fail -f yang pertama. Jika anda membuat deployment dari direktori yang berbeza daripada direktori yang mengandungi .env, amaran ini akan dipaparkan dan pangkalan data kemudiannya menolak setiap sambungan.
Edit override anda tidak dipaparkan dalam docker compose config. Sama ada anda menghantar -f, yang mematikan pemuatan override secara automatik, atau Compose menemui compose.yaml dalam direktori induk dan fail override anda tidak berada bersebelahan dengannya. Menjalankan docker compose config tanpa argumen lain akan menunjukkan model yang sebenarnya sedang dibina oleh Compose.
Bind mount kosong dan Docker mencipta direktori yang tidak anda minta. Laluan relatif diselesaikan berdasarkan direktori fail pertama. Betulkan laluan itu, hantar --project-directory, atau pindahkan fragmen tersebut ke belakang include.
Kontena kembali dengan nama baharu dan volume kelihatan kosong. Nama projek berubah kerana nama projek mengikut direktori fail pertama. Tambahkan name: peringkat teratas pada fail asas supaya penamaan tidak lagi berubah. Volume lama masih berada di bawah awalan lama, dan docker volume ls akan memaparkannya.
Port yang anda buang dalam override masih terbuka. Cantuman ports menambah entri dan bukannya menggantikannya. Sahkan dengan docker compose config, kemudian gunakan !override atau pindahkan ports keluar daripada fail asas.
FAQ
Adakah Compose memuatkan compose.override.yaml secara automatik?
Ya, apabila anda menjalankan docker compose tanpa bendera -f. Compose mencari compose.yaml atau docker-compose.yaml dalam direktori kerja dan direktori induknya. Jika fail override berada dalam direktori yang sama, fail itu dimuatkan kemudian. Nama yang diiktiraf ialah compose.override.yaml, compose.override.yml, docker-compose.override.yml dan docker-compose.override.yaml. Menyertakan mana-mana -f akan melumpuhkan tingkah laku ini. Oleh itu, docker compose -f compose.yaml up hanya membaca satu fail.
Apakah tertib penggabungan beberapa fail -f?
Dari kiri ke kanan. Compose membina konfigurasi mengikut tertib fail yang anda berikan. Setiap fail mengatasi dan menambah konfigurasi daripada fail sebelumnya. Oleh itu, fail terakhir pada baris perintah akan mengatasi sebarang konflik. Senarai yang sama mesti digunakan untuk setiap perintah dalam projek tersebut. COMPOSE_FILE=compose.yaml:compose.prod.yaml digunakan untuk tujuan ini.
Mengapakah port saya masih diterbitkan selepas saya mengatasinya?
Kerana entri ports dikenal pasti berdasarkan keseluruhan set ip, target, published dan protocol. Pengatasan 127.0.0.1:8080:80 terhadap asas 8080:80 berbeza pada bahagian ip. Oleh itu, Compose menganggapnya sebagai port kedua dan mengekalkan kedua-duanya. Jalankan docker compose config untuk melihat kedua-dua entri tersebut. Gunakan ports: !override pada Compose v2.24.4 atau yang lebih baharu. Sebagai alternatif, keluarkan ports daripada fail asas supaya tiada nilai untuk digabungkan.
Apakah perbezaan antara include dengan -f?
-f melapiskan beberapa fail ke dalam satu aplikasi. Setiap laluan relatif dalam setiap fail diselesaikan berbanding direktori fail pertama. include memasukkan aplikasi Compose yang berasingan. Setiap laluan yang disertakan mengekalkan direktori projeknya sendiri. Oleh itu, laluan relatifnya diselesaikan berbanding direktori tersebut. Gunakan -f untuk lapisan persekitaran dalam stack anda sendiri. Gunakan include untuk fragmen yang diselenggarakan di tempat lain. include memerlukan Compose v2.20.0 atau yang lebih baharu.
Bagaimanakah saya mengalih keluar nilai yang ditetapkan oleh fail asas?
Gunakan teg !reset pada Compose v2.24 atau yang lebih baharu. Tulis ports: !reset [] atau MY_VAR: !reset null dalam fail pengatas. Atribut tersebut akan kembali kepada nilai lalai atau null. Nilai yang diberikan kepada teg itu diperlukan tetapi diabaikan. Jika anda mahu menggantikan atribut dan bukannya mengosongkannya, !override melakukannya. Ciri ini memerlukan v2.24.4 atau yang lebih baharu.