Docker Desktop for Windows 啟動的容器無法透過遠端連接的靈異事件簿 | The Will Will Web

The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

Docker Desktop for Windows 啟動的容器無法透過遠端連接的靈異事件簿

今天因為要維護一個 11 年前完工的專案,特別把當時的 VM 還原到 Hyper-V 裡面執行,而 SQL Server 的部分我就打算直接跑在容器中。因為我的 VM 跑在 External network 網路下,所以等同於是區域網路的另一台電腦要連到我的 SQL Server on Linux 容器。照理說這應該只是個很簡單的問題,但是我的 VM 就是怎樣也連不到我這台電腦的 SQL Server 容器,網路就是打不通!最後搞了一整個上午,才真正釐清真相!

直接公布答案

本次事件最大的元兇其實就是「Windows Firewall」,有兩條 Inbound rules (連入規則) 明確阻擋了 Docker Desktop Backend 程式 (C:\program files\docker\docker\resources\com.docker.backend.exe) 從 Public 網路進來的連線!

唉~你一定覺得很蠢對不對!請繼續看一下,事情通常不是憨人想得這麼簡單!

關於 Windows 安全性警訊 (Windows Security Alert)

我相信很多人都看過以下的 Windows 安全性警訊畫面:

Windows 安全性警訊

尤其是電腦剛安裝好之後,這種畫面會經常出現,有時候還會覺得有點煩,不就是要叫我按個「允許存取」嗎,幹嘛每次都要問我?但隨著電腦越用越久,這個視窗出現的頻率也會日益下降,所以也就不以為意了。

許多人不知道,一台電腦其實可能會有很多網路介面(Network Interface),每個網路介面決定了你的網路封包出入口。如果你只有一個網路介面,那就意味著只有這個介面會接收到其他電腦傳來的封包。

以我的電腦為例,我就有 10 個網路介面。有 2 個是 VPN 網路,撥接的時候才會通。有 6 個是 Hyper-V 的虛擬網路介面,主要由 Hyper-V 進行管理。另外有 2 張實體的網路卡,但只有使用一張而已,另一張並沒有接上網路線。

Network Connections

你可以從我上圖的畫面看到,目前我這台電腦真正對外的網路介面其實只有 vEthernet (LAN_Bridge) 這項。

你也從我的上述截圖發現,其實我主要的網路介面預設已經選用了 公用網路 (Public networks) 這個網路類別

這裡我就要先問大家一個問題:

請問你的 PC 擺在家裡,家裡有一個封閉的區域網路,當你只有一個網路介面時,應該設定為哪一種網路類別?

  1. 公用網路 (Public networks)
  2. 私人網路 (Pviate networks)

我覺得應該很多人沒認真想過這個問題,連我自己都沒有特別在意,反正電腦可以上網就好,家裡也只有一個網段,選擇哪一個有差嗎?我告訴你:還真的有差!

學習如何切換網路介面的網路類別

變更網路類別很有可能會影響你目前的應用程式連接網路的狀況,主要影響的範圍還是在「從其他電腦連到你的電腦」的情況,如果你的電腦有跑許多需要遠端存取的服務,很有可能會導致服務突然連不上的狀況,這個部分稍後會做說明。不過,這對大部分使用者來說不會受到太多影響。

  • 取得目前網路介面的連線設定資訊

    Get-NetConnectionProfile
    
    Name             : 網路
    InterfaceAlias   : vEthernet (LAN_Bridge)
    InterfaceIndex   : 11
    NetworkCategory  : Private
    IPv4Connectivity : Internet
    IPv6Connectivity : LocalNetwork
    
  • 將現有的連線設定從 Public 切換到 Private

    Set-NetConnectionProfile -Name "網路" -NetworkCategory Private
    

建議你在切換完現有網路介面網路類別後,全部重置 Windows Firewall 的所有規則,然後進行一次重開機!

請認真選擇 Windows 安全性警訊視窗中的選項

好了,本文的重點來了,最雷的地方就在這裡!🔥

為了能讓 Windows 安全性警訊視窗再次出現,我們有兩種方法:

  1. 刪除掉原本建立好的防火牆規則

    因為連入規則很多,你可能不知道該刪除哪一個,所以第二個選項也不錯。

  2. 重置 Windows Firewall 所有連入規則(重置之前建議可以先匯出備份)

    Windows Defender Firewall with Advanced Security

這裡我們用 Python 3.x 來執行 http.server 應用,直接開啟一個監聽 Port 8000 的 HTTP 伺服器:

python -m http.server 8000

當你第一次執行 python 命令時,Windows 10 會自動開啟 Microsoft Store 自動幫你下載安裝 Python 工具。

以下就是開啟 Windows 安全性警訊視窗的各種魔鬼細節:

Windows 安全性警訊

  1. 認識幾個重要欄位

    名稱:應用程式的名稱

    發行者:應用程式的發行者名稱

    路徑:要「允許」或「封鎖」的應用程式路徑

  2. 預設值的勾選邏輯

    我以前並沒有特別注意為什麼有些電腦預設會勾選 私人網路,有些電腦會預設勾選 公用網路,但這次事件讓我相當清楚了。

    如果你的預設網路介面被歸類在公用網路 (Public networks),這個視窗預設就會幫你勾選公用網路 (Public networks) 選項。

    如果你的預設網路介面被歸類在私人網路 (Private networks),這個視窗預設就會幫你勾選私人網路 (Private networks) 選項。

    你可以兩個都勾選,畢竟大部分人的桌上型電腦並不會一直頻繁的移動,所以選哪個都沒關係!

    如果你用筆電的話,大部分的 Wi-Fi 上網用的網路介面預設會被選在公用網路 (Public networks),當你不希望用 Wi-Fi 上網時「可能」會有人連到你的電腦,那你的有線網路就選擇 私人網路 類型吧!

    像我的電腦預設網路介面就被選在公用網路,我今天已經手動調整為私人網路了,畢竟是家裡的網路嘛!

  3. 如果你直接按下 取消 按鈕

    按下 取消 的背後,並不是真的 取消,而是建立一筆 封鎖 的規則,很意外吧!🔥

    除此之外,如果你手賤按到 ESC 按鍵,跳開了這個 Windows 安全性警訊視窗,也是一樣得到 封鎖 的命運!

    具有進階安全性的 Windows Defender 防火牆

發生本次事件的主因

其實每個人的電腦用了幾年之後,Windows 防火牆的規則數量少說都兩三百條以上,你根本不可能一條一條看完。我在解決本次問題的時候,並不是沒有想到這裡的設定,我確實也看了,真的有 Docker Desktop Backend 這條防火牆規則,而且也是啟用允許的狀態,所以我就直覺的往其他地方排查問題。

我真的再次把 Windows Containers 的官方文件再看完一遍,尤其是網路的部分,看有沒有遺漏的部分,結果看不出異樣。

然後再把 Docker Desktop for Windows 的官方文件也看過一輪,真的認真看完了,還是無解。

我也到處搜尋各種解決方法,也到 Docker Desktop for Windows 的 GitHub Repo 查找問題,也完全找不到相關的問題,完全苦手。

讓我最納悶的地方,就是為什麼我遇到的問題,完全沒有人在討論?我又再次陷入膠著,滿腦子充滿著奇怪的想法:

  • 什麼爛東西,肯定沒什麼人在用 Windows Container 才沒人討論吧!
  • Windows Container 就是爛,我用 Linux Container 從來沒遇到這麼多鳥事!
  • Docker Desktop for Windows 出了好幾代,每代的網路架構都不同,這次肯定又遇到了什麼詭異問題!

由於我從一開始就排除了 Windows Firewall 的問題,這是最大的敗筆!😢

最後,我嘗試找出我的 Windows Firewall 的所有連入規則,這才發現一個驚人的規則:

Get-NetFirewallRule | where { $_.Name -like "*docker*" } | ft

原來我的電腦不是只有兩條名為 Docker Desktop Backend允許規則,還有兩條不知道何年何月何日加入的 com.docker.backend 規則,重點是這兩條 com.docker.backend.exe封鎖規則啊,是封鎖,是封鎖,是封鎖

我猜想應該是 Docker Desktop for Windows 早期的版本沒有設定「應用程式名稱」,所以直接拿執行檔名稱當作應用程式名稱,這才會造成不同時期建立了兩份不同的防火牆規則名稱!

重點是你在 具有進階安全性的 Windows Defender 防火牆 視窗中,這兩條規則根本不會排序在一起(一個是 D 開頭、一個是 c 開頭),在我的電腦裡面,所有 D 開頭的 Rules 就快一頁,而 c 開頭的 Rules 有兩頁之多啊!

最後,我將這兩條名為 com.docker.backend.exe封鎖規則刪除,所有 Docker 網路的問題就全部恢復正常了!😃

後記

當我最後知道是 Windows Firewall 搞的鬼之後,我的心情五味雜陳。一來覺得自己怎麼這麼笨,這麼簡單的問題都沒想到。二來覺得很生氣,他娘親的不知道是誰把我的防火牆設定調整成封鎖遠端連接(應該是之前的),而且前後版本的防火牆規則名稱竟然不一樣(氣)。三來覺得很開心,釐清問題之後,相同的問題大概不會再困擾我了。

最後總結一下幾點本文重點:

  1. 我覺得更換網路類別之後重置 Windows Firewall 所有連入規則是個不錯的作法,這樣可以讓你重新檢視整台電腦所有應用程式使用網路的狀況!
  2. 防火牆規則包含 啟用/停用允許/封鎖 狀態,然後還有 設定檔網路介面的網路類別 之間的關係也非常重要!
  3. 看到 Windows 安全性警訊 視窗千萬要注意你到底要允許封鎖,而且不能不選擇
  4. 如果真的選錯設定,可以立刻透過 wf.msc 命令開啟 具有進階安全性的 Windows Defender 防火牆 介面進行調整!(不馬上調整日後肯定就忘了)

相關連結