关于Docker启动容器时报端口占用错误的问题
Docker错误表现
Docker Desktop在启动容器的时候无法正常启动,并且报错 Error: (HTTP code 500) server error - Ports are not available:……。
问题出现的可能原因
该问题在我这边大多是因为关闭Docker Desktop或者关机时候没有先正常关闭容器导致的,再次打开容器就会报错,但是实际上Docker在Windows上的支持确实不太好,有时候即使操作按流程走,也可能会出各种各样的问题,这个问题就是其中之一。
问题分析
如报错信息所说,端口不可用,上面的报错信息没有完全截取,后面其实有详细说明(写记录的时候报错信息已经清掉了),总的来说的大意其实就是端口被占用。那解决方向就很清晰了,想办法找出占用端口的进程,kill即可,根据上面分析的出现可能原因,这个占用的进程大概率是之前没关掉的容器。
问题的解决方案
思路是,找到占用端口的设备,并且Kill之,网上看了下,有好几种方法,虽然前几种在我这里没生效,但先记录下:
1. netstat -nlp 查看占用端口号的服务
打开CMD命令行工具,下发netstat指令,findstr后面跟想查看的端口。
1
netstat –aon | findstr 8892
会出现使用对应端口号的进程:
找到想要关闭的进程ID,Kill之即可,如:
1
taskkill/pid 14872
但是这种方式在我这里没有生效,原因是netstat –aon | findstr 8892
什么也没查到,但是Docker 依然显示占用,无法运行容器。
2. docker 指令查看启动的容器
既然端口占用进程查不到,那就换个思路,看看现在有什么容器在运行,把对应容器关了,然后跟第一步一样,KILL之!
查看所有在运行的Docker:
1 | docker ps |
CMD命令行中出现部署的Docker 容器:
然后接下来有几个选项:
(1) 可以直接Kill之:
1
docker kill 容器ID或容器名 :直接关闭容器
(2) 可以用更优雅的方式Stop:
1
docker stop 容器ID或容器名
(3) 也可以重启docker容器:
不管容器是否启动,直接重启容器
1
docker restart
遗憾的是上面的方法在我这里都没有奏效,restart可以打开容器,但是docker的端口映射应该还是错的原因吗,我没法从外部访问docker应用,当然如果没有外部访问的需求,只需要功能在运行即可,那其实可以将就用一下,至于kill和stop,在我这下发之后则看不出什么变化,容器依然无法在Desktop中启动,端口报错信息还在。
3. 重启Winnat服务
这招对我来说百试百灵,既然端口被不知道什么东西占用那就一不做二不休,重启网络服务,重新分配端口,毕竟重启解决90%问题……
1
net stop winnat
关闭winnat服务之后,再将其重新启动:
1
net start winnat
用这种方式,大部分情况下,都能解决我的端口占用问题。
问题的根本原因
在踩坑后网上找资料时候,看到人写过另一篇关于Windows 10 端口被 Hyper-V 随机保留(占用)的问题帖子,我本人没系统学习过Web开发,所以大佬的分析确实让我有些茅塞顿开的感觉,之前虽然瞎猫碰上死耗子解决了问题,但是实际上还是不知道为什么会导致问题,甚至连到底是谁占用了端口都不知道……。因此记录一下:
错误的解决方法:
运行net stop winnat停止 winnat 服务,然后再运行net start winnat启动 winnat 服务。
这个方法本质上就是重启电脑的简化版……让Hyper-V再随机初始化一些端口保留,如果正好没随机到要用的端口,那一次成功。如果还是随机到了要用的端口,那就只能多来几次。
在那个问题的回答下,我看到有一些网友说「对我有用」,也有一些网友说「对我没用」,原因就是这个方法解决问题的概率完全是随机的……
正确的解决方法:
正确的解决方法很简单,就是重新设置一下「TCP 动态端口范围」,让Hyper-V只在我们设定的范围内保留端口即可。可以以管理员权限运行下面的命令,将「TCP 动态端口范围」重新设定为49152-65535。如果你觉得这个范围太大,还可以改小一点。
1 | netsh int ipv4 set dynamic tcp start=49152 end=16384 |
然后重启电脑即可。
重启电脑后,再运行命令netsh int ipv4 show dynamicport tcp
查看动态端口范围,发现确实已经修改为了49152-65535。现在只有这个范围内的端口可能会被保留了,基本不会影响日常使用。
PS:
还可以设置排除特定的端口,但是我自己没有尝试这种方法:
1 | netsh int ipv4 add excludedportrange protocol=tcp startport=要排除的端口 numberofports=范围 |