首页 / Docker 入门教程 / 容器互联与自定义网络

Docker 入门教程

容器互联与自定义网络

本教程共 25 篇 · 第 19 篇 · 更新于 2026-07-26 · 约 9 分钟阅读

DockerDocker 入门教程容器互联自定义网络DNS 解析多容器docker network

19. 容器互联与自定义网络

本节目标:学会用自定义网络让容器用名字互相通信,理解多容器应用怎么连起来,为后面学 Compose 打好基础。

上一章我们讲了端口映射,解决的是「外部怎么访问容器」。这一章解决另一个问题:「容器之间怎么互相访问」。

实际应用经常是多个容器协作:Web 容器要连数据库容器,API 容器要连缓存容器。这些容器之间怎么通信、怎么用名字找到对方,就是这一章的主题。

默认 bridge 网络的局限

先看为什么不能直接用默认 bridge 网络。

默认 bridge 网络里,容器之间是能通信的,但有个硬伤:只能用 IP,不能用容器名。

容器每次启动,分到的 IP 是动态的。今天 db 容器是 172.17.0.2,明天重启可能变成 172.17.0.3。你的 Web 应用里写死了连 172.17.0.2,下次重启就连不上了。

你可能会想:那我 ping 容器名行不行?试一下:

docker run -itd --name test1 ubuntu
docker run -itd --name test2 ubuntu
docker exec -it test1 ping test2
# ping: test2: Name or service not known

默认 bridge 不解析容器名,ping 不通。早期 Docker 有个 --link 参数能搞容器互联,但它有不少技术缺陷,官方已经不推荐了。

正确做法是:用自定义网络。

自定义 bridge 网络

自定义 bridge 网络解决了默认 bridge 的两个痛点:一是带自动 DNS 解析,容器能用名字互访;二是网络隔离,不同网络的容器默认不通,更安全。

创建自定义网络

docker network create my-net

默认创建的是 bridge 类型。看一下:

$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
c2c695315b3a   bridge    bridge    local
a875bec5d6fd   host      host      local
ead0e804a67b   none      null      local
3f8a9b2c1d4e   my-net    bridge    local

my-net 出现在列表里,类型也是 bridge,但它和默认那个 bridge 行为不同。

把容器加入自定义网络

--network 参数指定容器加入哪个网络:

docker run -itd --name test1 --network my-net ubuntu
docker run -itd --name test2 --network my-net ubuntu

现在从 test1 里 ping test2:

docker exec -it test1 ping test2

这次能 ping 通了。Docker 内置的 DNS 服务把 test2 这个名字解析成了 test2 容器的 IP。这就是「自动服务发现」(automatic service discovery)。

Note

自定义网络里的 DNS 解析是 Docker 内嵌的,不需要你额外装 DNS 服务器。容器启动时 Docker 把它的名字注册进去,其他同网络容器就能用这个名字找到它。容器重启 IP 变了也没关系,DNS 记录会跟着更新,名字永远指向最新的 IP。

默认 bridge vs 自定义 bridge

把两者的差异列清楚,这是面试和实战都常考的点:

对比项默认 bridge自定义 bridge
DNS 解析不支持,只能用 IP支持,用容器名互访
网络隔离所有容器都在一个网络不同网络默认隔离
适用场景单容器、临时测试多容器应用、生产
--link 兼容支持(已不推荐)不需要,原生支持 DNS
Tip

简单记:默认 bridge 是「公共大杂院」,所有容器挤一起,但不认识彼此名字;自定义 bridge 是「专属小区」,里面的容器互相认识,外人进不来。多容器应用一律用自定义网络。

用网络别名

除了用容器名,还能给容器起「网络别名」,别的容器可以用别名访问它。

docker run -d --name redis --network my-net --network-alias cache redis

这条命令起了个 Redis 容器,在网络里它既叫 redis(容器名),又叫 cache(网络别名)。同网络的其他容器 ping redisping cache 都能找到它。

别名在多实例场景特别有用。比如起两个 Web 容器,都叫同一个别名 web

docker run -d --name web1 --network my-net --network-alias web my-web
docker run -d --name web2 --network my-net --network-alias web my-web

其他容器请求 web 这个名字时,DNS 会轮询返回 web1 和 web2 的 IP,实现简单的负载均衡。这在配合 Nginx 反向代理时很方便。

一个完整的多容器示例

把前面学的串起来,跑一个 Web + Redis 的多容器应用。

第一步:建网络

docker network create sample-app

第二步:起 Redis 容器

docker run -d --name redis --network sample-app --network-alias redis redis

不映射端口—Redis 不需要被外部访问,只在网络内部用。这比 -p 6379:6379 暴露出去更安全。

第三步:起 Web 容器

假设你的 Web 应用配置里连 Redis 用的是主机名 redis

docker run -d --name web1 -h web1 --network sample-app --network-alias web1 my-web

-h web1 设置容器的主机名,--network-alias web1 给它一个网络别名。Web 容器里用 redis 这个名字就能连到 Redis 容器,不用关心 Redis 的 IP 是多少。

第四步:起 Nginx 反向代理

docker run -d --name nginx --network sample-app -p 80:80 nginx

Nginx 容器也在同一个网络里,它的配置里 upstream 指向 web1,就能反向代理到 Web 容器。只有 Nginx 映射了 80 端口对外,Web 和 Redis 都藏在内网。

验证

docker ps

能看到四个容器都在跑。浏览器访问 http://localhost,请求经 Nginx 转发到 web1,web1 读写 Redis。整个链路通。

Warning

这个例子里 Redis 没映射端口,外部访问不到,这是对的。很多新手习惯性地把数据库也 -p 出去,结果暴露在公网。正确做法是数据库只在自定义网络内通信,只把需要对外服务的容器(如 Nginx、Web)映射端口。

网络隔离

不同自定义网络之间默认是隔离的。容器 A 在 net1,容器 B 在 net2,它们互相 ping 不通。

这种隔离很有用:比如把前端、后端、数据库分成不同网络,数据库只对后端开放,前端访问不到数据库,安全性更高。

              ┌── frontend-net ── frontend 容器
backend 容器 ─┤
              └── backend-net  ── db 容器

backend 容器同时连 frontend-net 和 backend-net,db 容器只连 backend-net。这样 frontend 能访问 backend,但访问不到 db。

一个容器可以同时加入多个网络,用多次 --networkdocker network connect

docker network connect frontend-net backend
docker network connect backend-net backend

容器之间传文件不需要端口

一个常见误区:以为容器之间传文件也得开端口。其实只要在同一个自定义网络里,容器之间用容器名就能直接通信,不需要端口映射。

端口映射解决的是「宿主机外部 -> 容器」的访问,不是「容器 -> 容器」。容器之间走的是 Docker 内部网络,直接用 IP 或容器名 + 容器内端口就行。

比如 Web 容器连 Redis,写 redis:6379 就行,不用在 Redis 上 -p 6379。6379 是 Redis 在容器里监听的端口,同网络的 Web 容器能直接访问,外部才需要映射。

管理自定义网络

常用命令汇总:

# 创建网络
docker network create my-net

# 创建时指定子网和网关(一般不需要,Docker 自动分配)
docker network create --subnet=172.20.0.0/16 my-net

# 查看网络详情,能看到连了哪些容器
docker network inspect my-net

# 把运行中的容器加入网络
docker network connect my-net 容器名

# 把容器从网络移除
docker network disconnect my-net 容器名

# 删除网络(没有容器连接时)
docker network rm my-net

# 清理所有未使用的网络
docker network prune

docker network inspect 很有用,能看到这个网络里有哪些容器、各自的 IP 和别名。排查容器互联问题,第一步就是 inspect 看看容器到底在不在同一个网络里。

DNS 配置补充

自定义网络自带 DNS,但有时候你想让容器用特定的 DNS 服务器(比如内网的 DNS)。有两种方式。

全局配置:在 /etc/docker/daemon.json 里加:

{
  "dns": ["114.114.114.114", "8.8.8.8"]
}

改完重启 Docker,所有新启动的容器都用这个 DNS。

单个容器配置:用 --dns 参数:

docker run -d --dns 114.114.114.114 --dns-search mycompany.com nginx

--dns 指定 DNS 服务器,--dns-search 指定搜索域。比如设了搜索域 mycompany.com,ping db 时会同时查 dbdb.mycompany.com

Note

默认情况下,容器的 DNS 配置继承自宿主机的 /etc/resolv.conf。只有需要特殊解析内网域名时,才用上面这两种方式覆盖。大部分场景自定义网络自带的容器名 DNS 就够用了。

多容器管理的局限

到这里你已经能手动管理多容器应用了:建网络、起容器、连网络。但容器一多,命令就又长又乱—四个容器要敲四条 docker run,每条带一堆参数,顺序还不能错。

这就是 docker run 管理多容器的局限:

  • 命令冗长,容易写错。
  • 启动顺序要自己控制。
  • 环境变量、卷、网络配置散落在多条命令里。
  • 没法一键启停整套应用。
Tip

容器数量超过三四个,就别硬扛 docker run 了。Docker Compose 就是为这个生的—用一个 YAML 文件描述所有容器、网络、卷,一条 docker compose up 全部拉起。这是下一章(章 20)的主题,也是本教程编排篇的开篇。

小结

容器互联的要点:

  1. 默认 bridge 不支持容器名解析,多容器别用它。
  2. 自定义 bridge 网络带 DNS,容器能用名字互访,IP 变了也不怕。
  3. --network-alias 给容器起别名,多实例同别名能做简单负载均衡。
  4. 不同网络默认隔离,容器可加入多个网络实现精细的访问控制。
  5. 容器之间通信不需要端口映射,端口映射只用于外部访问。
  6. 容器多了用 docker run 难管,上 Docker Compose。

到这里,镜像构建篇和数据网络篇就讲完了。你已经能构建镜像、推送到仓库、持久化数据、配置网络。下一章开始编排篇,学 Docker Compose 把这些能力整合起来。