Docker 网络
容器默认是网络孤岛——既访问不到外面,也访问不到彼此。要让容器能联网、能被外部访问、能互相通信,就要理解 Docker 的网络模型。本章把默认网络、端口映射、自定义网络讲透,这是后面 Compose 多服务编排的基础。
三种默认网络
Docker 安装完就有三种预置网络,看一眼:
# Docker 自带三种网络,装完就有
docker network ls
# NETWORK ID NAME DRIVER SCOPE
# a1b2c3d4 bridge bridge local ← 默认,所有容器都连它
# e5f6g7h8 host host local ← 直接用主机网络,无隔离
# i9j0k1l2 none null local ← 完全无网络
# 1. bridge(默认):容器通过虚拟网桥 docker0 通信
docker run -d --name web nginx
# web 自动连到 bridge 网络,获得一个内网 IP(如 172.17.0.2)
# 2. host:容器直接用主机网络栈,无端口映射,性能最好
docker run -d --network host nginx
# 容器 80 端口就是主机 80 端口,-p 失效
# 仅 Linux 有效;macOS/Windows 由于有虚拟机层意义不大
# 3. none:完全无网络(适合纯离线计算任务)
docker run -d --network none alpine sleep 3600- bridge(默认):在主机上虚拟出一个网桥
docker0,所有容器默认连它,获得一个内网 IP。容器要被外部访问必须-p映射端口。 - host:容器直接共享主机网络栈,没有隔离。性能最好,但失去了网络隔离的安全性,且端口会和主机其他服务冲突。仅 Linux 原生支持,Mac/Windows 由于有虚拟机层意义不大。
- none:完全禁用网络。适合纯离线计算任务,或后面手动配置网络的场景。
99% 情况用默认的 bridge 就行。host 模式有特殊性能需求才考虑。
端口映射:让外部访问容器
默认 bridge 网络里的容器,IP 是内网的,外部访问不到。要让外部访问,必须用 -p 把主机端口映射到容器端口:
# 端口映射:让外部访问容器
# -p 主机端口:容器端口
docker run -d -p 8080:80 nginx # 主机 8080 → 容器 80
docker run -d -p 80:80 nginx # 主机 80 → 容器 80
# 多个端口
docker run -d -p 80:80 -p 443:443 nginx
# 指定监听 IP(默认 0.0.0.0 对所有网卡开放)
docker run -d -p 127.0.0.1:8080:80 nginx # 只本机能访问,不对外暴露
# UDP 端口
docker run -d -p 53:53/udp dns
# 大写 -P:自动分配主机端口(从 49153~65535 选一个空闲的)
docker run -d -P nginx
docker port <容器> # 看分到了哪个端口
# 范围映射
docker run -d -p 8000-8010:8000-8010 app # 端口范围记忆方式:-p 主机端口:容器端口,左主机、右容器。一定要写具体端口,生产环境用 -P(大写,随机分配)会让运维找不到服务到底在哪个端口。127.0.0.1:8080:80 这种写法在生产很有用——只让本机能访问的管理后台、数据库,避免暴露到公网。
自定义网络:容器互访的关键
默认 bridge 有个大问题:容器之间只能用 IP 通信,不能用名字。这就导致数据库连接串要写死 IP,容器一重启 IP 变了就连不上。解决方案是自定义 bridge 网络——它会自动启用 DNS,让容器能用名字互访:
# 自定义 bridge 网络:容器互访的关键
# 默认 bridge 网络有个大问题:容器之间只能用 IP 通信,不能用名字
# 解决:创建自定义 bridge 网络,自动启用 DNS,容器能用名字互访
docker network create mynet
# 把容器加进同一网络
docker run -d --network mynet --name api myapp
docker run -d --network mynet --name db postgres:16
# 在 api 容器里,直接用名字 db 就能连到 postgres
docker exec -it api sh
> ping db # 能解析到 db 的 IP
> psql -h db -U app # 数据库连接串直接写 db:5432
# 把运行中容器加入/移出网络
docker network connect mynet web # 把 web 加入 mynet(可同时连多个)
docker network disconnect mynet web # 移出网络
# 看网络里有谁
docker network inspect mynet # 列出所有连进来的容器和 IP这就是为什么后面 Compose 不用手动配网络也能互访——Compose 默认给每个项目创建一个自定义网络,服务名自动注册为 DNS。一个容器可以同时连多个网络(用多次 --network 或 docker network connect),实现精细的网络隔离。
自动 DNS 详解
# 自动 DNS 是自定义网络的核心优势
# 默认 bridge 网络:容器间只能用 IP 通信
docker run -d --name app1 alpine sleep 3600
docker run -d --name app2 alpine sleep 3600
docker exec app1 ping app2 # ping 不通!DNS 不解析 app2
# 自定义 bridge 网络:容器名自动注册为 DNS 名
docker network create mynet
docker run -d --network mynet --name svc1 alpine sleep 3600
docker run -d --network mynet --name svc2 alpine sleep 3600
docker exec svc1 ping svc2 # 通了!自动解析到 svc2 的 IP
# 这就是为什么 Compose 不用手动配网络也能互访:
# Compose 会为每个项目自动创建一个自定义网络,服务名即 DNS 名
# 在 docker-compose.yml 里写 db:5432 就能连数据库,背后就是这个机制理解了这个对比,你就明白了为什么"默认 bridge 不适合多容器应用"。注意 DNS 解析的是容器名或网络别名(alias),不是镜像名。同一个自定义网络内的容器才能互相解析,跨网络不行。
docker network 全套命令
# docker network 全套命令
# 创建网络
docker network create mynet # bridge(默认)
docker network create --driver bridge mynet # 显式指定 bridge
docker network create --subnet 192.168.10.0/24 mynet # 指定子网
docker network create --internal secure-net # 内部网络,不能出网
# 列出所有网络
docker network ls
# 看网络详情(容器列表、子网、网关)
docker network inspect mynet
# 删除网络(必须先断开所有容器)
docker network rm mynet
# 清理所有无用网络
docker network prune
# 让运行中容器加入/退出网络
docker network connect mynet web
docker network disconnect mynet webdocker network inspect 是排错利器——能看到某网络里有哪些容器、各自的 IP 是多少。"容器 A 连不上容器 B"时,先 inspect 看它们是否在同一个网络、IP 段是否一致。
生产网络拓扑实战
真实项目通常做多层网络隔离,把对外的和对内的分开:
# 生产环境网络拓扑(典型)
# 前端代理 → 后端 API → 数据库,三层隔离
docker network create web-tier # 公开,前端代理在这层
docker network create app-tier # 内部,API 和数据库在这层
# 前端代理:同时连 web-tier 和 app-tier
docker run -d --name proxy --network web-tier \
--network app-tier nginx
# API:只连 app-tier
docker run -d --name api --network app-tier myapp
# 数据库:只连 app-tier
docker run -d --name db --network app-tier postgres
# 效果:
# - 外部只能访问 proxy 的 80/443
# - api 和 db 不暴露任何端口给外部
# - proxy 通过 app-tier 网络能访问 api
# - 数据库被严格隔离在内部,无法被外部直连
# 多机部署:overlay 网络(配合 Swarm 或 Kubernetes)
docker network create --driver overlay --attachable mynet这种"代理层连两个网络、内层服务不暴露端口"的拓扑,是生产环境的基本安全模式。数据库绝不用 -p 暴露端口到公网,只在内部网络被 API 访问。多机部署时,跨主机容器通信用 overlay 网络(配合 Docker Swarm 或 Kubernetes),它能像在一个局域网里一样让不同主机的容器互访。
常见问题
- 容器连不上外网:检查主机能联网、iptables 没被改坏、bridge 网络的
icc选项。Linux 上sysctl net.ipv4.ip_forward=1必须开启。 - 端口冲突:"bind: address already in use" 说明主机端口被占。换端口,或用
lsof -i :80找占用进程。 - 容器间 ping 不通:多半是用了默认 bridge 而不是自定义网络。自定义网络才支持名字解析和默认互访。
- DNS 不生效:旧版 Docker(1.10 之前)没有内置 DNS,需升级。容器内
/etc/resolv.conf应该看到nameserver 127.0.0.11(Docker 内置 DNS)。
← 上一篇 Docker 数据卷
下一篇 Docker Compose →