Docker容器启动后为什么访问不了本地端口?
我用 Docker 跑了一个前端开发服务器,Dockerfile 里写了 EXPOSE 3000,启动容器时也加了 -p 3000:3000,但浏览器访问 localhost:3000 就是打不开,显示连接被拒绝。
我试过在容器里 curl localhost:3000 是通的,说明服务确实跑起来了,但宿主机就是连不上。是不是端口映射哪里写错了?
我的启动命令是:docker run -p 3000:3000 my-frontend-app,Dockerfile 相关部分如下:
FROM node:18
WORKDIR /app
COPY . .
RUN npm install
EXPOSE 3000
CMD ["npm", "start"]
问题的关键在于:容器内的服务监听了 localhost(127.0.0.1),这意味着它只接受来自容器内部的连接。Docker 的端口映射是把宿主机的一个端口流量转发到容器的 IP 地址上,而不是转发到容器的 localhost。容器内部服务绑 127.0.0.1 是收不到这个转发的。
你可以在容器里 curl localhost:3000 没问题,是因为从容器内部访问 localhost 确实能到达服务。但宿主机通过 -p 3000:3000 映射进来的时候,数据包到达的是容器的网卡(通常是 eth0 的 IP),而不是 127.0.0.1。
解决方法:让服务监听 0.0.0.0 而不是 127.0.0.1。
对于 Node.js 的开发服务器,通常有个 --host 或者 HOST 环境变量的参数。以 Create React App 为例,启动命令改成这样:
如果是用 express 或者其他框架自己写的服务,大概是这样:
改完重新 build 和运行:
然后再试试从宿主机访问 localhost:3000,应该就 OK 了。
顺带提一下,EXPOSE 3000 这个指令其实只是个文档作用,告诉别人这个容器会暴露 3000 端口,它不会真的限制端口映射,不加也行。加上 -p 参数才是真正做端口映射的动作,你这个写法没问题。
你容器里能curl通localhost:3000,但宿主机访问不了,说明服务只监听了容器内部的localhost。大多数前端开发服务器默认只监听127.0.0.1,需要改成0.0.0.0才能让外部访问。
试试修改你的npm启动命令,比如react项目的话:
或者如果是vite的话:
改完重建容器应该就能在宿主机访问了。顺便说下,EXPOSE其实可以去掉,它只是文档作用,实际端口映射全靠-p参数。