05入门:容器网络

1681 字
8 分钟
05入门:容器网络

第 5 关 容器网络#

本关的产出:让第 2 关那三个各跑各的容器能互相叫到名字,并补齐宿主机与容器之间两个方向的访问。

5.1 默认网络:IP 通,名字不通#

第 2 关「三连」收尾时说过:三个容器各跑各的,互相看不见。这一关把这句话拆开。

前面认识过镜像、容器、卷,网络是第四个对象,它管的是谁跟谁能说话:

docker network ls

装好 Docker 自带三张网,由 DRIVER 那一列决定各自怎么搭:

  1. bridge(驱动 bridge):搭一台虚拟交换机,容器接上去就彼此可通。这是默认网络——docker run 不写 --network 就接在它上面。
  2. host(驱动 host):不给容器单独建网络,直接用宿主机的。Linux 上名副其实,macOS 上不是(5.5 讲)。
  3. none(驱动叫 null):什么都不搭,容器没有对外网卡。

第 2 关那三个容器都在 bridge 上,却互相找不到。起两个默认容器做对照(第 2 关的 web 还在就先 docker rm -f web):

docker run -d --name web nginx:latest
docker run -d --name app nginx:latest

web 里跑着 nginx,监听 80。用 IP 连——先取它的地址:

docker exec web hostname -i
docker exec app curl -m 3 http://<上一步打出来的地址>

要观察:欢迎页出来了。它们本来就能通。

换成名字:

docker exec app curl -m 3 http://web

打不开。原因在「名字该问谁」这份名单里:

docker exec app cat /etc/resolv.conf

那行 nameserver 指向宿主机上的 DNS,它不认识 web。

所以默认网络的短板是:不解析容器名。 容器之间只能靠 IP 找人,而 IP 是创建时按顺序分的,docker rm 重起一次就可能换——别写死在配置里。

5.2 自定义网络:名字能互相叫到#

解法是不用默认网络,自己建一张:

docker network create demo-net
docker network ls

demo-net 列出来了。注意它的 DRIVER 也是 bridge——和默认网络一模一样,所以差别不在这一列。

把两个容器删掉重起,接在自己建的网上:

docker rm -f web app
docker run -d --name web --network demo-net nginx:latest
docker run -d --name app --network demo-net nginx:latest

这次用名字连:

docker exec app curl -m 3 http://web

要观察:一个 IP 都没写,欢迎页出来了。用 getent hosts 看 web 这个名字解析到了谁:

docker exec app getent hosts web

打出来就是 web 的那个 172.x 地址。(getent hosts 是查「名字解析成什么地址」的命令,后面都用它确认。)

原因还是 resolv.conf:

docker exec app cat /etc/resolv.conf

nameserver 变成了 127.0.0.11——Docker 内建的 DNS,容器名就登记在它那儿。

这里说的「名字」是容器名(--name 给的),它跟主机名是两回事:主机名不写就是容器 ID,要自己定就用 --hostname <名字>。内建 DNS 把容器名、主机名、容器 ID 一起登记,所以哪个都叫得到。

所以差别不在容器,在有没有内建的 DNS。 顺带兑现第 2 关那句:名字的第二份工作,就是「别的容器能叫到它」。

易踩的坑:确认名字解析,用 getent hosts,别拿 curl 通不通当判据——两者不是一回事。

5.3 接上、摘下、多张网#

刚才删掉重起,是因为要用 --network。其实运行中的容器也能后接上、或摘下:

docker network connect demo-net <容器>
docker network disconnect demo-net <容器>

一个容器可以同时接好几张网。看它挂在哪儿:

docker inspect <容器>

翻到 NetworkSettings 下面的 Networks 段,每张网都列着。这很有用:让数据库只待一张内部网,让 web 同时接内外两张——该露的露,不该露的留在里面。

易踩的坑:

  • 有运行中的容器挂着时删不掉网:docker network rm 报 has active endpoints。
  • 但停着不算在用——stop 之后再删会成功,那个容器下次 start 就起不来了(网没了)。
  • docker network prune 清掉所有没被容器用的网,不问就删;跑之前先 docker network ls 看一眼。

5.4 宿主机与容器之间的两个方向#

容器之间通了,剩下宿主机怎么访问容器、容器怎么访问宿主机。

方向一:宿主机 → 容器,靠 -p。

docker run -d --name pub-demo -p 18080:80 nginx:latest
lsof -nP -iTCP:18080 -sTCP:LISTEN

打出来的是 Docker Desktop 自己的进程。这就是 -p 在 macOS 上的真相:Docker Desktop 在宿主机上占住那个端口,再把流量送进虚拟机里的容器。第 1 关那句「不写 -p,端口就不会出现在 Mac 上」就是这回事。

在 Linux 上,占端口这件事由内核的网络规则做——那归第 15 关。

方向二:容器 → 宿主机,靠 host.docker.internal。

容器里写 localhost 是它自己。要访问宿主机上的服务(比如本机一个 dev server),用固定名字 host.docker.internal:

python3 -m http.server 8765 # 宿主机上起个服务(另开一个终端,用完 Ctrl+C 停)
docker exec app curl -m 3 http://host.docker.internal:8765

拿到目录列表,说明容器访问到了宿主机。

5.5 --network host 在 macOS 上名不副实#

Linux 上,--network host 是「不给容器单独建网络,直接用宿主机的」——容器开个端口,外面直接能访问,很省事。

macOS 上不是:

docker run -d --name host-demo --network host nginx:latest
docker exec host-demo hostname

打出来是 docker-desktop——那台 Linux 虚拟机。第 1 关说过,Docker Desktop 的守护进程跑在虚拟机里,所以这里的「host」指虚拟机,不是 Mac 本身。容器里的 127.0.0.1:80 是通的,Mac 上 curl localhost:80 打不开。

所以 macOS 上 --network host 基本没用,想要的效果还是得靠 -p。(用完 docker rm -f host-demo。)

5.6 把三连接回去#

回到第 2 关那三个容器,加一张网、每个容器加一次 --network(第 2 关的 db、cache 还在就先 docker rm -f db cache):

docker network create app-net
docker run -d --name web --network app-net -p 8080:80 nginx
docker run -d --name db --network app-net \
-e MYSQL_ROOT_PASSWORD=hecloud \
-v ~/docker/mysql-data:/var/lib/mysql \
mysql
docker run -d --name cache --network app-net \
-v ~/docker/redis-data:/data \
redis

web 里的程序现在可以用 db 这样的名字找数据库了。

但名字能叫到,不等于服务已经就绪——mysql 第一次启动要初始化十几秒(第 2 关说过),这期间 db 是通的、3306 上却还没人应答。怎么等它真的就绪,是第 7 关的事。

这一关的产出:三个容器互相叫得到名字,以及宿主机与容器之间两个方向的路。而命令也越写越长——建网、--network、记名字。下一关的 Compose 把它们收进一个文件:它会自己建网,也会把每个服务名注册成互相叫得到的名字。

本关命令速查#

网络对象的增删与连接,见 命令速查表 · 网络。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
05入门:容器网络
https://hecloud.top/posts/tech/docker/05容器网络/
作者
贺小云
发布于
2026-09-21
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
贺小云
热爱技术与折腾的博客 Dancing with uncertainty. 与不确定性共舞
公告
出于成本考虑,贺云已全面转型Serverless架构
分类
标签
碎碎念
站点统计
文章
91
分类
5
标签
44
总字数
103,192
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
Firefly v6.16.5
文章许可
CC BY-NC-SA 4.0