## 透過 [[Docker]] Daemon 全域設定,統一團隊開發環境 {#sec-b2e039a7f45a} 無論是在本機或伺服器上使用 Docker,我們經常會發現自己不斷地在每個專案的 `docker-compose.yml` 中複製貼上相同的設定。 * 例如,總是將 DNS 設定為 `1.1.1.1` 或 `8.8.8.8` * 固定使用 `json-file` 作為日誌驅動程式,並設定 `max-size=10m` * 還有代理伺服器、不安全註冊表、預設網路範圍等… 將這些設定從**容器個別設定**移至**「主機全域預設值」**,管理起來會更輕鬆。而負責這項任務的正是 **Docker Daemon 全域設定 (`daemon.json`)**。 在下文中,我們將整理: * 該建立什麼檔案 * 該建立在哪裡 * 該如何撰寫 * 在什麼情況下對哪些開發者/團隊有用
## 1. Docker Daemon 的兩種設定方式 {#sec-9c4e8fa25a41} Docker Daemon (`dockerd`) 主要有兩種設定方式: 1. **使用 JSON 設定檔 (`daemon.json`)** ← *推薦* 2. 執行 `dockerd` 時透過 **CLI 旗標**傳遞選項 兩者可以混合使用,但**如果同時指定相同的選項,Daemon 將無法啟動。**例如,若同時在 `--log-driver` 旗標和 `daemon.json` 中設定日誌驅動程式,Docker 將會在啟動階段報錯並終止。 為了統一團隊/伺服器環境,通常建議: >「盡可能將所有設定集中到 `daemon.json` 中,並將旗標的使用降到最低。」 ## 2. `daemon.json` 的位置 {#sec-97a08839a2de} 檔案位置通常是 **`/etc/docker/daemon.json`**。當然,這是指 Linux 環境。 雖然我不確定是否有使用者在 Linux 以外的環境中使用 Docker,但我個人只在 Linux 上使用,因此對其他作業系統並不熟悉。不過,以下表格整理了各作業系統的預設路徑,方便大家查閱: | 環境 | 預設路徑 | 備註 | | --- | ----- | --- | | 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. 基本使用模式:「建立檔案 → 重啟 Daemon」 {#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" } } ``` 2. **預先驗證**設定檔是否有效 ```bash sudo dockerd --validate --config-file=/etc/docker/daemon.json # 若顯示 configuration OK 則表示正常 ``` 3. **重啟** Docker Daemon ```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 Daemon 層級進行統一,會方便許多。 ### 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"` 等選項,**可以只查看特定時間點之後的日誌** * 也可以使用 `-t` 選項(基於標籤/識別符)如 `journalctl -f -t {container_name}`,**精確地查看特定容器的日誌**。 當然,也可以像 `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} 如果公司網路環境必須透過內部代理伺服器才能存取外部網路,與其每次都設定環境變數,不如直接在**Daemon 層級設定代理伺服器**。 ```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 Daemon 拉取映像檔或在建構時使用網路時,都會遵循這些代理伺服器設定。 ### 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-48b9-b9a9-e9514af1ba73.png)