前言:docker 的镜像是令人称道的地方,但网络功能还是相对薄弱的部分。 docker 安装后会自动创建 3 种网络:bridge、host、none

[root@docker harbor]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
2a93d6859680   bridge    bridge    local
4d81ddd9ed10   host      host      local
8c8c95f16b68   none      null      local

Docker 提供了 5 种主要网络模式,每种模式适用于不同的场景:

网络模式隔离级别端口映射与宿主机关系适用场景
Bridge高支持通过网桥通信默认模式单机容器通信
Host无不需要共享宿主机网络高性能需求场景
None最高不支持完全隔离安全隔离场景
Container中继承共享另一容器网络特殊协作场景
Overlay高支持跨主机通信集群网络多主机 / 集群环境

1.1 Docker 原生 bridge 网络

原理: Docker 服务默认创建 docker0 网桥 每个容器启动时会创建一对虚拟网卡(veth pair) 一端在容器内,另一端连接到 docker0 网桥 容器通过 NAT 访问外部网络

特点 ✅ 容器间可通过 IP 直接通信 ✅ 支持端口映射(-p 参数) ✅ 网络隔离性好 ❌ 默认不支持容器名解析(需自定义网络)

docker 安装时会创建一个名为 docker0 的 Linux bridge,新建的容器会自动桥接到这个接口

[root@docker mnt]# ip link show type bridge
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
    link/ether 02:42:5f:e2:34:6c brd ff:ff:ff:ff:ff:ff

bridge 模式下容器没有一个公有 ip,只有宿主机可以直接访问,外部主机是不可见的。 容器通过宿主机的 NAT 规则后可以访问外网。

# 运行容器
[root@docker-node2 ~]# docker run -d --name web -p 80:80 nginx:1.26

[root@docker-node2 ~]# docker ps -a
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS         PORTS                                     NAMES
61fe1dfcd025   nginx:1.26   "/docker-entrypoint.…"   2 seconds ago   Up 2 seconds   0.0.0.0:80->80/tcp, [::]:80->80/tcp       web

[root@docker-node2 ~]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::6484:9eff:fe23:5fa3  prefixlen 64  scopeid 0x20<link>
        ether 66:84:9e:23:5f:a3  txqueuelen 0  (Ethernet)
        RX packets 44  bytes 13164 (12.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 48  bytes 11845 (11.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.25.254.20  netmask 255.255.255.0  broadcast 172.25.254.255
        inet6 fe80::2360:d7ac:9af2:bb39  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:b7:c0:af  txqueuelen 1000  (Ethernet)
        RX packets 2505  bytes 232739 (227.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1953  bytes 232250 (226.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

veth3e65a2f: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500       # 这个是容器使用的网卡
        inet6 fe80::e490:e0ff:fe9e:13c2  prefixlen 64  scopeid 0x20<link>
        ether e6:90:e0:9e:13:c2  txqueuelen 0  (Ethernet)
        RX packets 3  bytes 126 (126.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 9  bytes 806 (806.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@docker-node2 ~]# brctl show       # 需要下载bridge-utils
bridge name bridge id       STP enabled interfaces
docker0     8000.66849e235fa3   no      veth3e65a2f

1.2 Docker 原生网络 host

原理 容器直接使用宿主机的网络命名空间 不创建虚拟网卡,无网络隔离

特点 ✅ 网络性能最优(无 NAT 开销) ✅ 无需端口映射 ❌ 无网络隔离,端口可能冲突 ❌ Linux 专属(Mac/Windows 不支持)

host 网络模式需要在容器创建时指定 --network=host host 模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性。

注意:共用宿主机网络栈,端口属于宿主机,端口不能重复占用,如果宿主机 80 端口已经被占用,再启动 nginx 容器就会启动失败。

# 运行busybox
[root@docker-node2 ~]# docker run -it --name test --network host busybox:latest

/ # ifconfig
docker0   Link encap:Ethernet  HWaddr 66:84:9E:23:5F:A3
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          inet6 addr: fe80::6484:9eff:fe23:5fa3/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:61 errors:0 dropped:0 overruns:0 frame:0
          TX packets:66 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:15041 (14.6 KiB)  TX bytes:13579 (13.2 KiB)

eth0      Link encap:Ethernet  HWaddr 00:0C:29:B7:C0:AF
          inet addr:172.25.254.20  Bcast:172.25.254.255  Mask:255.255.255.0
          inet6 addr: fe80::2360:d7ac:9af2:bb39/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2999 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2284 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:312084 (304.7 KiB)  TX bytes:270654 (264.3 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

veth3e65a2f Link encap:Ethernet  HWaddr E6:90:E0:9E:13:C2
          inet6 addr: fe80::e490:e0ff:fe9e:13c2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:20 errors:0 dropped:0 overruns:0 frame:0
          TX packets:33 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:2241 (2.1 KiB)  TX bytes:2960 (2.8 KiB)

1.3 Docker 原生网络 none

原理: 容器拥有独立的 Network Namespace 但不配置任何网络接口(只有 lo 回环)

特点 ✅ 最高安全隔离 ✅ 可手动配置网络 ❌ 无法访问外部网络(需手动配置)

none 模式是指禁用网络功能,只有 lo 接口,在容器创建时使用 --network=none指定。

[root@docker ~]# docker run -it --name test --rm --network none  busybox
/ # ifconfig
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

1.4 Container 模式(joined 网络)

原理 新容器共享已存在容器的网络命名空间 两个容器使用相同的网络接口和 IP

特点 ✅ 容器间通信通过localhost,通信高效 ✅ 适合 Sidecar 模式(如服务网格、日志采集) ❌ 依赖主容器生命周期,主容器销毁,网络同步消失

示例

# 先启动主容器
docker run -d --name main nginx

# 新容器共享主容器网络
docker run -d --name helper --network container:main busybox

1.5 Docker 的自定义网络

自定义网络模式,docker 提供了三种自定义网络驱动:

  • bridge
  • overlay
  • macvlan

bridge 驱动类似默认的 bridge 网络模式,但增加了一些新的功能; overlay 和 macvlan 是用于创建跨主机网络。

建议使用自定义的网络来控制哪些容器可以相互通信,还可以自动 DNS 解析容器名称到 IP 地址。

1.5.1 自定义桥接网络

1.在建立自定义网络时,默认使用桥接模式
[root@docker ~]# docker network create my_net1
f2aae5ce8ce43e8d1ca80c2324d38483c2512d9fb17b6ba60d05561d6093f4c4

[root@docker ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
2a93d6859680   bridge    bridge    local
4d81ddd9ed10   host      host      local
f2aae5ce8ce4   my_net1   bridge    local
8c8c95f16b68   none      null      local
2.桥接默认子网单调递增,每自定义一个桥接网络,宿主机上就多出一个 br 开头的网卡
[root@docker ~]# ifconfig
br-f2aae5ce8ce4: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255
        ether 02:42:70:57:f2:82  txqueuelen 0  (Ethernet)
        RX packets 21264  bytes 1497364 (1.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 27359  bytes 215202367 (205.2 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:5fff:fee2:346c  prefixlen 64  scopeid 0x20<link>
        ether 02:42:5f:e2:34:6c  txqueuelen 0  (Ethernet)
        RX packets 21264  bytes 1497364 (1.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 27359  bytes 215202367 (205.2 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
3.桥接也支持自定义子网和网关
[root@docker ~]# docker network create my_net2 --subnet 192.168.0.0/24 --gateway 192.168.0.100
7e77cd2e44c64ff3121a1f1e0395849453f8d524d24b915672da265615e0e4f9

[root@docker ~]# docker network  inspect my_net2
[
    {
        "Name": "my_net2",
        "Id": "7e77cd2e44c64ff3121a1f1e0395849453f8d524d24b915672da265615e0e4f9",
        "Created": "2024-08-17T17:05:19.167808342+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/24",
                    "Gateway": "192.168.0.100"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

1.5.2 为什么要自定义桥接网络

1.多容器之间可以通过 ip 互访,但是 IP 存在弊端:
[root@docker ~]# docker run  -d --name web1 nginx
d5da7eaa913fa6cdd2aa9a50561042084eca078c114424cb118c57eeac473424
[root@docker ~]# docker run  -d --name web2 nginx
0457a156b02256915d4b42f6cc52ea71b18cf9074ce550c886f206fef60dfae5

[root@docker ~]# docker inspect  web1
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:11:00:03",
                    "DriverOpts": null,
                    "NetworkID": "2a93d6859680b45eae97e5f6232c3b8e070b1ec3d01852b147d2e1385034bce5",
                    "EndpointID": "4d54b12aeb2d857a6e025ee220741cbb3ef1022848d58057b2aab544bd3a4685",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",      #注意ip信息
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DNSNames": null

#关闭容器后重启容器,启动顺序调换
[root@docker ~]# docker stop web1 web2
web1
web2
[root@docker ~]# docker start web2
web2
[root@docker ~]# docker start web1
web1
2.docker 引擎分配 IP 是按照容器启动顺序分配,谁先启动谁优先获取 IP,IP 是动态变更的。 多容器互访使用 IP 不稳定,推荐使用容器名称访问。 默认 bridge 网络不支持 DNS 解析容器名,自定义 bridge 网络自带内置 DNS。
[root@docker ~]# docker run -d --network my_net1 --name web nginx
d9ed01850f7aae35eb1ca3e2c73ff2f83d13c255d4f68416a39949ebb8ec699f
[root@docker ~]# docker run  -it --network my_net1  --name  test busybox
/ # ping web
PING web (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.197 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.096 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.087 ms

注意:不同的自定义网络之间默认不能通讯 RHEL7 使用 iptables 做网络隔离,RHEL9 使用 nftables,可以使用 nft list ruleset 查看隔离策略

1.5.3 如何让不同的自定义网络互通

1.使用 docker network connect 将容器额外接入其他网络,一个容器可以挂载多个网络。
[root@docker ~]# docker run -d  --name web1 --network my_net1 nginx
[root@docker ~]# docker run  -it --name test --network my_net2 busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:C0:A8:00:01
          inet addr:192.168.0.1  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:36 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 frame:0
          collisions:0 txqueuelen:0
          RX bytes:5244 (5.1 KiB)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2): 56 data bytes

# 将test容器接入my_net1网络
[root@docker ~]# docker network connect my_net1 test
2.再次进入容器查看网卡,会多出 eth1 网卡,实现跨网络互通:
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:C0:A8:00:01
          inet addr:192.168.0.1  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:45 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:5879 (5.7 KiB)  TX bytes:602 (602.0 B)

eth1      Link encap:Ethernet  HWaddr 02:42:AC:12:00:03
          inet addr:172.18.0.3  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:15 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:2016 (1.9 KiB)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:4 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:212 (212.0 B)  TX bytes:212 (212.0 B)

1.5.4 joined 容器网络实操演示

joined 容器一种较为特别的网络模式,在容器创建时使用--network=container:容器名指定。 处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用localhost高效快速通信。

[root@docker ~]# docker run  -it --rm  --network container:web1 busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02
          inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:28 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:3046 (2.9 KiB)  TX bytes:280 (280.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)


[root@docker ~]# docker run  -it --rm  --network container:web1 centos:7
[root@efae66874371 /]# curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

1.5.5 joined 网络实战案例:phpmyadmin 连接 mysql

利用 joined 共享网络,实现 phpmyadmin 访问本机的 mysql 服务,不需要暴露数据库端口到外部:

# 先启动phpmyadmin
[root@docker ~]# docker run -d --name mysqladmin --network my_net1 \
-e PMA_ARBITRARY=1 \                # 在web页面中可以手动输入数据库地址和端口
-p 80:80 phpmyadmin:latest

# 运行mysql数据库,共享mysqladmin容器的网络命名空间
[root@docker ~]# docker run  -d --name mysql \
-e MYSQL_ROOT_PASSWORD='lee' \                  #设定数据库密码
--network container:mysqladmin  \               #把数据库容器添加到phpmyadmin容器网络栈
mysql:5.7

phpmyadmin 和 mysql 共用同一个网络栈,在 phpmyadmin 网页填写数据库地址:localhost:3306 即可连接,mysql 不需要对外映射 3306 端口,安全性更高。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐