容器网络基础与端口映射
本教程共 25 篇 · 第 18 篇 · 更新于 2026-07-26 · 约 8 分钟阅读
18. 容器网络基础与端口映射
本节目标:搞懂 Docker 的三种网络模式,学会用
-p和-P把容器端口映射到宿主机,让外部能访问容器里的服务。
前面跑容器时你已经用过端口映射了,比如 docker run -p 8080:80 nginx。但为什么要这么写、-p 和 -P 有啥区别、bridge 和 host 网络又是怎么回事,这一章讲清楚。
为什么需要端口映射
容器是隔离的环境,有自己的网络栈。默认情况下,容器里的服务监听的端口,宿主机和外部是访问不到的。
打个比方:容器像一间有独立门牌的房间,里面的服务在房间内某个端口上听电话。但房间外面的人不知道这个端口,也进不来。端口映射就是在大门口设个前台,告诉来访者「你找 8080 号,我帮你转到房间的 80 号」。
不映射端口,容器里的服务只能容器自己玩;映射了,外部才能访问。这就是为什么跑 Web 服务必带 -p。
Docker 的三种网络模式
Docker 安装后会自动建三个网络,用 docker network ls 能看到:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
c2c695315b3a bridge bridge local
a875bec5d6fd host host local
ead0e804a67b none null local
这三个就是最基础的网络模式。
bridge:默认桥接网络
bridge 是默认网络。不指定 --network 时,容器都连到这个网络。
它的工作原理是在宿主机上建一个虚拟网桥(Linux 上叫 docker0),给每个容器分配一个内网 IP(通常是 172.17.0.x),容器通过网桥和宿主机通信,容器之间也能互通。
bridge 网络的特点:
- 容器有独立 IP,和宿主机网络隔离。
- 需要端口映射才能让外部访问。
- 同一个 bridge 网络的容器之间,默认只能用 IP 通信,不能用容器名(默认 bridge 不带 DNS 解析)。
Note默认 bridge 网络没有自动 DNS 解析,这是它和「自定义 bridge 网络」最大的区别。容器之间想用名字互相访问,得用自定义网络,这是下一章的重点。
host:直接用宿主机网络
host 模式下,容器不隔离网络,直接共用宿主机的网络栈。容器里监听 80 端口,就等于宿主机监听 80 端口,不用映射。
docker run -d --network host nginx
这种方式网络性能最好(没有桥接和 NAT 开销),但牺牲了隔离性:容器能看到的网络就是宿主机的网络,端口冲突也得自己处理。
Warninghost 模式下,容器里启动的服务端口如果和宿主机已有服务冲突,会直接启动失败。而且容器没有独立 IP,网络安全隔离变弱。生产环境慎用,主要用于对网络性能要求极高的场景。Docker Desktop(Mac/Windows)上 host 模式行为和 Linux 不同,因为宿主机本身就是个 VM,效果有限。
none:无网络
none 模式给容器一个独立的网络栈,但不配任何网络接口。容器里只有 lo(本地回环),没有外部网络。
docker run -d --network none alpine sleep 1000
这种容器完全断网,适合跑一些不需要联网的计算任务,或者出于安全考虑要隔离的容器。用得少,但要知道有这个选项。
端口映射:-p 和 -P
外部要访问容器,靠端口映射。docker run 时用 -p 或 -P 标志。
-p:指定端口映射
-p(小写)让你精确控制映射,语法是 宿主机端口:容器端口:
docker run -d -p 8080:80 nginx
这条命令把容器的 80 端口映射到宿主机的 8080 端口。访问 http://localhost:8080,流量被转发到容器的 80 端口。
宿主机端口和容器端口可以不一样,这是常用做法—容器内部用约定端口(比如 80),宿主机用你方便记的端口(比如 8080),避免和宿主机已有服务冲突。
一个容器可以映射多个端口:
docker run -d -p 8080:80 -p 8443:443 nginx
指定绑定的 IP
默认映射会绑定到宿主机的所有网络接口(0.0.0.0),意味着局域网里别的机器也能访问。如果想只允许本机访问,指定绑定 127.0.0.1:
docker run -d -p 127.0.0.1:8080:80 nginx
这样只有宿主机自己能访问 8080,外部访问不了。适合跑数据库这种不想暴露到外网的服务。
完整语法是 IP:宿主机端口:容器端口:
docker run -d -p 127.0.0.1:5432:5432 postgres
Warning端口默认绑定到
0.0.0.0,意味着所有网卡都能访问。在云服务器上,如果你把数据库端口直接-p 5432:5432映射出去,又没配安全组,等于把数据库暴露在公网。务必用127.0.0.1:5432:5432限制只本机访问,或者干脆不映射端口,用自定义网络让其他容器内部访问。
指定 UDP 端口
默认映射的是 TCP 端口。要映射 UDP,在端口后加 /udp:
docker run -d -p 5000:5000/udp my-udp-app
TCP 和 UDP 是两套独立的端口空间,可以同时映射:
docker run -d -p 5000:5000 -p 5000:5000/udp my-app
-P:随机映射所有暴露端口
-P(大写)让 Docker 自动把镜像里 EXPOSE 声明的所有端口,随机映射到宿主机的临时端口(通常是 32768-60999 范围)。
docker run -d -P nginx
查看映射到哪个端口了:
$ docker ps
CONTAINER ID IMAGE PORTS NAMES
a527355c9c53 nginx 0.0.0.0:54772->80/tcp romantic_williamson
0.0.0.0:54772->80/tcp 表示宿主机的 54772 映射到容器的 80。访问 http://localhost:54772 即可。
-P 适合不想纠结端口冲突、临时跑起来测试的场景。生产环境一般用 -p 精确指定,端口固定才好配置和监控。
-p 和 -P 的区别
| 标志 | 行为 | 适用场景 |
|---|---|---|
-p 宿主机:容器 | 指定端口映射 | 生产、需要固定端口 |
-P | 随机映射所有 EXPOSE 端口 | 测试、避免端口冲突 |
Note注意区分「EXPOSE」和端口映射。Dockerfile 里的
EXPOSE只是声明,不等于真的对外开。要真的能访问,还得靠docker run -p或-P。-P正是读取EXPOSE声明的端口来做自动映射的。
查看端口映射
除了 docker ps 看 PORTS 列,还有个专门命令 docker port:
docker port romantic_williamson 80
# 输出:0.0.0.0:54772
它会告诉你某个容器的指定端口映射到了宿主机的哪里。查多个端口就多查几次,或者直接 docker port 容器名 列出所有映射。
多个容器用同一个端口怎么办
宿主机的同一个端口只能被一个进程占用,端口映射也一样。如果你起两个容器都映射到宿主机 8080,第二个会报端口占用失败。
解决办法是让宿主机端口不同,容器端口可以相同:
docker run -d -p 8080:80 nginx # 第一个
docker run -d -p 8081:80 nginx # 第二个,用 8081
两个容器内部都是 80,但宿主机分别用 8080 和 8081 访问。开发测试时经常这么干,一台机器跑多个实例。
Tip想一次性起多个相同服务做负载测试,又不想手动指定端口,用
-P让 Docker 随机分配,省心。
网络相关的常用命令
汇总一下网络管理常用命令:
# 列出所有网络
docker network ls
# 查看某个网络的详情(含哪些容器连在上面、子网等)
docker network inspect bridge
# 创建自定义网络(下一章重点)
docker network create my-net
# 把运行中的容器连到某个网络
docker network connect my-net 容器名
# 把容器从网络断开
docker network disconnect my-net 容器名
# 删除网络(没有容器连接时才能删)
docker network rm my-net
这一章先用 ls 和 inspect 看看网络结构,create 和 connect 留到下一章细讲。
小结
把网络基础收一下:
- 容器默认网络隔离,外部访问靠端口映射。
- 三种网络模式:bridge(默认,需映射)、host(共用宿主机网络)、none(断网)。
-p 宿主机:容器精确映射,-P随机映射所有 EXPOSE 端口。- 用
127.0.0.1:宿主机:容器限制只本机访问,别把数据库直接暴露公网。 - 同一宿主机端口不能被多个容器占用,换宿主机端口即可。
EXPOSE只是声明,-p/-P才真的开放端口。
下一章讲容器互联—怎么让多个容器在一个自定义网络里用名字互相通信,这是搭建多服务应用的基础。