Docker 容器的 DNS 是怎么實現的!

Docker 容器的 DNS 是怎么實現的!

文章圖片

Docker 容器的 DNS 是怎么實現的!

在日常使用 Docker 構建微服務架構的過程中 , 我們經常會遇到一個問題:多個容器之間是如何通過名字互相訪問的?DNS 是怎么做到的?
從底層機制講清楚 Docker 的 DNS 系統

1. 容器間通信的前提:同一個網絡Docker 默認會創建一個叫 bridge 的網橋網絡 。 所有未指定網絡的容器 , 都會被分配到這個 bridge 網絡中 。
在這個默認網絡中 , 雖然每個容器都有一個獨立的 IP 地址 , 但要實現通過容器名訪問其他容器 , 就必須依賴 Docker 提供的 DNS 服務 。
?? 注意:只有在用戶自定義的 bridge 網絡中 , 容器名解析才默認開啟!默認的 bridge 網絡不支持容器名解析!
2. Docker 的內置 DNS 是如何工作的?Docker 在每個容器啟動時 , 會將容器的 /etc/resolv.conf 文件指向一個特殊的 DNS 地址:127.0.0.11
這個地址并不是真的公網 DNS , 而是 Docker Daemon 內置的 DNS 服務器 。
這個 DNS 有以下作用:
  • 解析外部域名(比如訪問百度、Google)
  • 解析容器內部服務名(比如 web db 等容器名)
它的背后是 Docker 的 embedded DNS server , 工作機制大概如下:
1?? 容器發出 DNS 查詢請求(查某個服務名)
2?? 請求發到 127.0.0.11(docker 的內部 DNS)
3?? Docker DNS 根據網絡配置 , 找到對應容器的 IP 地址
4?? 將結果返回給發起請求的容器
3. 實驗驗證:容器名訪問是否生效?我們創建一個自定義網絡 , 并啟動兩個容器測試下
# 創建一個自定義 bridge 網絡docker network create mynet# 啟動容器A , 名字叫 webdocker run -it --rm --name web --network mynet busybox sh# 啟動容器B , 在這個網絡中嘗試 ping webdocker run -it --rm --network mynet busybox sh在 B 容器中輸入:
ping web你會發現 , DNS 能自動解析出 web 的 IP , 這就說明 Docker 的內置 DNS 正常工作啦 ?
4. 自定義服務名(別名)怎么設置?有時候我們希望容器訪問的名字不是容器名 , 而是我們指定的服務名 。 Docker 也支持這一點:
docker run -it --rm \\--network mynet \\--name mydb \\--network-alias database \\busybox sh然后在其他容器中 , 就可以通過 database 這個名字訪問它

5. 與外部 DNS 的協同Docker 的 embedded DNS 并不是萬能的 , 它在無法解析服務名時 , 會把請求轉發給 /etc/resolv.conf 中指定的上游 DNS 。
這意味著:
  • 外部網絡訪問正常(比如你容器內 ping www.baidu.com)
  • 內部容器名也能解析
  • Docker DNS 是中間層代理
這個設計非常巧妙!兼顧了內外網的域名解析 。
6. 容器 DNS 失效的常見問題
  • ? 沒有使用自定義網絡 , 導致 DNS 解析失敗
  • ? 使用了 host 網絡 , 容器直接共享宿主機網絡 , 無法使用 Docker 的 DNS
  • ? 被 resolv.conf 修改或者掛載了宿主機 DNS 文件
  • ? 某些 VPN 環境導致容器 DNS 路由異常
解決方法建議:
  • 盡量使用自定義 bridge 網絡
  • 檢查 /etc/resolv.conf 是否被覆蓋
  • 檢查 Docker 網絡配置 docker network inspect

總結【Docker 容器的 DNS 是怎么實現的!】Docker 容器之間的 DNS 解析 , 其實是靠 Docker Daemon 內置的 DNS 服務(監聽在 127.0.0.11)來實現的 , 它能讓容器通過服務名互相訪問 , 還支持 alias、自定義網絡、多級域名等能力 。

    推薦閱讀