6月19日 23:48

Docker 端口映射怎么配置?-p、Compose 和排查怎么做?

Docker 端口映射的作用,是把容器网络命名空间里的端口发布到宿主机上。最常见的写法是 docker run -p 8080:80 nginx:外部访问宿主机的 8080 端口,请求会被转发到容器里的 80 端口。

这里最容易混淆的是:EXPOSE 只是镜像或 Dockerfile 里的声明,告诉别人“这个容器通常会监听哪些端口”;真正让宿主机能访问容器端口的,是 -p/--publish 或 Compose 里的 ports

-p 的完整写法是什么?

-p 的通用格式是:

bash
docker run -p [hostIP:]hostPort:containerPort[/protocol] image

几个常见例子:

bash
# 宿主机 8080 转发到容器 80 docker run -p 8080:80 nginx # 只允许本机访问宿主机 8080 docker run -p 127.0.0.1:8080:80 nginx # 绑定所有网卡的 8080 docker run -p 0.0.0.0:8080:80 nginx # 映射多个端口 docker run -p 8080:80 -p 8443:443 nginx # 映射 UDP 端口 docker run -p 5353:5353/udp some-image

默认协议是 TCP。如果服务用的是 UDP,比如 DNS、游戏服务、部分实时通信服务,必须显式写 /udp,否则你映射的是 TCP,访问当然不通。

0.0.0.0127.0.0.1 和安全性有什么区别?

0.0.0.0:8080:80 表示监听宿主机所有网卡。只要机器的公网 IP、内网 IP 能被访问,别人就可能连到这个端口。

127.0.0.1:8080:80 只绑定本机回环地址,通常只有宿主机自己能访问,适合数据库、管理后台、本地调试服务这类不该直接暴露的端口。

所以生产环境里不要随手写:

bash
docker run -p 0.0.0.0:3306:3306 mysql

这等于把数据库端口暴露在宿主机所有网卡上。更稳妥的方式是只绑定本地地址,再通过反向代理、堡垒机、VPN 或内网访问控制处理入口。

为什么映射了端口还是访问不了?

端口映射只负责把流量送到容器端口,但容器里的应用也要真的监听在正确地址上。

如果应用在容器内只监听 127.0.0.1,外部流量通常到不了它。因为 Docker 转发过来的目标地址是容器的网络地址,不是容器里的 loopback。容器里的 Web 服务应监听:

bash
0.0.0.0:80

而不是:

bash
127.0.0.1:80

很多 Node、Python、Go 开发服务默认只监听 localhost,本地直接跑没问题,放进容器再做端口映射就会踩坑。

EXPOSE-P-p 有什么区别?

EXPOSE 不会自动发布端口,例如:

dockerfile
EXPOSE 80

它只是元数据。你运行容器时仍然需要:

bash
docker run -p 8080:80 image

-P 是大写 P,会把镜像里 EXPOSE 声明的端口随机映射到宿主机端口:

bash
docker run -P nginx

这种方式适合临时调试,不适合稳定对外服务,因为宿主机端口不固定。要知道实际映射到了哪个端口,可以查:

bash
docker port 容器名

Docker Compose 里怎么写?

Compose 里最常见的是 ports

yaml
services: web: image: nginx ports: - "8080:80" - "127.0.0.1:8443:443"

ports 会把容器端口发布到宿主机。

expose 不会发布到宿主机,只是让同一个 Docker 网络里的其他服务知道这个服务使用了哪些端口:

yaml
services: api: image: my-api expose: - "3000"

在同一个 Compose 网络里,服务之间通常不需要端口映射。比如 web 访问 api:3000 即可,Docker 内部 DNS 会把服务名解析到对应容器。只有当宿主机或外部用户需要访问容器时,才需要 ports

常用排查命令有哪些?

先看 Docker 是否真的发布了端口:

bash
docker port 容器名

再看容器是否在运行:

bash
docker ps

检查宿主机端口是否监听:

bash
ss -lntp | grep 8080

如果是 macOS 没有 ss,可以用:

bash
lsof -i :8080

从宿主机访问测试:

bash
curl -v http://127.0.0.1:8080

进容器里看应用是否监听正确地址:

bash
docker exec -it 容器名 sh ss -lntp

如果 Docker 映射没问题、容器服务也在监听,但外部机器访问不了,继续查三件事:

  • 宿主机防火墙是否放行端口,比如 ufwfirewalld、云服务器安全组;
  • 是否绑定成了 127.0.0.1,导致只能本机访问;
  • 协议是否写错,UDP 服务不能只映射 TCP。

端口映射配置时要记住什么?

-p 8080:80 的方向是“宿主机端口:容器端口”,不要写反。EXPOSE 只是声明,-pports 才是真正发布端口。对外服务可以绑定 0.0.0.0,但数据库、后台管理、调试端口更适合绑定 127.0.0.1 或放在 Docker 内部网络里。

大多数端口映射问题最后都落在四处:Docker 没发布、应用没监听 0.0.0.0、宿主机端口被占用、防火墙或安全组没放行。按这个顺序查,通常很快能定位。

标签:Docker