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网络栈。

相关推荐
细节控菜鸡4 小时前
【2025最新】ArcGIS for JS 范围裁剪(只保留特定区域显示),实现精准地理范围聚焦
开发语言·javascript·arcgis
一根甜苦瓜4 小时前
Go语言Slice的一道骚题
开发语言·后端·golang
驰羽4 小时前
[GO]Go语言泛型详解
开发语言·golang·xcode
NPE~4 小时前
[手写系列]Go手写db — — 第五版(实现数据库操作模块)
开发语言·数据库·后端·golang·教程·手写系列·手写数据库
润 下5 小时前
C语言——深入解析C语言指针:从基础到实践从入门到精通(二)
c语言·开发语言·经验分享·笔记·学习·程序人生
布伦鸽5 小时前
C# WPF DataGrid使用Observable<Observable<object>类型作为数据源
开发语言·c#·wpf
say_fall5 小时前
精通C语言(4.四种动态内存有关函数)
c语言·开发语言
暴力求解5 小时前
c++类和对象(下)
开发语言·c++·算法
小镇学者5 小时前
【PHP】利用 xlswriter 扩展导出的Excel文件报错问题
php·excel