第六章

容器网络:让容器互相说话

第五层 · 网络模式/端口映射 前端容器怎么找到后端容器

一、三个网络模式:从"隔离"到"共享"

"小陈,容器默认是'谁也看不见谁'的(Namespace 隔离)。要让它们通信,得用 Docker 的网络。"老周说,"Docker 有几种内置网络模式,先记最常用的三个:"

① bridge(桥接,默认):
   每个容器分配一个内网 IP(172.17.x.x)
   容器之间通过虚拟网桥通信
   容器默认"不暴露"端口,要映射才能被外部访问
   ✅ 默认、常用、隔离性好

② host(宿主机):
   容器直接用宿主机的网络栈(没有自己的 IP)
   容器端口 = 宿主机端口
   ✅ 性能好(无 NAT),❌ 隔离差、容易端口冲突

③ none:
   没有网络(完全隔离)
   适合纯计算任务(不需要网络)

  docker network ls    # 查看网络
  docker run --network=bridge ...  # 指定网络

"默认 bridge 是 90% 场景的选择——隔离好、够用。host 只有在'要极高性能'时才考虑。"


二、端口映射:让外面的世界访问容器

"容器在 bridge 网络里有一个内网 IP,但外部(宿主机之外)访问不到。要让外面能访问,必须做端口映射(Port Mapping):"老周演示:

# 把容器的 8000 端口,映射到宿主机的 80 端口
docker run -d -p 80:8000 --name web01 yunjian/web:v1

# 格式:-p 宿主机端口:容器端口
# 访问 http://宿主机IP:80 → 转发到容器内 8000

# 其他映射方式
docker run -d -p 8080:8000 web01        # 指定端口
docker run -d -p 8000 web01             # 随机宿主机端口
docker run -d -p 443:443 -p 80:80 nginx # 多个端口

# 查看映射关系
docker port web01       # 80/tcp -> 0.0.0.0:80

"-p 宿主机端口:容器端口 这个格式必须刻进脑子。 左边是外面访问的,右边是容器里面的。搞反了你就访问不到了。"


三、容器互联:用名字代替 IP

"端口映射解决'外部访问容器',但容器之间互相访问怎么办?"老周说,"容器每次重启 IP 都可能变——总不能用 IP 通信吧?"

方案:自定义网络 + 容器名(DNS 解析)

第一步:创建自定义网络
  docker network create yunjian-net

第二步:把容器放进同一个网络
  docker run -d --network yunjian-net --name db01 mysql
  docker run -d --network yunjian-net --name web01 yunjian/web

第三步:容器之间直接用"名字"访问!
  web01 里访问数据库:db01:3306
  (Docker 内置 DNS 会把名字解析成对应 IP)

关键:只有在"同一个自定义网络"里的容器才能用名字互访
     默认 bridge 网络不支持容器名互访(要 --link,已过时)
# 验证:从 web01 ping db01
docker exec -it web01 bash
ping db01        # 能通!(名字被解析成 db01 的 IP)
mysql -h db01 -P 3306 ...   # 应用里就用 db01 当主机名

"生产实践:所有业务容器放进同一个自定义网络,用容器名互访。 这样容器 IP 怎么变都不用改配置——代码里写死 db01cache01 这些名字就行。"


四、云间书店的网络拓扑

老周带小陈设计云间书店容器化的网络:

云间书店容器网络拓扑:

                    宿主机
          ┌─────────────────────────┐
          │  外部访问 → 宿主机:80     │
          │        │ 端口映射         │
          │        ▼                 │
          │  yunjian-net(自定义网络) │
          │  ┌─────────┐             │
          │  │ web01   │  (前端)      │
          │  │ 80:8000 │             │
          │  └────┬────┘             │
          │       │ web01:8000       │
          │  ┌────┴────┐             │
          │  │ api01   │  (后端 API)  │
          │  └────┬────┘             │
          │       │ api01:5000       │
          │  ┌────┴────┐  ┌───────┐  │
          │  │ db01    │  │ cache01│  │
          │  │ mysql   │  │ redis  │  │
          │  └─────────┘  └───────┘  │
          └─────────────────────────┘

  外部 → 宿主机:80 → web01(只有 web 对外)
  web01 → api01:5000(内部,用名字访问)
  api01 → db01:3306 / cache01:6379(内部)
  数据库不对外暴露端口!(安全)

"记住:只有需要被外部访问的容器才做端口映射,内部服务(数据库、缓存)绝不映射端口,只在自定义网络内部通信。 这是容器网络安全的第一条规则。"


五、网络排障三件套

"容器连不上,怎么排查?三个命令:"老周说:

# 1. 看容器 IP 和网络
docker inspect web01 | grep -i ip

# 2. 进容器测试连通性
docker exec -it web01 bash
curl http://api01:5000/health   # 测 API
ping db01                        # 测连通

# 3. 看网络连接
docker network inspect yunjian-net   # 看谁在这个网络里

# 常见问题速查:
#  - 容器间不通:不在同一个网络?
#  - 名字解析不了:确认都在自定义网络里?
#  - 外部访问不了:端口映射写反了?宿主机防火墙?

"网络问题 80% 出在'不在同一网络'或'端口映射写错'——按这个思路查,大部分都能解决。"


六、章末:老周的第五层总结

第五层:容器网络
├── 三种模式:bridge(默认)/ host / none
├── 端口映射:-p 宿主机端口:容器端口(外部访问容器)
├── 容器互联:自定义网络 + 容器名(用名字代替 IP)
├── 安全规则:只有对外服务映射端口,数据库不暴露
└── 排障:inspect / exec curl / network inspect

"小陈,现在你有了:镜像、容器、数据卷、网络——单容器已经玩明白了。 但是,云间书店的直播带货模块有 5 个组件,你要一条条命令地启动 5 个容器、配 5 次网络、加 5 个数据卷……每次部署都要敲几十条命令?"

小陈:"……手都要敲断了。"

"所以下一章,我们学编排——用 docker-compose 把'整个系统的启动配置'写成一个文件,一条命令,全家桶全部拉起。这是从'管单个容器'到'管一套系统'的飞跃。"

✌ 语言