## 透過 [[Docker]] 守護程式全域設定,統一團隊開發環境 {#sec-b2e039a7f45a} 無論是在本機還是伺服器上使用 Docker 時,每個專案都會不斷地將相同的設定複製貼上到 `docker-compose.yml` 中。 * 例如,總是將 DNS 設定為 `1.1.1.1`、`8.8.8.8` * 或將日誌驅動程式固定為 `json-file` + `max-size=10m` * 還有代理伺服器、非安全登錄檔、預設網路區段等… 這些設定如果將其從**容器個別設定中獨立出來,作為「主機整體的預設值」**,管理起來會容易得多。 而扮演這個角色的就是 **Docker 守護程式全域設定(`daemon.json`)**。 在下文中,我們將整理: * 什麼檔案 * 應該建立在哪裡 * 如何撰寫 * 在什麼情況下對哪些開發者/團隊有用 等資訊。
## 1. 兩種 Docker 守護程式設定方式 {#sec-9c4e8fa25a41} Docker 守護程式(`dockerd`)主要可以透過兩種方式進行設定: 1. **使用 JSON 設定檔(`daemon.json`)** ← *建議* 2. 執行 `dockerd` 時透過 **CLI 旗標**傳遞選項 兩者可以混合使用,但**如果在兩者中指定相同的選項,守護程式將無法啟動。** 例如,如果同時在 `--log-driver` 旗標和 `daemon.json` 中設定日誌驅動程式,Docker 將在啟動階段報錯並終止。 為了統一團隊/伺服器環境,通常會建議: > 「盡可能將所有設定集中到 `daemon.json` 中,並將旗標的使用降到最低」 這樣做。 ## 2. `daemon.json` 位置說明 {#sec-97a08839a2de} 檔案位置通常是 **`/etc/docker/daemon.json`**,當然這是針對 Linux 環境。 雖然我只在 Linux 環境下使用 Docker,可能有些人會在其他作業系統上使用,但為了方便查看,我將各作業系統的預設位置整理成表格如下: | 環境 | 預設路徑 | 備註 | | --- | ----- | --- | | Linux (一般安裝) | `/etc/docker/daemon.json` | 最常見的情況 | | Linux (透過 snap 安裝的 Docker) | `/var/snap/docker/current/config/daemon.json` | Ubuntu snap 套件 | | Windows Server / Docker Engine | `C:\ProgramData\Docker\config\daemon.json` | | | Docker Desktop (Mac / Windows) | `~/.docker/daemon.json` | | * 這個檔案**預設可能不存在,如果沒有,請手動建立**並使用。 ## 3. 基本使用模式:「建立檔案 → 重新啟動守護程式」 {#sec-875278239b12} 以 Linux 為例,典型的工作流程如下: 1. **撰寫/修改 `daemon.json`** ```json { "dns": ["1.1.1.1", "8.8.8.8"], "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } } ``` 1. **預先驗證**設定檔是否有效 ```bash sudo dockerd --validate --config-file=/etc/docker/daemon.json # 如果顯示 configuration OK 則表示正常 ``` 1. **重新啟動** Docker 守護程式 ```bash sudo systemctl restart docker ``` 從現在開始,新啟動的容器除非有單獨設定,將會**繼承**這些全域設定作為**預設值**。 ## 4. 主要設定:將 DNS 伺服器設為全域固定 {#sec-c284419e45cd} ### 4.1 為何要將 DNS 設為全域? {#sec-78011cf35f17} 如果容器經常遇到「奇怪地無法找到外部 API」或「內部網域無法解析」等問題,這通常是因為它**依賴於主機的 DNS 設定/環境**。 例如: * 整個團隊都希望使用 Cloudflare DNS( `1.1.1.1` ) * 存在只能透過公司內部 DNS 伺服器解析的端點 在這種情況下,與其**每個專案都在 `docker-compose.yml` 中加入 `dns:` 設定**,不如直接在 Docker 守護程式層級進行統一,這樣會方便得多。 ### 4.2 設定範例(`daemon.json`) {#sec-2a85a418cbea} ```json { "dns": ["1.1.1.1", "8.8.8.8"] } ``` 如果已經有 `daemon.json`,只需在根 `{ ... }` 中加入 `"dns": [...]` 項目即可。 > ⚠️ **注意:** DNS 設定會反映在容器內的 `/etc/resolv.conf` 中。對於已經運行的容器不會立即生效,而是從**新啟動的容器開始應用**。 ## 5. 主要設定 2 – 日誌驅動程式與選項全域設定 {#sec-fe09c43b83b1} 容器日誌預設會透過 `json-file` 驅動程式累積在 `/var/lib/docker/containers/...` 下。如果將其設為全域設定,則可以: * 日誌格式 * 日誌儲存位置 * 日誌輪替策略 將這些設定**批次應用於所有容器**。 ### 5.1 預設 json-file 驅動程式 + 輪替 {#sec-26c5fb9056b5} 最常見的模式是「使用 `json-file`,但設定輪替以防止磁碟空間耗盡」。 ```json { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "5" } } ``` 這樣設定後: * 每個容器的日誌檔案大小上限為 `10MB`, * 最多保留 `5個` 檔案, * 超出部分將自動刪除。 ### 5.2 用於集中式日誌收集的驅動程式 (fluentd, journald 等) {#sec-e7499afd6f5d} 對於平台團隊/基礎設施團隊來說,通常會希望將所有容器的日誌發送到**中央日誌系統**。 例如,如果使用 Fluentd: ```json { "log-driver": "fluentd", "log-opts": { "fluentd-address": "localhost:24224", "tag": "{{.Name}}" } } ``` 這樣設定後,即使沒有單獨執行 `docker run --log-driver=...`,所有容器的日誌也會自動發送到 Fluentd。 我個人也相當喜歡 **`journald` 驅動程式**。在 systemd 為基礎的 Linux 環境中,可以將應用程式日誌和 Docker 容器日誌都集中到 journald,並僅透過 `journalctl` 統一查詢、過濾和保留策略。 如果想將 `journald` 作為全域日誌驅動程式,可以這樣設定: ```json { "log-driver": "journald", "log-opts": { "tag": "{{.Name}}" } } ``` 在這裡,由於我們將 `tag` 設定為容器名稱,因此: * 可以透過 `journalctl -f | grep {container_name}` 的形式**快速瀏覽即時日誌**, * 也可以結合 `--since "10m ago"` 等選項,**僅查看特定時間點之後的日誌**, * 或者像 `journalctl -f -t {container_name}` 一樣,使用 `-t` 選項(基於標籤/識別符)**精確地查看特定容器的日誌**。 當然,也可以像 `journalctl -u docker.service` 這樣以單元(unit)為單位查看,但以容器名稱為基準進行過濾會更直觀,且輸入更簡潔,在實際工作中會更常用。 ### 5.3 Compose / 與 `docker run` 的關係 {#sec-8d284e8a0dfd} * **全域的 `log-driver` + `log-opts`** 扮演「預設值」的角色 * 如果個別容器指定 `logging:` (Compose) 或 `--log-driver`、`--log-opt` (CLI),則**僅該容器會被覆寫** 策略建議: * 共通值放在 daemon.json 中 * 特殊服務才個別覆寫 建議採用這種配置。 *** ## 6. 主要設定 3 – 代理伺服器、非安全登錄檔等全域網路設定 {#sec-bc2f973bcb11} 全域設定中還有其他常用選項。 ### 6.1 代理伺服器設定 {#sec-753696ea7a1f} 如果只能透過公司內部代理伺服器存取外部網路,與其每次都設定環境變數,不如在**守護程式層級設定代理伺服器**。 ```json { "proxies": { "http-proxy": "http://proxy.example.com:3128", "https-proxy": "http://proxy.example.com:3128", "no-proxy": "localhost,127.0.0.1,.corp.example.com" } } ``` 這樣一來,當 Docker 守護程式拉取映像檔或在建置時使用網路時,都會遵循此代理伺服器設定。 ### 6.2 非安全登錄檔 (insecure registry) {#sec-fe7d1c14ce8d} 如果必須使用沒有 TLS 的登錄檔(例如用於內部開發): ```json { "insecure-registries": ["my-registry.local:5000"] } ``` 這可能會帶來安全風險,因此請務必注意**僅限於內部測試環境**使用。 *** ## 7. 主要設定 4 – 預設網路區段、儲存驅動程式等 {#sec-efc333459aa9} ### 7.1 自訂預設 bridge 網路區段 {#sec-00d891d2b55d} 當您希望避免與 VPN 或公司內部網路的 IP 位址衝突時: ```json { "default-address-pools": [ { "base": "10.20.0.0/16", "size": 24 } ] } ``` 這樣設定後,當 Docker 建立新的 bridge 網路時,將使用 `10.20.x.0/24` 區段。 ### 7.2 強制指定儲存驅動程式 {#sec-04d867ec1442} 根據 Linux 發行版,預設的儲存驅動程式可能會有所不同。如果團隊決定只使用 `overlay2`: ```json { "storage-driver": "overlay2" } ``` > 實際支援的儲存驅動程式會因作業系統/核心而異,因此務必查閱 `dockerd` 文件和發行版指南。 *** ## 8. 如果您也曾有過這種「似曾相識」的感受,那麼是時候導入它了 {#sec-e2c8a9ca03d5} 您不需要完全了解複雜的基礎設施狀況。如果您最近曾有過以下經驗,那麼現在就是您動手設定 `daemon.json` 的最佳時機。 * **每次啟動新專案時,都必須翻找 `docker-compose.yml` 並複製貼上日誌設定:**如果您仍在從昨天編寫的程式碼中尋找 `max-size` 和 `max-file` 設定並再次貼上,那麼您已經在浪費寶貴的時間了。只要將其設定為全域一次,所有容器都會自動以「精簡模式」啟動。 * **在辦公室運作正常的容器,到了咖啡廳或 VPN 環境就無法連網:**這就是典型的「在我本機環境下可以運作啊?」案例。如果您希望容器在任何網路環境下都能一致地與外部通訊,而不受主機 DNS 設定的影響,那麼固定全域 DNS 就是解決方案。 * **為了解決無數伺服器節點的設定差異而感到手足無措:**您是否因為每個伺服器的 Docker 設定略有不同而導致「幽靈錯誤」而苦惱?只需部署一個 `daemon.json` 檔案,所有伺服器都將遵循相同的規則運行。 *** > 當您厭倦了重複的設定,或者受夠了因環境變化而導致的麻煩時,就是導入此設定的最佳時機。 ## 總結 {#sec-857c80428df3} * Docker 的全域預設值由 **`daemon.json`** 管理。 * 位置通常是 `/etc/docker/daemon.json` * 典型的全域設定範例: * DNS: `"dns": ["1.1.1.1", "8.8.8.8"]` * 日誌驅動程式: `"log-driver": "json-file"`, `"log-opts": {...}` * 代理伺服器、非安全登錄檔、預設網路區段、儲存驅動程式… * 全域設定對於重複性設定以及在不同環境中部署多個節點時非常有用。 如果您仍在 `docker-compose.yml` 或 `docker run` 中重複使用相同的選項,那麼**現在或許是時候將其提升到 `daemon.json` 中**了。 ![Docker 守護程式 daemon.json 設定圖示](https://blog.mikihands.com/media/editor_temp/6/00f7dbc8-f71e-485b-b9a9-e9514af1ba73.png)