SSD Nodes Learn Hosting plans →
Panduan Matt ConnorOleh Matt Connor · Dikemas kini 2026-08-07

Cara Rangkaian Docker Compose Berfungsi

Ketahui cara Docker Compose mengurus rangkaian peribadi, DNS berdasarkan nama servis, dan penggunaan mod host. Artikel ini menjelaskan cara port terdedah memintas UFW.

Apa yang dibina oleh Compose sebelum aplikasi anda bermula

Rangkaian Docker Compose bermula dengan satu peraturan: docker compose up mencipta rangkaian peribadi untuk projek tersebut, menyambungkan setiap servis kepadanya, dan membolehkan servis-servis tersebut berhubung antara satu sama lain menggunakan nama servis. Anda tidak perlu menulis sebaris pun networks: untuk mendapatkannya. Kebanyakan kekeliruan mengenai rangkaian Compose berpunca daripada ketidaktahuan bahawa tetapan lalai tersebut sudah tersedia.

Berikut adalah fail kecil. Simpannya sebagai compose.yaml di dalam direktori bernama shop.

services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example

Jalankan ia dan lihat apa yang telah dibina oleh Docker:

docker compose up -d
docker network ls

Senarai tersebut kini mengandungi rangkaian bernama shop_default. Compose menamakannya <project>_default, dan nama projek secara lalai mengikut nama direktori dalam huruf kecil. Anda boleh mengubahnya dengan docker compose -p myproject up -d atau dengan name: myproject di peringkat atas fail. Drivernya ialah bridge, iaitu suis maya di dalam hos. Setiap kontena mendapat alamat pada subnet peribadi, dan trafik keluar diterjemahkan kepada alamat hos semasa keluar.

docker compose down memadamkan rangkaian tersebut semula. Inilah sebabnya kontena lama daripada projek terdahulu boleh menyebabkan rangkaian kekal terbuka: Docker akan menolak dengan ralat error while removing network: network shop_default has active endpoints, dan penyelesaiannya adalah dengan menghentikan atau memadamkan kontena yang masih bersambung dengannya.

Jika Compose adalah perkara baharu bagi anda, susun atur fail Compose dan arahan kitaran hayat adalah wajar dibaca terlebih dahulu, kerana segala maklumat di bawah mengandaikan anda sudah tahu cara untuk memulakan dan menghentikan sesuatu projek.

DNS mengikut nama servis adalah bahagian yang sering terlepas pandang oleh pemula

Pada mana-mana rangkaian yang ditentukan pengguna, Docker menjalankan pelayan DNS terbenam yang dilihat oleh setiap kontena pada 127.0.0.11. Ia meleraikan nama servis kepada alamat kontena semasa. Jadi web mencapai pangkalan data pada nama hos db, pada port 5432, tanpa sebarang konfigurasi langsung.

docker compose exec web getent hosts db

Perintah itu mencetak baris seperti 172.18.0.2 db. Jika ia tidak mencetak apa-apa, kedua-dua servis tersebut tidak berada pada rangkaian yang sama.

Kesilapan yang hampir dilakukan oleh semua orang sekali adalah menggunakan localhost dalam konfigurasi aplikasi. Di dalam kontena, localhost ialah kontena itu sendiri, bukan hos dan bukan servis yang lain. Klien Postgres melaporkannya dengan jelas:

could not connect to server: Connection refused
	Is the server running on host "localhost" (127.0.0.1) and accepting
	TCP connections on port 5432?

Rentetan sambungan sepatutnya ialah postgresql://postgres:example@db:5432/postgres. Bahagian hos ialah nama servis tersebut.

Dua perincian yang menjimatkan masa kemudian hari. Nama meleraikan kepada apa sahaja yang sedang berjalan sekarang, jadi docker compose up -d --scale web=3 memberikan satu nama dengan tiga alamat, dan klien yang menyimpan cache DNS selama-lamanya akan terikat pada kontena yang telah mati. Selain itu, rangkaian bridge legasi yang digunakan oleh docker run biasa tanpa --network tidak mempunyai peleraian nama langsung, itulah sebabnya nasihat mengenai pautan kontena dari tahun 2016 tidak sepadan dengan apa yang anda lihat.

You do not need ports: to connect two services

ports: publishes a container port on the host. It is for traffic arriving from outside Docker. It has nothing to do with service-to-service traffic, which already works across the whole port range on the project network.

So the ports: - "5432:5432" many people add to their database service does no good and real harm: it exposes Postgres on the public interface of the server. Delete it. If you want it reachable from your laptop for a migration, bind it to loopback with "127.0.0.1:5432:5432" and reach it over an SSH tunnel. The difference between a listening socket, a published port, and a firewall rule is covered in how ports and listening services work on Linux.

expose: is documentation only under Compose. It does not open anything, because nothing was closed between containers on the same network.

Apabila network_mode host adalah pilihan yang tepat, dan kosnya

Mod host membuang namespace rangkaian bekas (container) dan membenarkan proses menggunakan antara muka (interface) hos secara terus.

services:
  probe:
    image: alpine:3.20
    network_mode: host
    command: sleep infinity

Terdapat sebab yang kukuh untuk menggunakan mod ini. Proses yang perlu melihat trafik broadcast atau multicast pada rangkaian setempat, seperti penemuan peranti untuk pelayan media atau hab automasi rumah, tidak dapat melihatnya dari sebalik bridge, kerana bridge tidak memajukan trafik tersebut ke dalam bekas. Ejen pemantauan yang membaca pembilang antara muka hos memerlukan antara muka hos tersebut. Selain itu, anda melangkau langkah terjemahan alamat, yang penting pada kadar paket yang tinggi.

Kosnya adalah khusus.

ports: berhenti berfungsi. Docker memberi amaran bahawa port yang diterbitkan (published ports) akan diabaikan apabila menggunakan mod rangkaian host, dan bekas akan mengikat (bind) apa sahaja yang diikat oleh prosesnya. Dua bekas dalam mod host yang mahukan port 8080 akan bertembung, dan bekas kedua akan mati dengan bind: address already in use.

Resolusi nama mengikut nama servis hilang dalam kedua-dua arah. Bekas tersebut tidak berada dalam rangkaian projek, jadi ia tidak dapat menyelesaikan db, dan servis lain juga tidak dapat menyelesaikannya. Ia hanya boleh mencapai servis lain melalui port yang diterbitkan pada hos, biasanya pada 127.0.0.1.

Pengasingan (isolation) hilang. Proses yang mengikat 0.0.0.0 di dalam bekas mod host akan mendengar pada setiap antara muka pelayan anda, termasuk antara muka awam, sama seperti pakej yang dipasang dengan apt. Terdapat satu kelebihan: trafik ini mengikuti laluan input biasa, jadi peraturan UFW akan terpakai kepadanya, yang tidak berlaku pada port yang diterbitkan.

Mod host ialah ciri Linux Docker Engine. Docker Desktop menyokongnya hanya dari versi 4.34 ke atas dan hanya selepas anda mendayakannya, dengan had tambahan bahawa bekas tidak boleh mengikat alamat IP hos dan hanya TCP serta UDP yang dikendalikan. Jika separuh pasukan anda menggunakan pelayan Linux dan separuh lagi menggunakan Docker Desktop, jangkakan fail yang sama akan berkelakuan berbeza.

Gunakan mod host apabila anda memerlukan antara muka hos. Jangan gunakannya untuk menyelesaikan masalah sambungan, kerana ia biasanya menggantikan satu masalah dengan masalah yang lebih sukar.

Menyambungkan dua projek Compose dengan rangkaian luaran

Rangkaian yang dicipta oleh satu projek tidak dapat dilihat oleh projek lain. Itulah sebabnya reverse proxy dalam proxy/compose.yaml tidak dapat melihat aplikasi dalam app/compose.yaml, walaupun berada pada pelayan yang sama. Penyelesaiannya ialah rangkaian yang tidak dimiliki oleh mana-mana projek.

Cipta rangkaian tersebut sekali sahaja, secara manual:

docker network create edge

Kemudian, isytiharkan rangkaian tersebut sebagai luaran (external) dalam setiap projek. Bahagian proksi:

services:
  proxy:
    image: traefik:v3.1
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - edge

networks:
  edge:
    name: edge
    external: true

Bahagian aplikasi:

services:
  app:
    image: nginx:1.27
    networks:
      - edge
      - internal
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example
    networks:
      - internal

networks:
  edge:
    name: edge
    external: true
  internal:

external: true memberitahu Compose untuk menyambung kepada rangkaian sedia ada dan bukannya mencipta rangkaian baharu, serta membiarkannya kekal di tempatnya semasa docker compose down. Kunci name: yang berasingan adalah lebih penting daripada yang kelihatan: tanpanya, Compose akan mencari rangkaian yang bernama tepat seperti edge, manakala dengannya, anda boleh menamakan rangkaian tersebut dengan satu nama dalam fail anda dan nama lain pada hos.

Jika rangkaian tersebut tidak wujud, Compose enggan bermula dan melaporkan bahawa rangkaian telah diisytiharkan sebagai luaran tetapi tidak dapat ditemui. Cipta rangkaian tersebut terlebih dahulu.

Perhatikan tindakan fail aplikasi dengan internal. Pangkalan data hanya berada pada rangkaian setempat projek tersebut, jadi proksi tidak dapat mencapainya dan hanya app yang boleh. Menambah internal: true di bawah rangkaian akan melangkah lebih jauh dengan membuang laluannya ke dunia luar sepenuhnya. Ini merupakan tetapan lalai yang baik untuk pangkalan data, dengan satu kos yang perlu diketahui sebelum anda menetapkannya: kontena pada rangkaian dalaman tidak boleh memuat turun apa-apa, jadi entrypoint yang menjalankan apt-get update atau pip install semasa permulaan akan tergantung dan kemudian gagal dengan ralat timeout.

Untuk persediaan lengkap dengan peraturan penghalaan dan sijil, lihat menjalankan beberapa aplikasi di belakang satu instans Traefik.

Port yang diterbitkan memintas UFW

Ini adalah bahagian rangkaian Compose yang boleh menjadi insiden keselamatan. Anda menerbitkan port, anda menyemak bahawa UFW aktif dan menolak segala-galanya kecuali SSH, namun servis tersebut masih boleh dicapai dari internet.

sudo ufw status
curl http://203.0.113.10:8080

UFW menyatakan port tersebut disekat. curl tetap memaparkan halaman tersebut. Tiada apa-apa yang rosak. Docker menulis peraturan terjemahan alamat dan penghantaran (forwarding) miliknya sendiri terus ke dalam iptables, dan trafik ke port kontena yang diterbitkan dihantar terus ke kontena dan bukannya dihantar ke hos, jadi ia tidak pernah melalui rantaian yang diuruskan oleh UFW untuk trafik yang ditujukan kepada hos tempatan. Peraturan Docker juga dipadankan sebelum peraturan UFW.

Penyelesaian ringkasnya adalah dengan menerbitkan port hanya di tempat yang anda perlukan:

    ports:
      - "127.0.0.1:8080:80"

Ini mengikat bahagian hos kepada loopback, jadi port tersebut hanya boleh dicapai dari pelayan itu sendiri dan melalui terowong SSH, dan tidak dari tempat lain. Letakkan titik masuk awam di belakang reverse proxy yang menerbitkan port 80 dan 443 secara sengaja. Penjelasan penuh, termasuk rantaian DOCKER-USER bagi kes di mana anda perlu menapis port yang diterbitkan, terdapat dalam mengapa Docker menerbitkan port terus memintas UFW dan cara membaikinya.

Cara menyahpepijatnya dalam empat arahan

Mulakan dengan menyemak rangkaian sebenar bagi setiap container:

docker network inspect shop_default

Blok Containers menyenaraikan setiap container yang disambungkan berserta alamatnya. Servis yang tiada dalam senarai tersebut berada pada rangkaian berbeza, dalam mod host, atau tidak berjalan.

Uji resolusi nama daripada container sementara yang disambungkan pada rangkaian yang sama, supaya anda tidak perlu memasukkan sebarang alatan ke dalam imej anda sendiri:

docker run --rm --network shop_default busybox nslookup db
docker run --rm --network shop_default busybox nc -zv db 5432

nslookup yang gagal menunjukkan masalah pada resolusi nama atau keahlian rangkaian. nslookup yang berjaya manakala nc gagal bermakna servis sedang berjalan tetapi tidak mendengar pada port tersebut, atau ia mendengar pada 127.0.0.1 di dalam containernya sendiri dan bukannya 0.0.0.0. Masalah terakhir ini biasa berlaku pada pelayan pembangunan, dan penyelesaiannya terletak pada alamat bind aplikasi, bukan pada Docker.

Satu lagi kegagalan yang kelihatan seperti pepijat Docker. Jika container boleh berkomunikasi antara satu sama lain tetapi tidak dapat mencapai mesin pada rangkaian pejabat atau VPN anda, subnet Docker mungkin bertindih dengan rangkaian tersebut. Docker memperuntukkan alamat daripada 172.17.0.0/16 ke atas secara lalai. Alihkan pool tersebut dalam /etc/docker/daemon.json:

{
  "default-address-pools": [
    { "base": "10.200.0.0/16", "size": 24 }
  ]
}

Kemudian jalankan sudo systemctl restart docker dan cipta semula rangkaian yang terjejas, kerana rangkaian sedia ada akan mengekalkan subnet yang digunakan semasa ia dicipta.

FAQ

Mengapa kontena saya tidak boleh menghubungi antara satu sama lain menggunakan nama servis?

Kontena tersebut tidak berada pada rangkaian yang sama. Compose meletakkan setiap servis pada <project>_default secara automatik, tetapi sebaik sahaja anda menambah senarai networks: pada sesuatu servis, senarai tersebut menjadi set rangkaian lengkap untuk servis itu dan rangkaian lalai tidak lagi digunakan. Jalankan docker network inspect <network> dan semak sama ada kedua-dua kontena muncul dalam blok Containers. Semak juga bahawa tiada servis yang menggunakan network_mode: host, kerana kontena dalam mod host tidak berada pada mana-mana rangkaian Docker dan tidak boleh menyelesaikan nama servis.

Adakah saya perlu menerbitkan port untuk satu servis menghubungi servis yang lain?

Tidak. Pada rangkaian Compose, setiap port bagi setiap kontena boleh dicapai oleh kontena lain dalam rangkaian yang sama. ports: wujud hanya untuk mendedahkan kontena kepada trafik dari luar Docker, dan expose: hanyalah dokumentasi. Menerbitkan port pangkalan data merupakan tabiat biasa yang merugikan, kerana ia meletakkan pangkalan data tersebut pada antara muka awam pelayan anda.

Apakah perbezaan antara rangkaian bridge dan host?

Bridge memberikan kontena ruang nama rangkaian dan alamatnya sendiri pada suis maya, dengan penyelesaian nama automatik antara kontena dan trafik keluar yang diterjemahkan. Host memberikan kontena akses terus kepada tindanan rangkaian hos: tiada alamat berasingan, tiada penyelesaian melalui nama servis, tiada penerbitan port, dan tiada pengasingan daripada pendengar lain pada hos. Bridge ialah tetapan lalai dan pilihan yang tepat kecuali jika proses tersebut memerlukan antara muka hos.

Bagaimanakah cara saya menyambungkan kontena daripada dua fail Compose yang berbeza?

Cipta rangkaian kongsi dengan docker network create edge, kemudian isytiharkannya dalam kedua-dua fail dengan external: true dan lampirkan servis yang perlu berhubung. Compose tidak akan mencipta atau memadam rangkaian tersebut. Jika anda melangkau langkah penciptaan, Compose akan enggan bermula dan melaporkan rangkaian sebagai diisytiharkan sebagai luaran tetapi tidak ditemui.

Mengapa kontena saya boleh dicapai dari internet sedangkan UFW menyekat port tersebut?

Ini kerana port yang diterbitkan dikendalikan oleh peraturan penghantaran (forwarding) yang ditambah oleh Docker ke dalam iptables. Peraturan tersebut dipadankan sebelum peraturan UFW, dan trafik yang dihantar tidak melalui rantaian yang ditapis oleh UFW. Ikat (bind) bahagian hos kepada loopback dengan "127.0.0.1:8080:80" dan letakkan sebarang perkhidmatan awam di belakang reverse proxy pada port 80 dan 443.