讲解

容器有自己的网络命名空间,容器里监听的端口默认外界不可达。docker run -p 宿主机端口:容器端口 在宿主机上建立转发规则:访问宿主机的 18080,流量被送进容器的 80。映射是「宿主:容器」的顺序,写反了是最常见的新手错误——-p 80:18080 表示宿主 80 转发到容器 18080,和你想的正相反。

几个进阶形态:-p 127.0.0.1:18080:80 只绑定回环地址(本机调试的服务不该暴露给局域网);-p 18080:80/udp 映射 UDP;-P(大写)把镜像 EXPOSE 声明的所有端口映射到宿主随机端口,配合 docker port 容器名 查看实际端口。一个容器可以多次 -p 映射多个端口;不同容器映射同一个容器端口互不冲突(它们各有网络命名空间),但宿主机端口全局唯一,谁先占谁得。

注意 EXPOSE 指令只是文档性声明,不做任何实际映射——真正的映射永远来自 -p/-P。排查「服务通了没有」的标准动作链:docker ps 看 PORTS 列确认映射 → docker exec 进去确认进程在监听 → curl 宿主机端口验证 → 不通再查防火墙(云主机的安全组是另一层,Docker 管不到)。

示例

起 nginx,把容器 80 映射到宿主 18081:

docker run -d --name ohmydocs-verify-ports -p 18081:80 nginx:1.27-alpine

确认 PORTS 列的映射关系,再从宿主机访问:

docker ps --filter name=ohmydocs-verify-ports --format '{{.Names}} -> {{.Ports}}'
curl -sf --retry 5 --retry-connrefused --retry-delay 1 http://localhost:18081 | head -2

只绑定回环地址的写法(服务只对本机可见):

docker run -d --name ohmydocs-verify-loop -p 127.0.0.1:18082:80 nginx:1.27-alpine
docker port ohmydocs-verify-loop

同一容器端口可以被多个容器使用,宿主机端口则必须各用各的——这里两个 nginx 的容器内端口都是 80:

curl -sf http://localhost:18082 >/dev/null && echo "18082 也通了"
docker rm -f ohmydocs-verify-ports ohmydocs-verify-loop

常见坑

  • 宿主/容器端口写反:记忆口诀「外面:里面」;docker ps 的 PORTS 列 0.0.0.0:18080->80/tcp 左边永远是宿主。
  • 应用监听 127.0.0.1:容器内应用只绑回环地址时,端口映射再正确也访问不到——容器里的服务必须监听 0.0.0.0。
  • -p 冲突:宿主端口被占会直接报错;脚本化部署前先查端口或让编排工具分配。
  • 云服务器上还是不通:宿主机防火墙/云安全组没放行该端口,与 Docker 无关;macOS 的 Docker Desktop 还有自己的转发层。

小结

-p 宿主:容器,顺序「外面:里面」;127.0.0.1 前缀限制只本机访问;EXPOSE 只是文档;排查链:PORTS 列 → 进程监听 → curl → 防火墙。下一章解决数据问题:卷与持久化。