编辑
2024-02-08
TechNotes
00

目录

概念
是什么
为什么需要
能做什么
网络模式
bridge(桥接)<默认模式>
host(主机模式)
none
container
自定义(推荐)
为容器指定网络模式
桥接模式的网络互联
实现原理
跨容器网络通信
原理图
none网络模式实容器互通
原理
容器和宿主机的关系

概念

是什么

是 Docker 对容器网络隔离的一项技术,提供了多种不同的模式供用户使用,选择不同的网络模式来实现容器网络的互通以及彻底的隔离。

为什么需要

  • 容器间的网络隔离
  • 实现部分容器之间的网络共享
  • 管理多个子网下容器的 ip

能做什么

  • 提供了多种模式,可以定制化的为每个容器置顶不同的网络
  • 自定义网络模式,划分不同的子网以及网关、dns等配置
  • 网络互通
    • 实现不同子网之间的网络互通
    • 基于容器名(主机名)的方式在网络内访问

网络模式

bridge(桥接)<默认模式>

在主机中创建一个 Docker0 的虚拟网桥,在 Ddocker0 创建一对虚拟网卡,有一半在主机上 veth,还有一半在容器内 eth0, 实现主机与容器间的通信.

image.png

host(主机模式)

容器不再拥有自己的网络空间,而是直接与主机共享网络空间,那么基于该模式创建的容器对应的 ip 实际就是与主机同一个子网,同一个网段。

  • 牺牲主机一定的安全性, 无法实现容器的隔离

image.png

none

Docker 会拥有自己的网络空间,不与主机共享,在这个网络模式下的容器,不会被分配网卡、ip、路由等相关信息。

  • 特点:完全隔离,与外部任何机器都无网络访问,只有自己的 lo 本地网络 127.0.0.1

image.png

container

就是不会创建自己的网络空间,而是与其他容器共享网络空间,直接使用指定容器的ip/端口等

自定义(推荐)

不适用 Docker 自带的网络模式,而是自己去定制化自己特有的网络模式。

  • 命令:
bash
docker network COMMAND
  • 例子
bash
docker network create --driver bridge --subnet 192.168.133.0/24 --gateway 192.168.133.1 gycnet01
  • docker network create: 这个命令用于创建一个新的 Docker 网络。Docker 网络使容器可以相互通信,也可以连接到外部网络。

  • --driver bridge: 这个参数指定网络驱动类型为 bridge。桥接网络是 Docker 默认的网络驱动,创建的容器会在同一个虚拟局域网(VLAN)中,相互通信时使用容器的 IP 地址。

  • --subnet 192.168.133.0/24: 这个参数指定了新建网络的子网范围。192.168.133.0/24 表示子网掩码为 255.255.255.0 的子网,IP 地址范围从 192.168.133.1 到 192.168.133.254。

  • --gateway 192.168.133.1: 这个参数指定了该网络的默认网关 IP 地址,通常是子网中的第一个可用 IP 地址。在这个网络中,所有容器都会通过这个网关与外部网络通信。

  • gycnet01: 这是为新创建的 Docker 网络指定的名称。在这个例子中,网络名称为 gycnet01。

为容器指定网络模式

bash
[root@ser977621502852 ~]# docker run -d --rm -P --name nginx_network1 --net gycnet01 nginx 3a157e7e143292f7c1d0edb58b1dd3cc2d77ebb6596ac07c172e076cf14c0117 [root@ser977621502852 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3a157e7e1432 nginx "/docker-entrypoint.…" 8 seconds ago Up 5 seconds 0.0.0.0:32768->80/tcp, :::32768->80/tcp nginx_network1 [root@ser977621502852 ~]# docker exec -it 3a157e7e1432 /bin/bash root@3a157e7e1432:/# cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 192.168.133.2 3a157e7e1432
  • --net 参数指定网络模式

桥接模式的网络互联

bash
[root@ser977621502852 ~]# docker run -d --rm -P --name docker_net1 --net bridge centos ping 127.0.0.1 Unable to find image 'centos:latest' locally latest: Pulling from library/centos a1d0c7532777: Pull complete Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177 Status: Downloaded newer image for centos:latest 8aea9f40c341a4bb0c7bfa1a940eaf5da32a3d0d645409bebc5ca79dd6d5f8ad [root@ser977621502852 ~]# docker run -d --rm -P --name docker_net2 --net bridge centos ping 127.0.0.1 6b375a46000f8b0d7cb85544aae188c1d7912b697b7fefb66d958506042c023b [root@ser977621502852 ~]# docker exec -it docker_net1 ping docker_net2 ping: docker_net2: Name or service not known
  1. 创建了两个网络模式为bridge的centos容器
  2. 让它们执行ping 127.0.0.1命令是为了容器不停止而被终止删除
  3. 两个桥接模式下的容器无法相互(名称)ping通
bash
docker run -d --rm -P --name docker_net2 --link docker_net1 centos ping 127.0.0.1
  • 使用--link参数可以使docker_net2关联到docker_net1,使docker_net2ping通docker_net1
  • 只支持自定义的网络, 或默认(bridge)网络
  • 只能实现ping通关联的容器, 无法实现双向ping通

实现原理

image.png

  • 在/etc/hosts文件中将所链接的容器名称与ip相对应

跨容器网络通信

  1. 创建两个不同网络模式的容器
bash
[root@ser977621502852 ~]# docker run -d --rm -P --name net1 centos ping 127.0.0.1 a83bab59f6922fd319c5ad764f5322c518327c0272d8e059ccc743138ded2d89 [root@ser977621502852 ~]# docker run -d --rm -P --name net2 --net gycnet01 centos ping 127.0.0.1 dbf74338e382f009a79b5641d6a3a2b56ca6409d74c5c623735d1b028d0270eb
  1. 使用docker inspect 命令查看容器详细信息
  • net1 172.17.0网段

image.png

  • net2 192.168.133网段

image.png

  1. net2 ping net1, 无法ping通
bash
[root@ser977621502852 ~]# docker exec -it net2 ping net1 ping: net1: Name or service not known
  1. 使用 docker network connect命令连接
bash
[root@ser977621502852 ~]# docker network connect gycnet01 net1 [root@ser977621502852 ~]# docker exec -it net2 ping net1 PING net1 (192.168.133.3) 56(84) bytes of data. 64 bytes from net1.gycnet01 (192.168.133.3): icmp_seq=1 ttl=64 time=0.235 ms 64 bytes from net1.gycnet01 (192.168.133.3): icmp_seq=2 ttl=64 time=0.128 ms ^C --- net1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 0.128/0.181/0.235/0.055 ms
  • 发现可以ping通
  • 命令 docker network connect gycnet01 net1 的作用是将已经运行的容器 net1 连接到 Docker 网络 gycnet01 中
  • 实际上相当于在容器 net1 中添加了一张新网卡,这张网卡使用 gycnet01 网络

image.png

原理图

image.png

none网络模式实容器互通

  1. 创建两个网络模式为none的容器
bash
[root@ser977621502852 ~]# docker run -d --rm -P --name net1 --net none centos ping 127.0.0.1 a2ea1a0de45cbc53016943d86e85725aefe639029dbb2a6bba411045de0d7e82 [root@ser977621502852 ~]# docker run -d --rm -P --name net2 --net none centos ping 127.0.0.1 e40dad334de72b76d1112ac66c5807621aa128e75dbb9e1eb852ce17997fd475 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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 [root@ser977621502852 ~]# docker exec -it net2 ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
  • 发现两个容器只有回环地址
  • 当然无法ping通

两个容器之间可以直连通信,但不通过主机网桥进行桥接。解决的办法是创建一对 peer 接口,分别放到两个容器中,配置成点到点链路类型

  1. 找到这两个容器的进程号:
bash
[root@ser977621502852 ~]# docker inspect -f '{{.State.Pid}}' net1 5117 [root@ser977621502852 ~]# docker inspect -f '{{.State.Pid}}' net2 5172
  1. 然后创建网络命名空间的跟踪文件:
bash
mkdir -p /var/run/netns ln -s /proc/5117/ns/net /var/run/netns/5117 ln -s /proc/5172/ns/net /var/run/netns/5172
  1. 创建一对 veth 接口并配置网络
bash
ip link add A type veth peer name B ip link set A netns 5117 ip netns exec 5117 ip addr add 10.1.1.1/32 dev A ip netns exec 5117 ip link set A up ip netns exec 5117 ip route add 10.1.1.2/32 dev A ip link set B netns 5172 ip netns exec 5172 ip addr add 10.1.1.2/32 dev B ip netns exec 5172 ip link set B up ip netns exec 5172 ip route add 10.1.1.1/32 dev B
  1. 测试连接
  • 你可以进入任一容器,并尝试 ping 另一容器的 IP 地址来测试通信:
bash
[root@ser977621502852 ~]# docker exec -it net1 ping 10.1.1.2 PING 10.1.1.2 (10.1.1.2) 56(84) bytes of data. 64 bytes from 10.1.1.2: icmp_seq=1 ttl=64 time=0.194 ms 64 bytes from 10.1.1.2: icmp_seq=2 ttl=64 time=0.071 ms ^C --- 10.1.1.2 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 999ms rtt min/avg/max/mdev = 0.071/0.132/0.194/0.062 ms [root@ser977621502852 ~]# docker exec -it net2 ping 10.1.1.1 PING 10.1.1.1 (10.1.1.1) 56(84) bytes of data. 64 bytes from 10.1.1.1: icmp_seq=1 ttl=64 time=0.138 ms 64 bytes from 10.1.1.1: icmp_seq=2 ttl=64 time=0.152 ms ^C --- 10.1.1.1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1000ms rtt min/avg/max/mdev = 0.138/0.145/0.152/0.007 ms
  • 可以ping通

原理

在 Docker 的 none 网络模式下,容器没有任何网络连接,除了本地的回环接口(lo)。要使这些容器进行通信,你需要创建虚拟网络接口(veth),并将这些接口连接到容器的网络命名空间中。这样,两个容器可以通过虚拟网卡直接通信,而不依赖于主机的网络桥接。

虚拟以太网(veth)接口 是一对网络接口,其中一个接口在主机或一个网络命名空间中,另一个接口在另一个网络命名空间中。它们在逻辑上是相连的,因此一个接口发送的数据包会被另一个接口接收到。

  • 步骤总结:
  1. 创建 veth 对:创建一对虚拟以太网接口,其中一个接口连接到一个容器的网络命名空间,另一个接口连接到另一个容器的网络命名空间。
  2. 分配 IP 地址:为每个 veth 接口分配一个 IP 地址,并在容器的网络命名空间中配置这些接口。
  3. 设置路由:在每个容器中配置路由,使其能够通过对端接口与另一容器通信。

image.png

容器和宿主机的关系

  1. veth 接口的一端在宿主机:每对 veth 接口中的一个接口可以位于宿主机网络命名空间中,而另一端位于容器的网络命名空间中。图中展示的 veth A 和 veth B 是在各自的网络命名空间中,但它们实际是通过宿主机连接的。

  2. 宿主机管理网络命名空间:宿主机负责创建和管理这些网络命名空间,并将 veth 接口分配到对应的命名空间中。宿主机可以看到所有的 veth 接口,并决定如何配置这些接口以实现网络通信。

  3. 宿主机作为网关(可选):在某些情况下,宿主机可以充当网关,允许这些网络命名空间访问外部网络。不过,在这个 "none" 网络模式的示例中,宿主机只是作为一个基础设施存在,主要提供接口连接和命名空间管理,而不直接参与数据包的转发。

  • 宿主机的主要作用是提供和管理虚拟网络环境,确保这些命名空间中的 veth 接口能够互通。在这个设计中,容器之间的通信并不依赖宿主机的外部网络,而是通过宿主机内部的虚拟网络实现。
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:GYC

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!