关于dockerdesktop(win)出现幽灵端口占用的问题
解决 Docker Desktop (Windows) 出现幽灵端口占用的问题
在使用 Docker Desktop 的过程中,有时会遇到一些奇怪的端口占用问题。明明没有应用程序在使用某个端口,但 Docker 容器启动时却报错说端口被占用。
问题现象
在 Docker Desktop 启动容器时,有概率出现如下报错:
Failed to run image. (HTTP code 500) server error - Ports are not available: exposing port TCP 0.0.0.0:4222 -> 127.0.0.1:0: listen tcp 0.0.0.0:4222: bind: An attempt was made to access a socket in a way forbidden by its access permissions.
我这里是因为想要启动 NATS Docker 容器时出现的这个错误。有趣的是,在此之前我已经成功启动过一次,但时隔大概 1 天后再次启动想要进行程序调试时就出现了这个报错。
排查过程
首先,我通过端口进行线程搜索,试图找到占用 4222 端口的应用程序,但没有找到对应的应用。
然后我开始怀疑是否是因为 Docker Desktop 启动时调用的 WSL 内部环境导致的问题。也许是 WSL 随开机启动,然后 WSL 内部有什么进程占用了这个端口?虽然感觉不太可能,但还是值得一试。
于是在 WSL 内执行 sudo netstat -tulnp | grep 4222
命令,结果仍然没有发现任何占用该端口的进程。
解决方案
经过搜索,我找到了一个简单有效的解决方案(原作者:https://www.jianshu.com/p/1c75c4662d2a)。
处理方法很简单,只需以管理员身份在 PowerShell 中运行以下命令:
net stop winnat
net start winnat
在新版 Windows 中,也可以直接在前面加上 sudo
来获取管理员权限:
sudo net stop winnat
sudo net start winnat
原理解释
那么,这两个命令到底做了什么,为什么能解决问题呢?
WinNAT
(Windows Network Address Translation)是 Windows 的一个服务,负责管理网络地址转换功能。Docker Desktop 在 Windows 上运行时,会使用 WinNAT 服务来处理容器网络与主机网络之间的通信和端口映射。
当我们执行 net stop winnat
时,实际上是停止了 Windows 的 NAT 服务,这会释放所有当前被 NAT 服务占用的网络资源,包括那些可能处于"幽灵状态"的端口绑定。
而 net start winnat
则是重新启动 NAT 服务,让它以一个干净的状态开始工作。
这个问题通常发生在 Docker 容器非正常关闭,或者系统休眠/重启后 WinNAT 服务状态没有正确恢复的情况下。重启 WinNAT 服务可以清除这些残留的端口绑定,让端口重新可用。