Docker for Mac 的網路問題及解決辦法

用 Docker for Mac 已經很久了,用它跑本地開發環境可以說是非常方便。

但是 Docker for Mac 自誕生以來就一直有一個問題,那就是在宿主機上看不到 docker0,無法訪問容器所在的網路,也就是說不能 ping 通 Docker 給 Container 所分配的 IP 地址。關於這個問題,官方文件有描述:

https://docs.docker.com/docker-for-mac/networking/#there-is-no-docker0-bridge-on-macos

對於 docker run 啟動的 Container 來說,通常會通過 -p 引數對映相應的服務埠,一般不會遇到要直接訪問容器 IP 的情況。

但是當我們在 docker 中執行多個微服務並想進行本地除錯的時候,在 Mac 上卻沒法實現。(--net=host 僅在 Linux 系統上有效,我在這個上邊被坑了兩三個小時 )

┌───────────────────────────────────────────────────────────────┐ │ │ │ ┌──────────────────────────────┐ │ │ macOS │ docker │ │ │ │ │ │ │ │ ┌───────────────┐ │ │ │ │ │ Eureka │ │ │ │ ┌───────────────┐ │ ┌──────▶│172.22.0.2:8761│ │ │ │ │ Order │ │ │ └───────────────┘ │ │ │ │127.0.0.1:8989 │─────┼─┘ ▲ │ │ │ └───────────────┘ │ │ │ │ │ │ │ ┌───────────────┐ │ │ │ │ │ │ User │ │ │ │ └─────────────┼────────▶│172.22.0.3:8080│ │ │ │ │ └───────────────┘ │ │ │ │ │ │ │ └──────────────────────────────┘ │ │ │ └───────────────────────────────────────────────────────────────┘    

例如上圖中,Eureka Server 和 User 服務均存在於容器中,本地除錯 Order 服務。Order 需要呼叫 User,但是我們在本機上是訪問不到 172.22.0.3:8080 的。

Docker for Mac 基本原理

要解決這個問題,得先搞清楚 Docker for Mac 的原理。

我們都知道 Docker 是利用 Linux 的 Namespace 和 Cgroups 來實現資源的隔離和限制,容器共享宿主機核心,所以 Mac 本身沒法執行 Docker 容器。不過不支援不要緊,我們可以跑虛擬機器,最早還沒有 Docker for Mac 的時候,就是通過 docker-machine 在 Virtual Box 或者 VMWare 直接起一個 Linux 的虛擬機器,然後在主機上用 Docker Client 操作虛擬機器裡的 Docker Server。

Docker for Mac Architecture

Docker for Mac 也是在本地跑了一個虛擬機器來執行 Docker,不過 Hypervisor 採用的是 xhyve,而 xhyve 又基於 Mac 自帶的虛擬化方案 Hypervisor.framework,虛擬機器裡執行的發行版是 Docker 自己打包的 LinuxKit,之前用的發行版好像是 Alpine Linux。

總而言之就是 Docker for Mac 跑的這個虛擬機器非常輕量級,效能也會更好。

解決辦法

網路上對於這個問題的解法多種多樣,這裡只說三個常見並靠譜的:

1.放棄 Docker for Mac 換 Docker Toolbox。

實際上就是用 Virtual Box 換掉 xhyve,然後設定容器例項和虛擬機器處於同一網段。

這有點像 “刮骨療傷”,不推薦,畢竟 Docker for Mac 就是為了替代 Docker Toolbox 的。

2.在 Docker for Mac 的虛擬機器裡跑一個 OpenVPN Server,然後從本地連過去。流程如下:

因為 Docker for Mac 在重啟的時候不會保留虛擬機器裡的改動,所以這個 OpenVPN Server 必須要跑在容器裡,並且網路模式需要設定為 host,這樣才可以訪問到所有的 Docker 網路。

使用起來略麻煩,雖說已經有寫好了的 OpenVPN 的配置與指令碼,但是要裝軟體、啟動容器、修改配置等,所以還是不推薦

3.使用 Docker for Mac 裡的一個實驗性功能:SOCKS 代理。

強烈推薦,傻瓜操作,在 docker 沒有啟動的時候也能 “自適應”—— 不用頻繁的來回改代理的配置。

下面就詳細講一下第 3 種。

首先需要安裝一下 jq

然後執行

重啟 Docker for Mac

前往 系統偏好設定 -> 網路 -> 高階 -> 代理

設定 SOCKS 代理:localhost:8888 並儲存、應用

跑個 nginx 看下效果

好了,至此就完事大吉了,可以關機睡覺了。

先關 Docker ……

等等,我怎麼上不了網了?

上邊配置 SOCKS 的方法需要每次在 Docker for Mac 開啟 / 關閉 的時候手動去網路裡配置一下。這就和我們

“人至懶則無敵” 的信仰有點背道而馳了。那麼有沒有解決辦法呢?

有,並且不止一種。

這裡介紹個大家之前常用的 PAC 檔案的方法吧。

下面是我 proxy.pac 檔案的一部分,大家可以參考(都是老司機了,不用說明了吧~)

因為實測現在新的 macOS 系統不支援本地的 PAC 檔案,所以你還得找個空間把這個檔案扔到 “雲上”。

有了 PAC 檔案的 http 地址,我們還是配置需要一次網路,不過這次就不是 “SOCKS 代理” 而是 “自動代理配置”

至此已經趨近完美了。至於這個實驗性的功能嘛,目前看來還是比較穩定的,不過一直沒被加到 Docker for Mac 的介面設定裡,希望官方能早日新增以解放我們吧。

本文作者: Yibo本文連結:
           https://windmt.com/2019/08/30/docker-for-mac-network/版權宣告: 本部落格所有文章除特別宣告外,均採用 BY-NC-SA 許可協議。轉載請註明出處!