docker网络

docker网络

一、docker网络类型

Docker安装时会自动的在Docker host上创建三种网络,我们可以使用docker netwokr ls查看。这三种网络分别是none网络、host网络、bridge网络,bridge网络是我们在创建容器时默认使用的网络。

复制代码
 docker network ls
 NETWORK ID     NAME      DRIVER    SCOPE
 aa894a535163   bridge    bridge    local
 e632387f1e35   host      host      local
 53dd0861786d   none      null      local

1.1 None网络

none网络就是什么都没有的网络。在这个网络下的容器除了lo,没有其他任何网卡。容器创建时,可以通过--network=none指定使用none网络,通过下面这个示例可以看出,创建容器时指定容器网络类型为none时,容器内只有一个lo网络。

复制代码
 [root@ldh ~]# docker pull busybox
 ​
 [root@ldh ~]# docker run --name a1 -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

none网络是个封闭的网络,使用了这种网络类型的容器无法在网络层被访问。封闭意味着隔离,一些对安全性要求高并且不需要联网的应用可以使用none网络。比如某个容器的唯一用途是生成随机密码,就可以放到none网络中避免密码被窃取。

1.2 Host网络

使用host网络的容器共享Docker host的网络栈,容器的网络配置与Docker host完全一样。可以通过--network=host指定使用host网络。可以通过以下示例看到,创建容器指定容器网络为host时,容器直接共享了Docker host的网络,能够获取到Docker host的网络信息。

复制代码
 [root@ldh ~]# docker run -it --name a1 --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:87:11:e4 brd ff:ff:ff:ff:ff:ff
     inet 192.168.100.5/24 brd 192.168.100.255 scope global noprefixroute ens33
        valid_lft forever preferred_lft forever
     inet6 fe80::72b1:63fc:272:c80c/64 scope link noprefixroute 
        valid_lft forever preferred_lft forever
 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue 
     link/ether 02:42:27:ce:5b:49 brd ff:ff:ff:ff:ff:ff
     inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
        valid_lft forever preferred_lft forever

直接使用Docker host的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择host网络。当然不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host上已经使用的端口就不能再使用了。

复制代码
 # 以httpd为例,开启apache服务,占用80端口
 yum -y install httpd
 systemctl restart httpd
 ss -anlt | grep 80
 LISTEN     0      128         :::80                      :::*
 # 可以看到80端口已经被使用
复制代码
 [root@ldh ~]# docker run -itd --name nginx --network=host nginx:latest
 ​
 e9036ae2d7c4cff020fcb186f9cfadaf3de28fce91597d9b0ae2a8d1aa375dee
 ​
 [root@ldh ~]# docker ps -a
 CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS                      PORTS     NAMES
 e9036ae2d7c4   nginx:latest   "/docker-entrypoint.…"   24 seconds ago   Exited (1) 21 seconds ago             nginx
 # 可以看到nginx容器没有运行

1.3 Bridge网络

Docker安装时会创建一个命名为docker0的linux bridge。如果不指定--network,创建的容器默认都会挂到docker0上。如下示例,docker0上没有任何其他网络设备。

复制代码
 [root@ldh ~]# yum install bridge-utils
 [root@ldh ~]# brctl show
 ​
 bridge name bridge id       STP enabled interfaces
 docker0     8000.024227ce5b49   no  

我们新创建一个容器,一个新的网络接口veth...被挂到了docker0上了,veth...就是新创建容器的虚拟网卡。由于在创建容器的时候使用了--rm参数,退出容器时会自动的删除容器,需要开启多个终端进行示例操作。

复制代码
 [root@ldh ~]# docker run -it --name a1 --rm 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
 4: eth0@if5: <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
复制代码
 [root@ldh ~]# brctl show
 bridge name bridge id       STP enabled interfaces
 docker0     8000.024227ce5b49   no      veth1c2b156

容器有一个网卡eth0@if5。实际上eth0@if5和veth...是一对veth pair。veth pair是一种成对出现的特殊网络设备,可以把它们想象成由一根虚拟网线连接起来的一堆网卡,网卡的一头(eth0@if5)在容器中,另一头(veth...)挂在网桥docker0上,其效果就是将eth0@if5也挂在了docker0上。

我们还看到eth0@if5已经配置了IP172.17.0.2,可以通过如下命令查看bridge网络的配置信息

复制代码
[root@ldh ~]# docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "aa894a53516352df029b8dedcd25f8dbbe2c38ea85673cb7b840346ff4ced065",
        "Created": "2025-10-10T18:05:20.436250929+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "b4e53552619839017b8102613909db8d78b6eeee2fe5cdaf6fde4f63312a432d": {
                "Name": "a1",
                "EndpointID": "90bb2c8f8b789dca046e04e58bd94fe03d843c44e5c6b331b625d5401787906d",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
复制代码
......
	   "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
......

原来bridge网络配置的subnet就是172.17.0.0/16,并且网关是172.17.0.1。容器创建时,Docker会自动从172.17.0.0/16分配一个IP,这里16位的掩码保证有足够多的IP可以供容器使用。

1.4 自定义Bridge网络

之前我们所使用的网络都是安装Docker时默认生成的网络。我们可以通过bridge驱动创建类似前面默认的bridge网络,示例如下

复制代码
[root@ldh ~]# docker network create --driver bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 ldh
0c7bf8cc3db1e2346200f10c1f48ee9192d443e0f73385bd94e9ba74dd1a7367

其中,网络名称为:ldh,类型为:bridge,地址池为:172.20.0.0/16,网关为:172.20.0.1

复制代码
[root@ldh ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
aa894a535163   bridge    bridge    local
e632387f1e35   host      host      local
0c7bf8cc3db1   ldh       bridge    local
53dd0861786d   none      null      local
复制代码
[root@ldh ~]# ip a
......
6: br-0c7bf8cc3db1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:4c:b6:2a:7f brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.1/16 brd 172.20.255.255 scope global br-0c7bf8cc3db1
       valid_lft forever preferred_lft forever

创建新的容器,指定使用ldh网络,还可以使用--ip指定容器所使用的IP,这个IP必须是ldh网络地址池中的IP。如果不指定IP,那么ldh网络会自动给容器分配IP。

复制代码
# 自动分配IP
[root@ldh ~]# docker run -it --name a1 --rm --network=ldh 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
7: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.2/16 brd 172.20.255.255 scope global eth0
       valid_lft forever preferred_lft forever
复制代码
# 手动指定IP
[root@ldh ~]# docker run -it --name a2 --rm --network=ldh --ip 172.20.0.100 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
9: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:14:00:64 brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.100/16 brd 172.20.255.255 scope global eth0
       valid_lft forever preferred_lft forever

如果创建一个容器a1,使用默认的bridge网络,再创建第二个容器a2,使用ldh网络,这种情况下两个容器之间不能够直接通讯的。只有指定了相同的网络的容器才能够互通。其实我们可以为容器指定多个网络,实现容器之间的通讯,示例如下,创建新的容器,指定ldh网络,使用connect参数为该容器添加默认bridge网络,或者其他的bridge网络。

复制代码
# 创建并运行a1容器,使用默认bridge网络
[root@ldh ~]# docker run -it --name a1 --rm busybox:latest 
/ # ip a
......
11: eth0@if12: <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
复制代码
# 创建并运行a2容器,使用ldh网络
[root@ldh ~]# docker run -it --name a2 --rm --network=ldh busybox:latest 
/ # ip a
......
13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.2/16 brd 172.20.255.255 scope global eth0
       valid_lft forever preferred_lft forever

可以看到a1容器与a2容器的IP不是一个网段的,所以不能够直接通讯。

给a2容器添加默认的bridge网络

复制代码
[root@ldh ~]# docker network connect bridge a2
复制代码
/ # ip a
......
13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.2/16 brd 172.20.255.255 scope global eth0
       valid_lft forever preferred_lft forever
15: eth1@if16: <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 eth1
       valid_lft forever preferred_lft forever

这样a2容器就具有一个与a1容器同样网段的IP了,那么它们之间就可以直接通讯了。

二、docker容器之间的访问方式

容器之间访问可以使用以下方式

  1. 基于IP地址进行访问

  2. 基于容器名进行访问

  3. 多个容器共享同一个网络协议栈

注意:只有在同一个Docker网络中的容器才能够互相通讯;只有使用了默认的Bridge网络的容器是无法使用基于容器名的方式进行容器互访的。

2.1 基于IP地址进行访问

创建一个容器a1,使用ldh网络,指定IP为172.20.0.50

复制代码
[root@ldh ~]# docker run -it --name a1 --rm --network=ldh --ip 172.20.0.50 busybox:latest

创建第二个容器a2,使用ldh网络,指定IP为172.20.0.100

复制代码
[root@ldh ~]# docker run -it --name a2 --rm --network=ldh --ip 172.20.0.100 busybox:latest

直接ping对方的IP进行访问

复制代码
/ # ping 172.20.0.100
PING 172.20.0.100 (172.20.0.100): 56 data bytes
64 bytes from 172.20.0.100: seq=0 ttl=64 time=0.140 ms
64 bytes from 172.20.0.100: seq=1 ttl=64 time=0.046 ms
64 bytes from 172.20.0.100: seq=2 ttl=64 time=0.048 ms
64 bytes from 172.20.0.100: seq=3 ttl=64 time=0.047 ms
^C
--- 172.20.0.100 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.046/0.070/0.140 ms

通过以上两个示例得知,在同一个网络中的容器,是可以使用IP进行互相访问的。

2.2 基于容器名进行访问

通过IP访问容器虽然满足了通信的需求,但还是不够灵活。因为我们在部署应用之前可能无法确定IP,部署之后再指定要访问的IP会比较麻烦。对于这个问题,可以通过Docker自带的DNS服务解决。

从Docker 1.10版本开始,Docker daemon实现了一个内嵌的DNS server,使容器可以直接通过"容器名"通信。方法很简单,只要在启动时用--name为容器命名就可以了。

以centos镜像举例(有ping命令,没有ip a命令)

复制代码
# 创建a1容器,使用ldh网络
[root@ldh ~]# docker run -it --name a1 --rm --network=ldh centos:7 
[root@d69e08a904b7 /]# ip a
bash: ip: command not found
复制代码
# 创建a2容器,使用ldh网络
[root@ldh ~]# docker run -it --name a2 --rm --network=ldh centos:7 
[root@f32d9923bd73 /]# ip a
bash: ip: command not found

可以看到我们不知道a1容器与a2容器的IP地址

ping对方的容器名

复制代码
[root@d69e08a904b7 /]# ping a2
PING a2 (172.20.0.3) 56(84) bytes of data.
64 bytes from a2.ldh (172.20.0.3): icmp_seq=1 ttl=64 time=0.040 ms
64 bytes from a2.ldh (172.20.0.3): icmp_seq=2 ttl=64 time=0.035 ms
64 bytes from a2.ldh (172.20.0.3): icmp_seq=3 ttl=64 time=0.037 ms
^C
--- a2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.035/0.037/0.040/0.005 ms

通过以上示例得知,创建容器时,使用--name定义容器名称,当容器启动时,Docker daemon会把容器名与容器获取的IP进行绑定,写入到Docker DNS中,这样容器之间访问就可以基于容器名实现了,如果容器停止了,该容器所对应的DNS信息就会从Docker DNS中删除。使用Docker DNS有个限制,只能在新创建的bridge网络(自定义的网络)中使用。

2.3 joined容器

Joined(联合)容器是另一种实现容器间通信的方式。joined容器非常特别,它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined容器之间可以通过127.0.0.1直接通信。

复制代码
# 创建a1容器,使用ldh网络
[root@ldh ~]# docker run -it --name a1 --rm --network=ldh 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
25: eth0@if26: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.2/16 brd 172.20.255.255 scope global eth0
       valid_lft forever preferred_lft forever
复制代码
# 创建a2容器,--network指定为容器a1
[root@ldh ~]# docker run -it --name a2 --rm --network=container:a1 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
25: eth0@if26: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.2/16 brd 172.20.255.255 scope global eth0
       valid_lft forever preferred_lft forever

可以发现a1容器与a2容器的网络栈一样

ping对方容器名

复制代码
/ # ping a1
PING a1 (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.030 ms
64 bytes from 172.20.0.2: seq=1 ttl=64 time=0.038 ms
^C
--- a1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.030/0.034/0.038 ms

使用joined容器的方式实现容器间的通讯,需要注意的是两个容器之间的应用端口容易发生冲突,两个容器共享一个网络栈,那么容器中的应用在运行时,绑定的IP也是一样。

2.4 容器访问外部

同虚拟机访问外部网络使用的都是NAT地址转换原理

2.5 外部访问容器

使用的是docker端口映射原理

Docker 端口映射是指将容器内部的端口映射到宿主机的端口上,从而使外部可以访问容器内的服务。默认情况下,Docker 容器运行时是无法被外部网络直接访问的,因此需要进行端口映射。

也可以使用host网络,容器共享Docker host网络栈。

相关推荐
BingoGo2 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack2 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack5 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理5 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
feifeigo1235 天前
matlab画图工具
开发语言·matlab
dustcell.5 天前
haproxy七层代理
java·开发语言·前端