Docker网络模式详解与容器通信
Docker 网络概述
Docker 安装时会自动在 Docker host 上创建三种网络,可以使用 docker network ls
命令查看:
bash
# 查看 Docker 网络列表
[root@hrz3 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
805a6f455d21 bridge bridge local
07c01c3977b9 host host local
668ce77d8fd9 none null local
三种默认网络类型:
- none 网络:无网络连接
- host 网络:共享主机网络栈
- bridge 网络:默认使用的桥接网络
None 网络
顾名思义,none 网络就是没有任何网络连接的封闭环境。
创建并使用 none 网络
bash
# 拉取 busybox 镜像(小型 Linux 环境)
[root@hrz3 ~]# docker pull busybox
# 创建使用 none 网络的容器
[root@hrz3 ~]# docker run --name test1 -it --rm --network=none busybox:latest
# 在容器内查看网络接口
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
特点说明:
- 容器内只有 loopback 接口 (lo)
- 完全网络隔离,无法通过网络访问
- 适用于安全性要求高、不需要联网的应用场景
Host 网络
使用 host 网络的容器共享 Docker host 的网络栈。
创建并使用 host 网络
bash
# 创建使用 host 网络的容器
[root@hrz3 ~]# docker run --name test2 -it --rm --network=host busybox:latest
# 查看容器网络配置(与宿主机相同)
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 00:0c:29:b0:df:de brd ff:ff:ff:ff:ff:ff
inet 192.168.100.30/24 brd 192.168.100.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::f794:4cdf:8dc2:f40/64 scope link noprefixroute
valid_lft forever preferred_lft forever
端口冲突示例
bash
# 检查宿主机 80 端口占用情况
[root@hrz3 ~]# systemctl restart httpd.service
[root@hrz3 ~]# ss -tpln | grep 80
LISTEN 0 128 :::80 :::* users:(("httpd",pid=110359,fd=4)...
# 尝试启动使用 host 网络的 nginx 容器(会因端口冲突失败)
[root@hrz3 ~]# docker run --name nginx -itd --network=host nginx:latest
6c1b69b0b927627a77651a58adcd0faab18a6c218cc5d781573723321991e4ec
# 检查容器状态(启动失败)
[root@hrz3 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
特点说明:
- 容器直接使用宿主机的网络接口
- 端口绑定直接映射到宿主机
- 可能产生端口冲突问题
Bridge 网络
Docker 安装时会创建名为 docker0
的 Linux 网桥,默认容器都连接到该网桥。
查看网桥信息
bash
# 安装网桥管理工具
[root@hrz3 ~]# yum install bridge-utils -y
# 查看网桥信息
[root@hrz3 ~]# brctl show
bridge name bridge id STP enabled interfaces
br-98ee29092a6b 8000.02423e67826f no
docker0 8000.0242c68c95ae no
virbr0 8000.52540021eff1 yes virbr0-nic
创建容器并观察网络变化
终端一:创建容器
bash
# 创建新容器(默认使用 bridge 网络)
[root@hrz3 ~]# docker run --name test3 -it --rm busybox
# 在容器内查看网络配置
/ # ip a
...
47: eth0@if48: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
终端二:观察宿主机网络变化
bash
# 查看宿主机网络接口
[root@hrz3 ~]# ip a
...
48: veth7bc4c9b@if47: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 02:af:73:43:25:da brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::af:73ff:fe43:25da/64 scope link
valid_lft forever preferred_lft forever
# 再次查看网桥,可以看到新接口已连接
[root@hrz3 ~]# brctl show
bridge name bridge id STP enabled interfaces
br-98ee29092a6b 8000.02423e67826f no
docker0 8000.0242c68c95ae no veth7bc4c9b
virbr0 8000.52540021eff1 yes virbr0-nic
查看默认 bridge 网络配置
bash
# 查看默认 bridge 网络的详细配置
[root@hrz3 ~]# docker network inspect bridge
......
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
......
网络配置说明:
- 子网:172.17.0.0/16
- 网关:172.17.0.1
- Docker 自动从该子网为容器分配 IP
自定义 Bridge 网络
创建自定义 bridge 网络
bash
# 创建自定义 bridge 网络
[root@hrz3 ~]# docker network create --driver bridge --subnet 172.16.1.0/24 --gateway 172.16.1.1 testnetwork
abb2b722e12d17885bbd8756b89c3bc0ec6670bf31e51350dde232e825fd3507
# 查看网络列表
[root@hrz3 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
abb2b722e12d testnetwork bridge local
# 查看新创建的网络接口
[root@hrz3 ~]# ip a
......
49: br-abb2b722e12d: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:77:91:d1:70 brd ff:ff:ff:ff:ff:ff
inet 172.16.1.1/24 brd 172.16.1.255 scope global br-abb2b722e12d
valid_lft forever preferred_lft forever
使用自定义网络创建容器
bash
# 创建容器并指定使用自定义网络和静态 IP
[root@hrz3 ~]# docker run --name test -it --rm --network=testnetwork --ip 172.16.1.2 busybox
# 查看容器网络配置
/ # ip a
...
50: eth0@if51: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:10:01:02 brd ff:ff:ff:ff:ff:ff
inet 172.16.1.2/24 brd 172.16.1.255 scope global eth0
valid_lft forever preferred_lft forever
多网络容器通信
不同网络容器通信问题
bash
# 终端一:创建使用默认 bridge 网络的容器 a1
[root@hrz3 ~]# docker run --name a1 -it --rm busybox
/ # ip a
54: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
bash
# 终端二:创建使用自定义网络的容器 a2,并连接多个网络
[root@hrz3 ~]# docker run --name a2 -itd --network=testnetwork --ip 172.16.1.5 busybox
# 为容器 a2 添加默认 bridge 网络连接
[root@hrz3 ~]# docker network connect bridge a2
# 进入容器 a2 查看网络配置
[root@hrz3 ~]# docker exec -it a2 sh
/ # ip a
56: eth0@if57: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:10:01:05 brd ff:ff:ff:ff:ff:ff
inet 172.16.1.5/24 brd 172.16.1.255 scope global eth0
valid_lft forever preferred_lft forever
58: eth1@if59: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth1
valid_lft forever preferred_lft forever
网络连通性测试
bash
# 在容器 a2 中 ping 容器 a1
/ # ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.057 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.061 ms
64 bytes from 172.17.0.3: seq=2 ttl=64 time=0.062 ms
容器访问方式
基于 IP 地址访问
bash
# 创建容器 a1(自定义网络)
[root@hrz3 ~]# docker run --name a1 -it --rm --network=testnetwork busybox
/ # ip a
60: eth0@if61: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:10:01:02 brd ff:ff:ff:ff:ff:ff
inet 172.16.1.2/24 brd 172.16.1.255 scope global eth0
valid_lft forever preferred_lft forever
# 创建容器 a2(同一网络),通过 IP 访问 a1
[root@hrz3 ~]# docker run --name a2 -it --rm --network=testnetwork busybox
/ # ping 172.16.1.2
PING 172.16.1.2 (172.16.1.2): 56 data bytes
64 bytes from 172.16.1.2: seq=0 ttl=64 time=0.170 ms
64 bytes from 172.16.1.2: seq=1 ttl=64 time=0.088 ms
基于容器名访问(DNS 解析)
bash
# 在同一网络中使用容器名进行访问
/ # ping a2
PING a2 (172.16.1.3): 56 data bytes
64 bytes from 172.16.1.3: seq=0 ttl=64 time=0.025 ms
64 bytes from 172.16.1.3: seq=1 ttl=64 time=0.063 ms
DNS 特性说明:
- Docker 1.10+ 版本内置 DNS 服务器
- 自动将容器名解析为 IP 地址
- 仅在使用自定义 bridge 网络时可用
Joined 容器
Joined 容器共享同一个网络栈,可以通过 127.0.0.1 直接通信。
bash
# 创建基础容器 a3
[root@hrz3 ~]# docker run --name a3 -itd --network testnetwork busybox
# 创建 joined 容器 a4,共享 a3 的网络栈
[root@hrz3 ~]# docker run --name a4 -it --rm --network container:a3 busybox
# 在 a4 中访问 a3
/ # ping a3
PING a3 (172.16.1.2): 56 data bytes
64 bytes from 172.16.1.2: seq=0 ttl=64 time=0.028 ms
64 bytes from 172.16.1.2: seq=1 ttl=64 time=0.059 ms
容器与外部网络通信
容器访问外部网络
bash
# 在容器中访问外部网络
[root@hrz3 ~]# docker run --name a4 -it --rm --network container:a3 busybox
/ # ping www.baidu.com
PING www.baidu.com (103.235.46.102): 56 data bytes
64 bytes from 103.235.46.102: seq=0 ttl=127 time=227.597 ms
64 bytes from 103.235.46.102: seq=2 ttl=127 time=201.077 ms
网络地址转换(NAT)过程:
- 容器发送 Ping 包:172.17.0.3 → www.baidu.com
- docker0 收到包,发现目标为外网,交给 NAT 处理
- NAT 将源地址换成主机 IP:192.168.100.30 → www.baidu.com
- Ping 包从主机网卡发送到目标地址
外部访问容器
方法一:使用 host 网络
bash
# 使用 host 网络,容器服务直接绑定到宿主机网络
方法二:端口映射(推荐)
bash
# 启动容器并将容器端口映射到宿主机端口
[root@hrz3 ~]# docker run --name web1 -itd -p 80:80 httpd
d85baf83b1da6381446f88a4db5b17d962b209259f9c481db4921748a35e51a4
# 通过宿主机 IP 访问容器服务
[root@hrz3 ~]# curl 192.168.100.30:80
<html><body><h1>It works!</h1></body></html>
总结
- none 网络:封闭网络,容器无法在网络层被访问,适用于高安全性需求
- host 网络:容器共享宿主机网络栈,网络配置与宿主机完全一致
- 默认 bridge 网络:无法使用容器名进行互访
- 自定义 bridge 网络:支持容器名解析和互访
- 网络连通性:只有在同一网络中的容器才能互相通信
- 外部访问:可通过 host 网络或端口映射实现外部访问容器服务
关键点:
- 使用自定义 bridge 网络可实现容器名解析
- 多网络容器可通过网络连接实现跨网络通信
- 端口映射是最常用的外部访问容器方式