﻿# 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 安全性警訊](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/53471e1f92b44a6f2c0f-121853199-33b54800-cd23-11eb-840e-33a010e02192.png)

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

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

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

![Network Connections](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/84d884bb4c7c1c755677-121855319-c7881380-cd25-11eb-93ef-759fab314ca7.png)

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

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

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

> 請問你的 PC 擺在家裡，家裡有一個封閉的區域網路，當你只有一個網路介面時，應該設定為哪一種網路類別？
> 
> 1.  公用網路 (Public networks)
> 2.  私人網路 (Pviate networks)

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

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

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

-   取得目前網路介面的連線設定資訊
    
    ```powershell
    Get-NetConnectionProfile
    ```
    
    ```log
    Name             : 網路
    InterfaceAlias   : vEthernet (LAN_Bridge)
    InterfaceIndex   : 11
    NetworkCategory  : Private
    IPv4Connectivity : Internet
    IPv6Connectivity : LocalNetwork
    ```
    
-   將現有的連線設定從 `Public` 切換到 `Private`
    
    ```powershell
    Set-NetConnectionProfile -Name "網路" -NetworkCategory Private
    ```
    

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

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

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

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

1.  刪除掉原本建立好的防火牆規則
    
    因為連入規則很多，你可能不知道該刪除哪一個，所以第二個選項也不錯。
    
2.  重置 Windows Firewall 所有連入規則（重置之前建議可以先匯出備份）
    
    ![Windows Defender Firewall with Advanced Security](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/d9cde3687c7fe4d20eb3-121857890-a37a0180-cd28-11eb-8b29-caf7f7530506.png)
    

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

```bash
python -m http.server 8000
```

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

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

![Windows 安全性警訊](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/c54b765cd9338ef1557c-121865637-c7414580-cd30-11eb-83d5-9d898602869b.png)

1.  認識幾個重要欄位
    
    **名稱**：應用程式的名稱
    
    **發行者**：應用程式的發行者名稱
    
    **路徑**：要「允許」或「封鎖」的應用程式路徑
    
2.  預設值的勾選邏輯
    
    我以前並沒有特別注意為什麼有些電腦預設會勾選 **私人網路**，有些電腦會預設勾選 **公用網路**，但這次事件讓我相當清楚了。
    
    如果你的預設網路介面被歸類在**公用網路** (Public networks)，這個視窗預設就會幫你勾選**公用網路** (Public networks) 選項。
    
    如果你的預設網路介面被歸類在**私人網路** (Private networks)，這個視窗預設就會幫你勾選**私人網路** (Private networks) 選項。
    
    你可以兩個都勾選，畢竟大部分人的桌上型電腦並不會一直頻繁的移動，所以選哪個都沒關係！
    
    如果你用筆電的話，大部分的 Wi-Fi 上網用的**網路介面**預設會被選在**公用網路** (Public networks)，當你不希望用 Wi-Fi 上網時「可能」會有人連到你的電腦，那你的**有線網路**就選擇 **私人網路** 類型吧！
    
    > 像我的電腦預設網路介面就被選在**公用網路**，我今天已經手動調整為**私人網路**了，畢竟是家裡的網路嘛！
    
3.  如果你直接按下 **取消** 按鈕
    
    按下 **取消** 的背後，並不是真的 **取消**，而是建立一筆 **封鎖** 的規則，很意外吧！🔥
    
    除此之外，如果你手賤按到 `ESC` 按鍵，跳開了這個 Windows 安全性警訊視窗，也是一樣得到 **封鎖** 的命運！
    
    ![具有進階安全性的 Windows Defender 防火牆](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/d5c29b50bfe674022dae-121866972-0b811580-cd32-11eb-81f4-15e93d6e4ed3.png)
    

### 發生本次事件的主因

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

我真的再次把 [Windows Containers](https://learn.microsoft.com/en-us/virtualization/windowscontainers/?WT.mc_id=DT-MVP-4015686) 的官方文件再看完一遍，尤其是網路的部分，看有沒有遺漏的部分，結果看不出異樣。

然後再把 [Docker Desktop for Windows 的官方文件](https://docs.docker.com/desktop/features/networking/)也看過一輪，真的認真看完了，還是無解。

我也到處搜尋各種解決方法，也到 [Docker Desktop for Windows 的 GitHub Repo](https://github.com/docker/for-win/issues) 查找問題，也完全找不到相關的問題，完全苦手。

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

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

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

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

```powershell
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 防火牆** 介面進行調整！（不馬上調整日後肯定就忘了）

### 相關連結

-   [4 Ways To Change Network Type In Windows 10 (Public, Private or Domain)](https://www.itechtics.com/change-network-type-windows-10/)
-   [How to reset your Windows Firewall settings (4 methods)](https://www.digitalcitizen.life/restore-windows-firewall-defaults/)
