
1. 排查思路先搞清楚是誰(shuí)占了這個(gè)端口遇到docker run時(shí)報(bào)端口被占用或者在瀏覽器里訪問(wèn)容器服務(wù)發(fā)現(xiàn)連不上我的第一反應(yīng)從來(lái)都不是急著去改命令而是先回答三個(gè)問(wèn)題宿主機(jī)的端口是不是真的被某個(gè)進(jìn)程占了占了端口的是Windows原生進(jìn)程還是WSL2里的Linux進(jìn)程容器到底有沒(méi)有正常監(jiān)聽那個(gè)端口這三個(gè)問(wèn)題的排查路徑完全不一樣混在一起只會(huì)越查越亂。我見過(guò)不少同事一上來(lái)就netstat -ano看一眼發(fā)現(xiàn)端口有PID就直接taskkill結(jié)果殺完發(fā)現(xiàn)是Windows系統(tǒng)服務(wù)機(jī)器直接出問(wèn)題得不償失。先看第一個(gè)問(wèn)題怎么查。Windows下推薦用系統(tǒng)自帶的netstat配合PID定位進(jìn)程這一步是基礎(chǔ)中的基礎(chǔ)。netstat -ano | findstr :8080這條命令會(huì)把所有包含8080的TCP連接和監(jiān)聽狀態(tài)列出來(lái)最后一列就是進(jìn)程PID。拿到PID之后再用tasklist確認(rèn)是哪個(gè)程序tasklist | findstr 12345如果查出來(lái)的進(jìn)程是你自己開的比如占了8080的是個(gè)Node服務(wù)、Python開發(fā)服務(wù)器、Nginx之類的那你直接關(guān)掉它就行或者換Docker映射端口。但如果查出來(lái)的是System、svchost.exe這種系統(tǒng)進(jìn)程那就得謹(jǐn)慎對(duì)待了千萬(wàn)別亂殺。還有一種情況特別容易踩坑端口在Windows這一側(cè)根本查不到占用但容器啟動(dòng)還是報(bào)錯(cuò)。這時(shí)候問(wèn)題往往出在WSL2內(nèi)部。我在實(shí)際項(xiàng)目里遇到過(guò)一個(gè)典型的案例。某次我在開發(fā)機(jī)上跑一個(gè)MySQL容器映射的是3306端口但Windows本機(jī)明明沒(méi)裝MySQLnetstat也查不到3306被占結(jié)果容器就是啟動(dòng)失敗報(bào)端口沖突。后來(lái)進(jìn)WSL2里查了一下發(fā)現(xiàn)是WSL2的Linux子系統(tǒng)里跑了一個(gè)舊的MySQL實(shí)例占著3306。為什么會(huì)這樣因?yàn)镈ocker Desktop默認(rèn)用的是基于WSL2的后端Windows上的netstat和WSL2內(nèi)部的網(wǎng)絡(luò)棧是隔離開的兩邊各有獨(dú)立的端口占用表。Windows側(cè)看不到WSL2里監(jiān)聽的端口反過(guò)來(lái)也一樣。所以排查的時(shí)候兩個(gè)環(huán)境都得看一遍缺一不可。注意 當(dāng)Docker Desktop使用WSL2后端時(shí)Windows下查不到占用不代表端口就是空閑的。WSL2內(nèi)部的進(jìn)程占用的端口同樣會(huì)導(dǎo)致容器映射失敗排查時(shí)必須兩側(cè)確認(rèn)。下面我把排查步驟總結(jié)成一個(gè)穩(wěn)定可復(fù)用的流程按這個(gè)順序走基本不會(huì)漏# 第一步Windows側(cè)查端口 netstat -ano | findstr :端口號(hào) # 第二步確認(rèn)PID對(duì)應(yīng)的進(jìn)程 tasklist | findstr PID # 第三步進(jìn)WSL2查內(nèi)部監(jiān)聽 wsl -d docker-desktop -u root netstat -tunlp | grep 端口號(hào) # 第四步檢查宿主機(jī)自身服務(wù) # Windows下用 services.msc 或 sc query 確認(rèn)是否有系統(tǒng)服務(wù)綁定該端口這套流程看著簡(jiǎn)單卻能解決絕大多數(shù)端口占用問(wèn)題。關(guān)鍵是記住一個(gè)原則先定位再處理不要瞎猜。端口沖突看起來(lái)只是個(gè)小問(wèn)題但處理不好輕則服務(wù)起不來(lái)重則把系統(tǒng)進(jìn)程誤殺了導(dǎo)致系統(tǒng)不穩(wěn)定那就得不償失了。2. 原理剖析Docker端口映射到底做了什么Docker的端口映射機(jī)制簡(jiǎn)單說(shuō)就是把容器內(nèi)部的端口和宿主機(jī)的端口做一個(gè)綁定關(guān)系。比如你運(yùn)行docker run -p 8080:80 nginx意思就是訪問(wèn)宿主機(jī)的8080端口請(qǐng)求會(huì)被轉(zhuǎn)發(fā)到容器內(nèi)的80端口。這里有個(gè)很多人會(huì)誤解的點(diǎn)Docker的-p參數(shù)指定的是宿主機(jī)端口和容器端口的映射關(guān)系左邊是宿主機(jī)端口右邊是容器端口。容器內(nèi)部的端口一般是固定的由鏡像里的應(yīng)用配置文件決定而宿主機(jī)端口是可以靈活調(diào)整的。所以當(dāng)宿主機(jī)端口被占時(shí)最簡(jiǎn)單的解決辦法就是換一個(gè)宿主機(jī)端口比如把8080改成8081。但換端口只是治標(biāo)不治本。要真正理解端口占用還得知道Docker在Windows上的幾種網(wǎng)絡(luò)模式。在Windows上用Docker Desktop實(shí)際上有幾種不同的網(wǎng)絡(luò)棧在同時(shí)工作Windows原生模式Docker容器直接在Windows的網(wǎng)絡(luò)棧上運(yùn)行端口監(jiān)聽在Windows側(cè)netstat直接能看到。WSL2模式Docker引擎跑在WSL2的一個(gè)特殊發(fā)行版docker-desktop里面端口監(jiān)聽在Linux網(wǎng)絡(luò)棧中Windows側(cè)通過(guò)localhost轉(zhuǎn)發(fā)訪問(wèn)。Docker Desktop默認(rèn)配置下當(dāng)你運(yùn)行docker run -p 8080:80時(shí)Docker引擎會(huì)向WSL2的網(wǎng)絡(luò)命名空間申請(qǐng)綁定8080端口。如果WSL2內(nèi)部的某個(gè)進(jìn)程已經(jīng)占用了這個(gè)端口就會(huì)報(bào)port is already allocated的錯(cuò)誤。另外還有一類常見問(wèn)題大家最容易忽略容器已經(jīng)啟動(dòng)成功了但你在Windows瀏覽器上訪問(wèn)localhost:8080頁(yè)面一直轉(zhuǎn)圈報(bào)連接失敗。這種情況往往不是端口沖突而是Windows防火墻攔截了到WSL2的流量或者Docker Desktop的端口轉(zhuǎn)發(fā)服務(wù)出了問(wèn)題。我見過(guò)一個(gè)有意思的案例某開發(fā)者把Docker Desktop安裝到非默認(rèn)盤符之后發(fā)現(xiàn)所有端口映射都失效了但容器本身是正常運(yùn)行的。查了半天才發(fā)現(xiàn)是Docker Desktop的端口轉(zhuǎn)發(fā)服務(wù)com.docker.backend在系統(tǒng)更新后沒(méi)有正常啟動(dòng)。重啟一下Docker Desktop服務(wù)就好了。所以排查端口占用的時(shí)候腦子里要有這個(gè)意識(shí)端口綁定的完整鏈路是「宿主機(jī)端口 → Windows網(wǎng)絡(luò)棧 → WSL2網(wǎng)絡(luò)棧 → Docker引擎 → 容器內(nèi)端口」。哪一環(huán)出了問(wèn)題表現(xiàn)都可能像“端口占用”。下面我列一個(gè)簡(jiǎn)化的端口映射鏈路表方便理解環(huán)節(jié)作用常見問(wèn)題宿主機(jī)端口外部訪問(wèn)入口被Windows進(jìn)程占用Windows網(wǎng)絡(luò)棧轉(zhuǎn)發(fā)到WSL2防火墻攔截、服務(wù)未啟動(dòng)WSL2網(wǎng)絡(luò)棧容器引擎監(jiān)聽內(nèi)部進(jìn)程占用端口Docker引擎端口綁定管理配置沖突、端口池被占容器內(nèi)端口應(yīng)用服務(wù)端口容器內(nèi)應(yīng)用啟動(dòng)失敗理解了這條鏈路后面所有解決方案都會(huì)變得順理成章。3. 解決方案不同場(chǎng)景下的端口占用處理實(shí)操3.1 換端口最快最小化的臨時(shí)方案如果只是本地開發(fā)調(diào)試端口沖突的時(shí)候換一個(gè)端口往往是最省事的。不需要?dú)⑦M(jìn)程不用動(dòng)系統(tǒng)配置風(fēng)險(xiǎn)幾乎為零。舉例來(lái)說(shuō)你本來(lái)想啟動(dòng)一個(gè)Redis容器默認(rèn)映射6379端口結(jié)果被占用了。直接換一個(gè)映射端口docker run -d --name my-redis -p 6380:6379 redis:7命令里的-p 6380:6379把宿主機(jī)的6380端口映射到容器內(nèi)的6379端口。這樣Redis在容器里還是監(jiān)聽6379但從外部訪問(wèn)就要用6380了。這里有一個(gè)配套動(dòng)作需要注意如果你的應(yīng)用代碼里寫死了Redis連接地址為localhost:6379那么換端口之后代碼里的連接配置也得同步改成localhost:6380否則應(yīng)用連不上Redis。我在項(xiàng)目里就因?yàn)檫@個(gè)吃過(guò)虧改完Docker命令忘了改配置排查了半天還以為是容器沒(méi)起來(lái)。格式化地說(shuō)換端口要做的配套工作有三個(gè)修改docker run命令或docker-compose.yml里的端口映射配置。修改依賴該服務(wù)的所有客戶端連接配置。如果這個(gè)端口被其他人或團(tuán)隊(duì)共用記得同步通知變更信息。3.2 殺進(jìn)程清理Windows側(cè)原生占用換端口只是繞開問(wèn)題如果這個(gè)端口必須保留比如是約定好的對(duì)外服務(wù)端口那就得把占用它的進(jìn)程處理掉。上一節(jié)提到的排查流程已經(jīng)幫你定位到了PID接下來(lái)分兩種情況處理情況一自己?jiǎn)?dòng)的開發(fā)進(jìn)程比如占了端口的是你之前啟動(dòng)的一個(gè)Node開發(fā)服務(wù)直接關(guān)掉對(duì)應(yīng)終端窗口或者用taskkill結(jié)束進(jìn)程taskkill /PID 12345 /F/F是強(qiáng)制結(jié)束的意思。正常情況下先嘗試不帶/F的禮貌關(guān)閉優(yōu)雅終止進(jìn)程比強(qiáng)制殺進(jìn)程更安全能避免一些數(shù)據(jù)寫入中斷導(dǎo)致的問(wèn)題。情況二系統(tǒng)服務(wù)如果端口被系統(tǒng)服務(wù)占用比如HTTP協(xié)議的80端口往往被World Wide Web Publishing Service或SQL Server Reporting Services占用那就要進(jìn)入服務(wù)管理確認(rèn)這個(gè)服務(wù)是不是你需要的。# 查詢服務(wù)狀態(tài) sc query W3SVC # 停止服務(wù)需要管理員權(quán)限 net stop W3SVC關(guān)于net stop和sc stop的區(qū)別我順手補(bǔ)充一下net stop是高層命令會(huì)自動(dòng)處理服務(wù)的依賴關(guān)系相對(duì)友好sc stop更底層可以直接操作服務(wù)狀態(tài)適合在腳本里用。日常手動(dòng)操作net stop就夠用了。注意 不要輕易結(jié)束名字看起來(lái)像系統(tǒng)核心服務(wù)的進(jìn)程。如果端口占用方是System進(jìn)程PID為4不建議直接殺這種情況應(yīng)該換個(gè)端口或者查清楚到底是不是某個(gè)系統(tǒng)組件在監(jiān)聽。強(qiáng)殺系統(tǒng)進(jìn)程可能導(dǎo)致網(wǎng)絡(luò)服務(wù)異常、系統(tǒng)不穩(wěn)定甚至藍(lán)屏風(fēng)險(xiǎn)。3.3 WSL2內(nèi)部占用被忽略的重災(zāi)區(qū)WSL2內(nèi)部端口占用問(wèn)題在Docker Desktop用戶里其實(shí)很常見但很多人壓根沒(méi)往這個(gè)方向想過(guò)。怎么判斷是WSL2內(nèi)部占用最簡(jiǎn)單的辦法是用wsl命令進(jìn)到docker-desktop發(fā)行版里查wsl -d docker-desktop -u root netstat -tunlp注意docker-desktop這個(gè)發(fā)行版是Docker Desktop引擎所在的環(huán)境不是你的日常Linux工作環(huán)境。如果你的容器還跑在業(yè)務(wù)環(huán)境里也可以直接進(jìn)WSL2的主發(fā)行版查wsl -u root netstat -tunlp | grep 端口號(hào)如果發(fā)現(xiàn)端口被WSL2里的一個(gè)進(jìn)程占用了判斷一下這個(gè)進(jìn)程是不是還有用。比如是之前手動(dòng)啟動(dòng)的MySQL、Nginx或者Redis服務(wù)那就通過(guò)Linux的進(jìn)程管理工具關(guān)掉它# 查看進(jìn)程詳情 ps aux | grep redis # 優(yōu)雅停止 kill PID # 如果優(yōu)雅停止無(wú)效再?gòu)?qiáng)制結(jié)束 kill -9 PID這里有個(gè)細(xì)節(jié)值得注意WSL2的Linux環(huán)境里netstat不一定默認(rèn)安裝。如果提示命令不存在可以考慮用ss -tunlp代替這是iproute2包自帶的工具通常更常見。另外部分極簡(jiǎn)環(huán)境可能需要先apt update apt install net-tools。3.4 Docker自身狀態(tài)容器沒(méi)刪干凈、端口池枯竭每次docker run之前Docker都會(huì)檢查端口映射池。如果之前啟動(dòng)過(guò)的容器還存活著哪怕處于退出狀態(tài)它占用的端口映射依然會(huì)被視為“已分配”。我見過(guò)一個(gè)很典型的場(chǎng)景你運(yùn)行了一個(gè)MySQL容器映射3306端口后來(lái)容器被docker stop停掉了但是沒(méi)docker rm刪除。這時(shí)候你再想啟動(dòng)另一個(gè)容器映射同一個(gè)3306Docker會(huì)提示端口被占用。但你以為之前那個(gè)容器已經(jīng)停了就該把端口釋放出來(lái)于是各種懷疑人生。解決方案很簡(jiǎn)單先看這個(gè)端口到底歸屬于哪個(gè)容器docker ps -a --filter publish8080或者直接列出所有容器的端口映射docker ps -a --format table {{.Names}}\t{{.Ports}}找到占用端口的容器之后如果不需要了就徹底清理掉docker rm 容器ID如果需要保留容器但不再使用那就確認(rèn)它確實(shí)處于停止?fàn)顟B(tài)即可停止?fàn)顟B(tài)下的容器端口映射會(huì)釋放。還有一種隱性情況Docker Desktop在Windows上長(zhǎng)期運(yùn)行重啟過(guò)、休眠過(guò)、網(wǎng)絡(luò)切換過(guò)之后端口映射狀態(tài)偶爾會(huì)錯(cuò)亂。此時(shí)最干凈的做法不是反復(fù)重試而是直接重啟Docker Desktop# 重啟Docker Desktop的方式 # 1. 系統(tǒng)托盤找到Docker圖標(biāo)右鍵選擇 Restart # 2. 或者命令行方式 wsl --shutdownwsl --shutdown會(huì)同時(shí)關(guān)閉所有WSL2發(fā)行版。執(zhí)行完再打開Docker Desktop等它重新啟動(dòng)端口映射狀態(tài)通常就恢復(fù)了。注意這個(gè)命令會(huì)把WSL2里正在跑的所有Linux進(jìn)程全部停掉操作前確認(rèn)沒(méi)有重要的開發(fā)服務(wù)在跑。3.5 動(dòng)態(tài)端口和防火墻看起來(lái)像占用但不是占用最后補(bǔ)一個(gè)很容易讓人誤判的情況。有時(shí)候端口本身并沒(méi)有被任何進(jìn)程占用但你就是訪問(wèn)不了容器服務(wù)表現(xiàn)很像“端口被占用”。這類問(wèn)題的根源通常是Windows防火墻攔截。Docker Desktop首次安裝時(shí)通常會(huì)自動(dòng)配置防火墻規(guī)則但公司電腦、加固過(guò)的系統(tǒng)、某些安全軟件可能會(huì)把規(guī)則禁掉導(dǎo)致端口轉(zhuǎn)發(fā)不生效??焖倥挪榉椒ㄅR時(shí)把防火墻對(duì)Docker的規(guī)則打開一下試試。在管理員權(quán)限的PowerShell里執(zhí)行New-NetFirewallRule -DisplayName Docker Inbound -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8080如果加完規(guī)則之后容器服務(wù)就能正常訪問(wèn)了那說(shuō)明問(wèn)題在防火墻而不是端口占用。測(cè)試完之后可以根據(jù)實(shí)際需要保留或刪除規(guī)則。提示 出現(xiàn)端口相關(guān)報(bào)錯(cuò)時(shí)先驗(yàn)證“是否真的是被占用”再驗(yàn)證“訪問(wèn)不通是否真的是端口問(wèn)題”。我見過(guò)很多同事把防火墻問(wèn)題當(dāng)成端口占用排查了半天最后浪費(fèi)了大量工作時(shí)間。4. 常見問(wèn)題速查一張表解決80%的端口占用麻煩我把實(shí)際運(yùn)維中高頻出現(xiàn)的端口占用問(wèn)題整理成了一張速查表按癥狀、原因、解決方案三個(gè)維度劃分遇到問(wèn)題可以直接對(duì)照處理。癥狀可能原因解決方案port is already allocated宿主機(jī)的端口被Windows進(jìn)程占用netstat -ano定位PID確認(rèn)進(jìn)程后結(jié)束或換端口port is already allocatedWSL2內(nèi)部進(jìn)程占用端口wsl -d docker-desktop -u root netstat -tunlp定位kill進(jìn)程port is already allocated之前啟動(dòng)的容器未刪除端口映射仍被占用docker ps -a查找容器docker rm清理容器啟動(dòng)成功但訪問(wèn)不通Windows防火墻攔截添加入站規(guī)則或在防火墻中允許Docker引擎通信容器啟動(dòng)成功但訪問(wèn)不通Docker Desktop端口轉(zhuǎn)發(fā)服務(wù)異常重啟Docker Desktop或者wsl --shutdown后重新啟動(dòng)bind: An attempt was made to access a socket in a way forbidden by its access permissions端口處于TIME_WAIT狀態(tài)或受系統(tǒng)預(yù)留限制用管理員執(zhí)行netsh interface ipv4 show excludedportrange protocoltcp查看系統(tǒng)預(yù)留端口段端口看起來(lái)沒(méi)被占用但啟動(dòng)失敗Windows的Hyper-V保留端口范圍沖突換一個(gè)不在保留范圍內(nèi)的端口或用netsh int ipv4 add excludedportrange調(diào)整保留段最后一行的“端口看起來(lái)沒(méi)被占用但啟動(dòng)失敗”值得展開說(shuō)說(shuō)。Windows系統(tǒng)出于安全考慮會(huì)保留一段動(dòng)態(tài)端口范圍Hyper-V、WSL2、Windows容器等功能都會(huì)使用這個(gè)范圍。如果你映射的端口恰好落在系統(tǒng)保留段里Windows會(huì)拒絕綁定表現(xiàn)就是端口無(wú)人占用但綁定失敗。查詢系統(tǒng)保留端口段的命令如下netsh interface ipv4 show excludedportrange protocoltcp輸出的結(jié)果里會(huì)列出一個(gè)個(gè)端口區(qū)間比如1000-1100、50000-51000之類。如果你的目標(biāo)端口落在這個(gè)范圍里那就不需要再做別的排查了直接換一個(gè)端口最省事。我實(shí)際遇到過(guò)這樣的情況某臺(tái)開發(fā)機(jī)上端口6000到6100正好是Hyper-V保留段我的一個(gè)服務(wù)想映射6000端口反復(fù)確認(rèn)沒(méi)被任何進(jìn)程占用但就是綁定失敗。后來(lái)用上面這條命令一看才發(fā)現(xiàn)是系統(tǒng)保留果斷換到7000端口就一切正常了。5. 預(yù)防與規(guī)范讓端口沖突不再找上門端口占用問(wèn)題看起來(lái)是個(gè)小麻煩但反復(fù)出現(xiàn)就會(huì)明顯拖慢開發(fā)節(jié)奏。我在團(tuán)隊(duì)里推行了一套簡(jiǎn)單的端口管理規(guī)范執(zhí)行下來(lái)之后這類問(wèn)題確實(shí)少了很多。5.1 統(tǒng)一規(guī)劃端口段開發(fā)環(huán)境里的服務(wù)端口不是越多越好而是越清晰越好。我習(xí)慣把不同用途的端口錯(cuò)開規(guī)劃比如Web應(yīng)用統(tǒng)一使用8080-8099段中間件Redis、MySQL、RabbitMQ統(tǒng)一使用6300-6399段API網(wǎng)關(guān)統(tǒng)一使用9000-9099段臨時(shí)調(diào)試服務(wù)使用20000以上端口避免與常用段沖突這樣做的好處是當(dāng)端口沖突發(fā)生時(shí)你一眼就能看出端口是不是規(guī)劃內(nèi)的也更容易判斷是誰(shuí)占用了它。5.2 使用docker-compose管理端口映射命令行里敲docker run -p雖然方便但時(shí)間一長(zhǎng)管理成本很高。端口映射散落在各個(gè)命令歷史里別人接手項(xiàng)目根本不知道端口是怎么規(guī)劃的。用docker-compose.yml統(tǒng)一管理端口映射是更好的實(shí)踐。下面是一個(gè)典型的配置示例services: web: image: nginx:latest ports: - 8080:80 redis: image: redis:7 ports: - 6379:6379配置里端口映射關(guān)系一目了然而且可以作為項(xiàng)目文檔的一部分提交到版本庫(kù)新成員拉下來(lái)項(xiàng)目直接就能啟動(dòng)依賴服務(wù)不用反復(fù)問(wèn)人。5.3 容器生命周期管理不用就清理每次用完容器尤其是臨時(shí)調(diào)試容器記得隨手做一件事docker rm 容器名如果你只是想停掉它用docker stop如果想徹底釋放端口映射就需要docker rm。兩者的區(qū)別就是是否保留容器實(shí)例。長(zhǎng)期堆積的廢棄容器不僅占端口還占磁盤空間月底清理的時(shí)候悔不當(dāng)初。5.4 必要時(shí)用端口動(dòng)態(tài)映射如果只是本地開發(fā)不求固定端口訪問(wèn)可以用-P參數(shù)讓Docker自動(dòng)分配一個(gè)可用的隨機(jī)端口docker run -d -P redis:7然后通過(guò)docker port 容器名查看實(shí)際映射的端口docker port my-redis這個(gè)做法的缺點(diǎn)是端口會(huì)變依賴固定端口的客戶端無(wú)法連接但優(yōu)點(diǎn)是不用擔(dān)心端口沖突適合快速試運(yùn)行鏡像的場(chǎng)景。6. 我踩過(guò)的幾個(gè)坑與最終心得梳理完上面的技術(shù)細(xì)節(jié)最后分享幾個(gè)我親歷過(guò)的典型坑希望能幫讀者省下一些踩坑時(shí)間。第一個(gè)坑是早年把端口占用只當(dāng)作“Windows進(jìn)程占用”來(lái)處理。某次排查一個(gè)端口沖突netstat -ano查了半天愣是沒(méi)看到占用進(jìn)程后來(lái)才發(fā)現(xiàn)是WSL2里的舊服務(wù)占了端口。那次之后我在排查流程里固定加了一步“進(jìn)WSL2查監(jiān)聽”再也沒(méi)有出現(xiàn)過(guò)類似盲區(qū)。第二個(gè)坑發(fā)生在刪容器不徹底的場(chǎng)景。當(dāng)時(shí)一個(gè)測(cè)試庫(kù)容器被我docker stop了我以為端口就釋放了結(jié)果啟動(dòng)新容器時(shí)還是報(bào)沖突。后來(lái)才知道停止?fàn)顟B(tài)的容器依然保留端口映射得docker rm才會(huì)真正釋放。第三個(gè)坑是Windows防火墻。有段時(shí)間我發(fā)現(xiàn)容器怎么都訪問(wèn)不通反復(fù)驗(yàn)證端口占用情況查了整整一個(gè)下午最后無(wú)意中打開了防火墻的高級(jí)配置才發(fā)現(xiàn)入站規(guī)則沒(méi)放行Docker。那種郁悶感現(xiàn)在想起來(lái)還歷歷在目。根據(jù)個(gè)人經(jīng)驗(yàn)處理Windows下Docker端口占用最有效的習(xí)慣是先花兩分鐘把整條端口鏈路的每個(gè)環(huán)節(jié)都過(guò)一遍而不是一上來(lái)就嘗試某種偏方。按排查流程、對(duì)照速查表、逐層定位絕大多數(shù)問(wèn)題都能在十分鐘內(nèi)解決。最后再分享一個(gè)小技巧如果你經(jīng)常在同一臺(tái)開發(fā)機(jī)上切換不同網(wǎng)絡(luò)公司網(wǎng)絡(luò)、家里網(wǎng)絡(luò)、手機(jī)熱點(diǎn)Docker Desktop偶爾會(huì)出現(xiàn)網(wǎng)絡(luò)棧狀態(tài)異常導(dǎo)致的端口綁定問(wèn)題。遇到這種詭異情況先別急著殺進(jìn)程試試重啟Docker Desktop往往比任何排查都管用。這個(gè)動(dòng)作代價(jià)極低但能解決的問(wèn)題比你想象中多得多。