【云原生Docker】09-Docker网络详解

【云原生|Docker】09-Docker网络详解

前言

	当项目大规模使用 Docker 时,容器通信的问题也就产生了。要解决容器通信问题,必须先了解很多关于网络的知识。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker 同样有着很多不完善的地方,网络方面就是 Docker 比较薄弱的部分。因此,我们有必要深入了解 Docker 的网络知识,以满足更高的网络需求。
	Docker网络也是docker学习中重要的一部分,前门我们说介绍的docker操作均是在单宿主机上安装和使用docker,然后再生产环境中单节点的使用是没有实际意义的,因此这一章节我们将详细介绍docker的网络使用,已经docker跨宿主机网络使用。

网络详解

​ 安装 Docker 以后,会默认创建三种网络,可以通过 docker network ls 查看。

[root@clinet ~]# docker network ls 
NETWORK ID     NAME      DRIVER    SCOPE
44ccbd74a658   bridge    bridge    local
016f4cda7f9a   host      host      local
6167ccead0c4   none      null      local

网络模式介绍:

  • 桥接网络(bridge network

桥接网络是Docker默认的网络模式,也是最常用的一种。在桥接网络中,Docker主机上的所有容器都连接到同一个虚拟网络中。Docker会为每个容器分配一个唯一的IP地址,容器之间可以相互通信。

  • 主机网络(host network)

主机网络模式让容器直接使用主机的网络栈,容器中的应用程序可以直接访问主机上的网络接口。这种模式的好处是容器的网络性能非常高,但是容器之间无法直接通信,因此这种模式一般只用于需要访问主机网络的应用程序。

  • none网络(none network)

none网络模式让容器没有网络接口,也没有IP地址。这种模式通常用于测试和调试,或者需要在容器中运行一些不需要网络连接的应用程序。

  • container模式

container模式,也称为容器网络模式。在这种模式下,容器可以共享另一个容器的网络栈,即两个容器可以使用同一个虚拟网络接口和IP地址。

  • 自定义

docker 1.9版本以后新增的特性,允许容器使用第三方的网络实现或者创建单独的bridge网络,提供网络隔离能力。可自定义的网络类型:bridge,overlay,macvlan。

bridge网络

​ 在该模式中,Docker 守护进程创建了一个虚拟以太网桥 docker0,新建的容器会自动桥接到这个接口,附加在其上的任何网卡之间都能自动转发数据包。

默认情况下,守护进程会创建一对对等虚拟设备接口 veth pair,将其中一个接口设置为容器的 eth0 接口(容器的网卡),另一个接口放置在宿主机的命名空间中,以类似 vethxxx 这样的名字命名,从而将宿主机上的所有容器都连接到这个内部网络上。

 容器安装后默认会创建一个docker0的网桥,网桥的默认ip段为172.17.0.1/16,我们可以通过docker的配置文件(/etc/docker/daemon.json)自定义网桥ip段。
 
 [root@clinet ~]# cat /etc/docker/daemon.json 
{
  "bip": "172.18.0.1/16",
  "registry-mirrors": ["https://mqkiky4e.mirror.aliyuncs.com"]
}
[root@clinet ~]#

我们通过创建一个busybox的容器,使用bridge网络,来深入了解brige网络的连接。

[root@clinet ~]# docker run -it --network bridge busybox /bin/sh
(--network  bridge是默认的,可以不指定。)

创建完容器之后,我们在宿主机上通过ip add查看的信息如下:

在这里插入图片描述

此时宿主机上创建了一对对等虚拟设备接口 veth pair,将其中一个接口设置为容器的 eth0 接口(容器的网卡),另一个接口放置在宿主机的命名空间中,以类似 vethxxx 这样的名字命名。如上图所示,9表示为连接到容器内的网络连接(eth0@if9),

在这里插入图片描述

同时通过在宿主机上可以查看到相关网桥的信息:

在这里插入图片描述

综上所述,bridge网络的拓扑如下:

在这里插入图片描述

Bridge 桥接模式的实现步骤主要如下:

1. 启动一个容器的时候,Docker Daemon会在宿主机上创建一对虚拟网络接口,该接口相当于网线的两端,一端在宿主机上(veth pair格式),另外一端在容器内为eth0;
2.  同时Docker Daemon 会将宿主机上的 veth pair 接口桥接到 Docker Daemon 创建的 docker0 网桥上。
3.  docker0网桥同时也类似为dhcp,会给容器的eth0网卡分配相同段的ip。
  • 通过docker inspect 容器id来查看容器的详细信息,其中网络部分如下:
[root@clinet ~]# docker inspect 53a |grep -A 30 Networks

在这里插入图片描述

  • docker network inspect bridge查看网桥的详细信息。
[root@clinet ~]# docker network inspect bridge 
# 通过如下命令会列出bridge网络的相关信息,其中"Containers"字段的表示是信息是指当前节点上有哪些容器使用了该网络。

  • 使用–network 指定bridge网络
docker run -d --name web1 --net bridge nginx

基于bridge网络的容器访问外部网络

默认情况下,基于bridge网络容器即可访问外部网络,这是因为默认情况下,docker使用了iptables的snat转发来实现容器对外部的访问(需要内核开启net.ipv4.ip_forward=1)

在这里插入图片描述

外部网络访问基于bridge网络的容器

如果想让外界可以访问到基于bridge网络创建的容器提供的服务,则必须要告诉docker要使用的端口。

可以通过如下方法查看镜像会使用哪些端口:

docker inspect nginx | jq .[]."ContainerConfig"."ExposedPorts"

在创建容器的时候可以指定这个容器的端口与主机端口的映射关系:

docker run -d --name web -P nginx

-p: 可以指定主机与容器的端口关系,冒号左边是主机的端口,右边是映射到容器中的端口
-P:该参数会分配镜像中所有的会使用的端口,并映射到主机上的随机端口

这种端口映射基于iptables的dnat实现

在这里插入图片描述

查看容器的端口情况:

docker port  容器名称
或
docker  ps  -a  (找到对应容器)

host网络

  • host 网络模式需要在创建容器时通过参数 --net host 或者 --network host 指定;
  • 采用 host 网络模式的 容器,可以直接使用宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换;
  • 使用host网络的主机,与宿主机共享网络地址,可以获得最好的数据转发性能。
  • 使用host网络的缺点是,同一个宿主机上的多个容器共享同一个ip地址,如果多容器使用相同的端口,需要自行解决端口冲突问题。(这也是host网络一般不使用的原因。)
  1. 可以通过如下方式查看host网络信息:
docker inspect host
  1. 创建一个使用host网络容器的示例:
# 可以看到该容器没有自己的IP地址,因为它直接使用宿主机IP地址
docker run -it --network host busybox

在这里插入图片描述

host网络拓扑

在这里插入图片描述

none网络

  • none 网络模式是指禁用网络功能,只有 lo 接口 local 的简写,代表 127.0.0.1,即 localhost 本地环回接口。在创建容器时通过参数 --net none 或者 --network none 指定;
  • 使用none网络的容器除了lo,没有其他任何网卡,完全隔离。用于既不需要访问外部服务,也不允许外部服务访问自己的应用场景。
  1. 查看none网络信息:
docker network inspect none
  1. 创建一个使用none网络容器的示例:
docker run -it --network none busybox

在这里插入图片描述

container网络

  • Container 网络模式是 Docker 中一种较为特别的网络的模式。在创建容器时通过参数 --net container:已运行的容器名称|ID 或者 --network container:已运行的容器名称|ID 指定;
  • 处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用 localhost 高效快速通信。
  • Container 网络模式即新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样两个容器除了网络方面相同之外,其他的如文件系统、进程列表等还是隔离的。

在这里插入图片描述

  1. 创建一个基础容器nginx,该容器使用bridge模式
[root@clinet ~]# docker run -d --name nginx --network bridge nginx 
5acd9628840da292a618b44499fdf4c6ac56f11b4c64390411ec41f7b59a8b9f
[root@clinet ~]#

此时基础容器的网络情况如下:

在这里插入图片描述

  1. 创建一个busybox容器,使用container网络模式
docker run -it --network container:nginx busybox

此时busybox容器的网络如下:

在这里插入图片描述

此时宿主机上的网络情况如下:

在这里插入图片描述

总上所述,Docker 守护进程只创建了一对对等虚拟设备接口,busybox容器完全的使用了nginx容器的网络。

  1. 当我们停止掉nginx容器的时候,网络信息如下:

在这里插入图片描述

此时busybox容器只剩下了lo网络接口。

自定义网络

Docker除了提供三种的默认网络模式之外,也允许用户针对一些特定的应用场景去创建一些自定义的网络。这样属于这个网络的容器就可以单独隔离出来,它们之间可以相互通信,而不在这个网络的容器就不能直接访问到它们。一个容器可以属于多个网络,同一个自定义网络下的容器可以通过各自的容器名访问到对方,因为会使用到docker内嵌的一个dns功能。

Docker提供三种自定义网络驱动:

1. bridge
2. overlay
3. macvlan

自定义bridge网络

  1. 创建一个叫作my_net的自定义网络
docker network create --driver bridge my_net    #--driver用于指定网络类型,不指定默认为bridge
  1. 通过指定子网和网关的方式创建my_net2网络:
docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net2
  1. 查看网络信息

在这里插入图片描述

  1. 宿主机上会产生两个类似docker0的网桥。

在这里插入图片描述

  1. 删除自定义网络

docker network rm my_net1 (自定义网络名称)

注意:如果通过某个自定义网络模式创建了容器,则该网络模式无法删除。

示例:

  • 使用自定义的bridge网络my_net1,创建一个busybox容器
docker run -it --network my_net1 busybox

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aMNzP2LI-1680683532782)(D:\学习\学习笔记\图片\29.png)]

  • 使用自定义的bridge网络my_net2,创建一个busybox容器
docker run -it --network my_net2 busybox

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-twjma6ca-1680683532783)(D:\学习\学习笔记\图片\30.png)]

容器的互通

  • 这里所说的容器互通是指在同一个宿主机上的容器;
  • 容器互通必须要求互通容器在同一个网络内;

两个相同的bridge网络容器互通(默认bridge)

  1. 创建一个基于默认的 bridge 网络模式的容器.
docker run -d --name  nginx_test nginx

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i9QQGdjD-1680683532784)(D:\学习\学习笔记\图片\31.png)]

  1. 创建另一个基于默认的 bridge 网络模式的容器,并测试连通性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bVTl7dg6-1680683532785)(D:\学习\学习笔记\图片\32.png)]

经过测试,从结果得知两个属于同一个网络的容器是可以进行网络通信的。

两个相同的bridge网络容器互通(自定义bridge)

  1. 创建一个基于自定义的my_net1网络模式的容器.
docker run -d --name nginx --network my_net1 nginx

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jZ5bIytW-1680683532786)(D:\学习\学习笔记\图片\33.png)]

  1. 创建另一个基于my_net1网络模式的容器,并测试连通
docker run -it --name busybox --network my_net1 busybox ping 172.17.0.2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LHvbz97a-1680683532787)(D:\学习\学习笔记\图片\34.png)]

	从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过容器名称通信。方法很简单,只要在创建容器时使用 --name 为容器命名即可。
	但是使用 Docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的,所以我们就需要自定义网络。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4JFnEGXO-1680683532788)(D:\学习\学习笔记\图片\35.png)]

两个不同bridge网络互通

  1. 创建一个基于默认的 bridge 网络模式的容器.
docker run -d --name  nginx_1 nginx

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kCA9TWLx-1680683532789)(D:\学习\学习笔记\图片\36.png)]

  1. 创建一个基于自定义的my_net2网络模式的容器. 并测试互通。
docker run -it --network my_net2  busybox ping 172.18.0.3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QGh8ZTDy-1680683532790)(D:\学习\学习笔记\图片\37.png)]

此时网络不通。

  1. 通过 docker network connect 网络名称 容器名称 为容器连接新的网络模式。
docker network connect my_net2 nginx_1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v9d5Yjdc-1680683532791)(C:\Users\xhz\AppData\Roaming\Typora\typora-user-images\38.png)]

  1. 测试网络连通性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4PiPYh6R-1680683532792)(C:\Users\xhz\AppData\Roaming\Typora\typora-user-images\39.png)]

  1. 此时两个网络结果如下:

此时相当于nginx_1容器存在两个网卡,一个是桥接到docker0的,一个是桥接到my_net2的,因此实现原理还是两容器处于相同的ip段。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k9KnlmuQ-1680683532793)(D:\学习\学习笔记\图片\388.png)]

  1. 断开网络
docker network disconnect my_net2 nginx_1
1.  上述所说的容器互通均是同一宿主机上的场景;
2.  互通的根本原理是让两个容器处于同一个桥接网卡上,即:相同的ip段。

后面我们将单独说说跨主机容器互通的问题。

Docker network命令

  1. 创建一个新的Docker网络
docker network create my_network

语法如下:

docker network create [OPTIONS] NETWORK
其中,OPTIONS是一些可选参数,NETWORK是要创建的网络的名称。
下面是一些常用的OPTIONS参数:
--driver:指定网络驱动程序,默认为bridge。
--subnet:指定网络的IPv4子网。
--gateway:指定网络的IPv4网关。
--ipv6:启用IPv6支持。
--ip-range:指定网络的IPv4地址范围。
--ipam-driver:指定IP地址管理驱动程序。
--ipam-opt:指定IP地址管理驱动程序的选项。

1.1 创建一个名为my_network的桥接网络,其中IPv4子网为172.18.0.0/16,网关为172.18.0.1

docker network create --driver bridge --subnet=172.18.0.0/16 --gateway=172.18.0.1 my_network

1.2 将创建一个名为my_network的桥接网络

docker network create --driver bridge my_network
  1. 将名为my_container的容器连接到名为my_network的Docker网络
docker network connect  my_network  my_container
  1. 将名为my_container的容器从名为my_network的Docker网络中断开连接,
docker network disconnect my_network my_container
或
## --force  强制
docker network disconnect --force  my_network my_container
  1. 查看网络的详细信息
docker  inspect  网络名称
  1. 列出所有的Docker网络
docker  network  ls
  1. 删除一个Docker网络
docker  network  rm  网络名
  1. 删除所有未使用的Docker网络
docker  network  prune

为my_container的容器从名为my_network的Docker网络中断开连接,

docker network disconnect my_network my_container
或
## --force  强制
docker network disconnect --force  my_network my_container
  1. 查看网络的详细信息
docker  inspect  网络名称
  1. 列出所有的Docker网络
docker  network  ls
  1. 删除一个Docker网络
docker  network  rm  网络名
  1. 删除所有未使用的Docker网络
docker  network  prune

猜你喜欢

转载自blog.csdn.net/qq_43714097/article/details/129972782