一、Bridge网络

bridge网络表现形式就是docker0这个网络接口。容器默认都是通过docker0这个接口进行通信。也可以通过docker0去和本机的以太网接口连接,这样容器内部才能访问互联网。

查看docker0网络,在默认环境中,一个名为docker0的linux bridge自动被创建好了,其上有一个 docker0 内部接口,IP地址为172.17.0.1/16。通过命令:ip a

image-20240222113826449

查看docker网络

docker network ls

查看bridge网络详情。主要关注Containers节点信息。

docker network inspect bridge

输出如下:

[
    {
        "Name": "bridge",
        "Id": "8f2bb7721e07845f809dab6cfeefccc5145cbb99953bbe090d5c349af5bf5fa1",
        "Created": "2024-01-22T22:29:27.110338803+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": {},
        "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": {}
    }
]

我们看到Containers这个节点下,没有值,也就是没有任何容器加入这个网络环境

1.1、docker0详解

1、拉取镜像

docker pull nginx:1.19.3-alpine

2、运行镜像

docker run -itd --name nginx1 nginx:1.19.3-alpine

3、观察bridge网络

docker network inspect bridge

image-20240222113925889

可以看到nginx的网络ip地址是172.17.9.2。这个是因为docker0的网络地址范围是172.17.0.1~172.17.255.255

4、查看宿主机上的网卡

// 用于显示或操作系统的网络接口信息

ip a

image-20240222113941106

发现多出一块网卡veth0ce8f41@if9

veth(Virtual Ethernet)是Linux网络命名空间中的一种虚拟网络设备类型。它总是成对出现,就像一个虚拟的以太网线缆,一端插在一个网络命名空间,另一端插在另一个网络命名空间或者主机的全局网络命名空间。

veth对在容器技术(如Docker)中实现网络隔离和通信非常有用。例如,当你在Docker中启动一个新的容器时,Docker会创建一对veth接口。一个接口在新的容器的网络命名空间中,另一个接口在主机的网络命名空间中。这样,容器就可以通过这对veth接口与主机和其他容器通信。

Docker创建一个容器的时候,会执行如下操作:

  • 创建一对虚拟接口/网卡,也就是veth pair,分别放到本地主机和新容器中;
  • 本地主机一端桥接到默认docker0或指定网桥上,并具有一个唯一的名字,如veth0ce8f41@if9`;
  • 容器一端放到新容器中,并修改名字作为eth0,这个网卡/接口只在容器的名字空间可见;
  • 从网桥可用地址段中(也就是与该bridge对应的network)获取一个空闲地址分配给容器的eth0,并配置默认路由到桥接网卡veth0ce8f41@if9:。

完成这些之后,容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络。 如果不指定–network,创建的容器默认都会挂到 docker0 上,使用本地主机上 docker0 接口的 IP 作为 所有容器的默认网关

第一种方式:
docker exec -it nginx1 sh
ip a
第二种方式:
docker exec -it nginx1 ip a

image-20240222113958742

安装brctl

brctl是一个用于设置和管理Linux桥接设备的命令行工具。在大多数Linux发行版中,brctl包含在bridge-utils软件包中。

yum install -y bridge-utils

运行命令

brctl show

1.2、多容器之间通信

1、再安装一个nginx

docker run -itd --name nginx2 nginx:1.19.3-alpine

2、查看bridge网络

docker network inspect bridge

3、显示结果

"Containers": {
            "3c178352ba547b43d84d1027bd268cf037488a7351cf5bb18c09b8a326a7986a": {
                "Name": "nginx1",
                "EndpointID": "21c8a36dcf1b22414098f112af7ff5a896180fd60d88f918cf220e2de4cb1aeb",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "bc60737cd65607de4224337766c01a7e3e0177e401ab1170e76cfe00a4b083c2": {
                "Name": "nginx2",
                "EndpointID": "b10d02f3435c51053c7ddb4b1c915b2bef9e90a79caf9b0819ae2316a7ef9a4a",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },

4、运行brctl show

brctl show命令用于显示系统中所有的网络桥接器及其相关信息。

image-20240222114022127

image-20240222114032731

问题点:

每次重启docker的时候,容器的ip地址会变,谁先启动,谁获取前面的ip地址。开发人员不能在代码中写死数据库的IP地址。举个例子:

在企业开发环境中,有个msql服务容器mysql5,还有个web服务容器tomcat8,tomcat8肯定要连接mysql5,需要知道对方的真实ip地址。这时候我们就需要使用容器名来ping,而不是ip地址

二、新建Bridge网络

docker network create -d bridge test-bridge

这条命令是用来在Docker中创建一个新的网络桥接器的。

docker network create是用来创建新的网络的命令,-d bridge指定了网络的驱动类型为桥接,test-bridge是你为新创建的网络桥接器指定的名称。

创建完成后,你可以使用docker network ls命令来查看所有的网络,包括你刚刚创建的test-bridge网络。

你也可以在运行新的容器时,使用--network=test-bridge参数来指定容器使用这个新创建的网络。

当然如果你就要创建bridge。可以不带-d的参数。

image-20240222114052084image-20240122233909390

2.1、brctl show查看

image-20240222114106035image-20240122234038290

说明这个网卡还没有绑定容器

2.2、启动nginx3绑定test-bridge网卡

docker run -itd --name nginx3 --network test-bridge nginx:1.19.3-alpine

启动一个nginx的容器nginx3,并通过参数network connect来连接test-bridge网络。

image-20240222114118906image-20240122234323512

bridge绑定了新的网卡

2.3、把一个运行中容器连接到test-bridge网络

docker network connect test-bridge nginx2

2.4、创建自定义网络的好处

当你在Docker中创建一个自定义网络时,Docker会为该网络启用一个内置的DNS服务器。这个DNS服务器会自动为加入该网络的每个容器提供DNS解析服务。

这意味着,当你的容器加入到这个自定义网络时,它们可以使用其他容器的名称来进行网络通信,而不需要知道其他容器的IP地址。这是因为Docker的内置DNS服务器会自动将容器的名称解析为其内部IP地址。

例如,假设你有两个在同一个自定义网络中的容器,名为container1container2。在container1中,你可以直接使用ping container2来pingcontainer2,而不需要知道container2的IP地址。

这个特性使得在Docker中管理和连接容器变得更加简单,因为你不需要手动管理和配置IP地址。

2.5、docker0默认不能互访的原因

Docker的默认桥接网络(通常被称为docker0)是在Docker首次安装时创建的。这个默认网络的设计目标是为了让Docker能够“开箱即用”,而不需要用户进行任何额外的网络配置。

然而,docker0网络并没有启用Docker的内置DNS服务。这意味着在docker0网络中的容器不能直接通过容器名进行通信,必须使用容器的IP地址。这是一个已知的限制,是为了保持向后兼容性和简单性。

如果你需要使用容器名进行通信,你可以创建一个自定义的桥接网络。在自定义网络中,Docker的内置DNS服务是默认启用的。你可以使用docker network create命令来创建一个自定义网络,然后在运行容器时使用--network参数来指定容器加入这个网络。

三、none、host网络

3.1、none网络

环境准备,先stop和rm掉全部之前开启的容器。并且把前面创建的test-bridge网络也删除。当然,更简单的办法是使用快照方式。将虚拟机恢复到docker初始化安装时。或者手动删除容器与网络

docker rm -f $(docker ps -aq)
docker network rm test-bridge
docker network ls

启动一个ngnix的容器nginx1,并且连接到none网络。然后执行docker network inspect none,看看容器信息

docker run -itd --name nginx1 --network none nginx:1.19.3-alpine
docker network inspect none

image-20240222114139716image-20240123232817227

注意,容器使用none模式,是没有物理地址和IP地址。我们可以进入到nginx1容器里,执行ip a命令看 看。只有一个lo接口,没有其他网络接口,没有IP。也就是说,使用none模式,这个容器是不能被其他 容器访问。这种使用场景很少,只有项目安全性很高的功能才能使用到。例如:密码加密算法容器。

知识点:

lo 接口,全称为 “loopback” 接口,是一个特殊的网络接口,用于网络软件的测试和本地通信。

当你向 lo 接口发送数据时,数据不会被发送到网络上,而是直接返回到发送者。这就像你在一个封闭的房间里大声说话,声音会反射回来,你可以听到自己的声音。

lo 接口通常有一个特殊的 IP 地址 127.0.0.1(也被称为 “localhost”)。当你向这个地址发送数据时,数据会被发送到 lo 接口,然后直接返回到发送者。

lo 接口在网络软件的开发和测试中非常有用。例如,你可以在同一台机器上运行客户端和服务器程序,然后使用 lo 接口进行通信,以测试它们的功能。

docker exec -it nginx1 sh

image-20240222114153074image-20240123233007075

3.2、host网络

启动一个nginx的nginx2容器,连接到host网络。然后docker network inspect host, 看看容器信息

docker run -itd --name nginx2 --network host nginx:1.19.3-alpine
docker network inspect host

image-20240222114209444image-20240123233320208

这里来看,也不显示IP地址。那么是不是和none一样,肯定不是,不然也不会设计none和host网络进 行区分。下面我们进入nginx2容器,执行ip a看看效果。我们在容器里执行ip a,发现打印内容和在 linux本机外执行ip a是一样的。

docker exec -it nginx2 sh

image-20240222114222720image-20240123233439168

这说明什么呢?容器使用了host模式,说明容器和外层linux主机共享一套网络接口。VMware公司的虚拟机管理软件,其中网络设置,也有host这个模式,作用也是一样,虚拟机里面使用网络和你自己外层机器是一模一样的。这种容器和本机使用共享一套网络接口,缺点还是很明显的,例如我们知道web服务器一般端口是80,共享了一套网络接口,那么你这台机器上只能启动一个nginx端口为80的服务器了。否则,出现端口被占用的情况。

四、总结

Docker 提供了多种网络模式,以满足不同的应用场景:

  1. 桥接网络(bridge):这是 Docker 的默认网络模式。在这种模式下,Docker 为每个容器分配一个私有的网络空间,并为每个容器创建一个虚拟网络接口,然后将这个接口连接到一个虚拟桥接器上。Docker 还会在宿主机上创建一个 docker0 网桥,并将所有容器的虚拟网络接口连接到这个网桥上,从而实现容器之间的通信。
  2. 主机网络(host):在这种模式下,容器直接共享宿主机的网络,没有自己的网络空间。这种模式的优点是网络性能高,但缺点是容器的网络隔离性差。
  3. 无网络(none):在这种模式下,容器没有自己的网络空间,也不能访问宿主机的网络。这种模式通常用于需要高度隔离的场景。
  4. 用户定义网络(user-defined network):Docker 允许用户创建自定义的网络,并将容器连接到这些网络上。用户定义网络可以是桥接网络、覆盖网络(overlay)或者 MACVLAN 网络。覆盖网络用于跨主机的容器通信,MACVLAN 网络用于将容器直接连接到物理网络。

如果刚接触docker对这块网络没有什么概念的话,安装镜像就会遇到一系列问题。比如我们在使用docker安装es与kibana的时候,会遇到kibana连不上es的问题,直到你了解docker设计的网络的原理,才能正确安装。总之,多多练习。