iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0

在前幾篇中,我們介紹了很多功能該怎麼使用,而其中,我想要特別針對volume跟network再多補充一點

volumes 負責解決資料的「持久化」問題,確保我們的資料在容器生命週期結束後依然安然無恙,也就是讓資料活下來。 networks 則負責服務之間的「通訊」問題,讓容器們不再是孤島,而是可以互相溝通、協同作戰的團隊,也就是讓服務聊起來

今天,我們就來徹底搞懂這兩個關鍵角色。

Part 1:Volumes - 資料的安身立命之所

容器本身是「無狀態 (stateless)」且「短暫 (ephemeral)」的。這意味著當你執行 docker compose down 移除容器時,任何在容器內部檔案系統上發生的變更(例如,資料庫寫入的資料、使用者上傳的檔案)都會隨之煙消雲散。這在開發時或許可以接受,但在生產環境中絕對是一場災難。

volumes 就是為了解決這個問題而生。它讓我們能將一塊由 Docker 管理的儲存空間,或是主機上的一個特定路徑,「掛載 (mount)」到容器內部,從而將資料的生命週期與容器本身脫鉤。

在 docker-compose 中,主要有兩種掛載方式:Named Volumes 和 Bind Mounts

1. Named Volumes (命名資料卷) - Docker 官方推薦

這是最推薦的方式,特別是用於儲存應用程式產生的資料,例如資料庫檔案、日誌等。

回顧一下我們的 db 服務:

services:
  db:
    # ...
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

這裡的 db_data:/var/lib/postgresql/data 就是一個 Named Volume。

  • db_data: 我們為這個 Volume 取的名字。

  • :: 分隔符。

  • /var/lib/postgresql/data: 容器內部的路徑,也就是 PostgreSQL 預設存放資料的地方。

我們在檔案最下方透過 volumes: db_data: 來聲明它。這麼做的好處是:

  • 由 Docker 管理:你不需要關心 db_data 到底儲存在主機的哪個實體位置,Docker 會在它自己的特定目錄下(例如 /var/lib/docker/volumes/)管理這塊空間,避免了路徑混亂。

  • 跨平台:無論你的主機是 Linux, macOS 還是 Windows,docker-compose.yaml 檔案都無需修改,Docker 會處理底層差異。

  • 安全且高效:通常比 Bind Mounts 效能更好,也更安全,因為容器內的進程無法輕易修改到主機檔案系統上的任意檔案。

使用時機:當你需要持久化應用程式資料(資料庫、使用者上傳內容、日誌)時,永遠優先考慮 Named Volumes。

2. Bind Mounts (綁定掛載) - 開發與配置的利器

Bind Mounts 則是將主機 (Host) 上的一個已存在的檔案或資料夾,直接掛載到容器內部。它的語法是 HOST_PATH:CONTAINER_PATH

這種方式賦予了我們極大的靈活性,主要用於以下兩種情境:

a. 掛載整個資料夾 (用於程式碼同步)

這是開發時的黃金搭檔。想像一下,你正在開發一個 Node.js 應用,你希望每次修改程式碼後,不用重新 build image 就能立刻看到效果。

# docker-compose.yaml 範例
version: '3.8'
services:
  webapp:
    image: node:18
    # 將目前目錄下的 ./src 掛載到容器的 /app/src
    volumes:
      - ./src:/app/src
    working_dir: /app/src
    command: npm start
    ports:
      - "3000:3000"

在這個例子中,我們將主機上當前路徑下的 src 資料夾,直接映射到容器內的 /app/src。當你在主機上用 VS Code 修改 src/index.js 並存檔時,容器內的 /app/src/index.js 也會即時同步更新。如果你的 Node.js 服務設定了熱重載 (hot-reloading),就能立刻看到變更,極大地提升了開發效率。

b. 掛載單一檔案 (用於注入設定檔)

另一個常見用途是將設定檔掛載進容器,以覆蓋 image 中預設的設定。例如,你想為一個 Nginx 服務提供一個自訂的設定檔。

# docker-compose.yaml 範例
services:
  proxy:
    image: nginx:latest
    volumes:
      # 將主機的 my-nginx.conf 掛載到容器內 Nginx 的預設設定檔路徑
      - ./my-nginx.conf:/etc/nginx/nginx.conf
    ports:
      - "80:80"

這樣一來,我們就可以在專案目錄下直接維護 my-nginx.conf,而不用為了修改一個設定檔就重新建置整個 Nginx image。

常見疑問:掛載前需要在容器內建立資料夾嗎?

答案是:通常不需要

當你使用 Bind Mounts 掛載一個資料夾時,如果容器內的目標路徑(如 /app/src)不存在,Docker 會自動為你建立這個資料夾。

但掛載單一檔案時需要注意:如果目標路徑(如 /etc/nginx/nginx.conf)的上層目錄(/etc/nginx)不存在,Docker 不會自動建立,這會導致錯誤。因此,你必須確保掛載的目標路徑是基於 image 中已存在的目錄結構。

Part 2:Networks - 服務間的溝通橋樑

預設情況下,當你執行 docker compose up,Compose 會為你的專案建立一個專屬的橋接網路 (Bridge Network),並將該專案下的所有服務容器都連接到這個網路上。

這就是為什麼在我們先前的範例中,adminer 容器可以直接透過服務名稱 db 來找到並連線到資料庫容器。Docker 在這個內部網路上提供了一套 DNS 服務,能將服務名稱解析成對應容器的內部 IP 位址。

了解 Docker 的網路模式對於設計應用架構和排查連線問題至關重要。

1. Bridge (橋接模式) - 預設且最常用

  • 隔離性:每個 docker-compose 專案都有自己獨立的 Bridge Network,與主機網路和其他專案的網路是隔離的。這提供了極佳的安全性,A 專案的容器預設無法直接訪問 B 專案的容器。

  • 服務發現:如同前面提到的,在同一個 Bridge Network 內的容器,可以透過「服務名稱」互相訪問。這是微服務架構的基礎。

  • 需要 Port Forwarding:因為網路是隔離的,如果想從外部(例如你的瀏覽器)訪問容器內的服務,就必須透過 ports 關鍵字設定端口轉發 (Port Forwarding),也就是我們熟知的 - "8080:8080"

注意事項:當你設定 ports: - "8080:8080" 時,意味著將主機 (Host) 的 8080 port 映射到容器的 8080 port。主機上的 port 是獨佔資源,如果你同時啟動了另一個也想使用主機 8080 port 的服務,Compose 會報錯。這時你必須修改其中一個,例如改成 - "8081:8080",然後透過 http://localhost:8081 來訪問。

2. Host (主機模式) - 高效能但需謹慎使用

當網路模式設定為 host 時,容器將不會擁有自己獨立的網路空間。它會直接共享主機的網路介面。

services:
  my_service:
    image: some_image
    network_mode: "host"
  • 優點

    • 高效能:網路傳輸效能幾乎等同於在主機上直接執行的程式,因為它省去了網路位址轉換 (NAT) 的環節。

    • 無需端口映射:如果容器內的服務監聽 3000 port,那麼你可以直接在主機上透過 localhost:3000訪問它,不再需要 ports 設定。

  • 缺點

    • 喪失隔離性:這是最大的問題。容器可以直接訪問主機的所有網路服務,也可能與主機上已有的服務發生 port 衝突,安全性較低。
  • 使用時機:適用於對網路效能有極高要求的應用,或者容器需要監聽大量動態 port 的情境。一般業務開發中很少需要用到。

總結

掌握了 volumes 和 networks,你對 Docker Compose 的理解就從「會用」提升到了「精通」。

  • Volumes

    • Named Volumes (my_data:/path):管理應用資料的首選,交給 Docker 處理最省心。

    • Bind Mounts (./src:/path):開發時同步程式碼、掛載設定檔的絕佳工具。

  • Networks

    • Bridge (預設):提供安全的隔離環境和便捷的服務發現,是 99% 場景下的最佳選擇。

    • Host:犧牲隔離性換取極致效能,僅在特殊場景下使用。


上一篇
Day15-docker-compose-簡介-2
系列文
開發環境設定指南及工具分享16
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言