Docker容器虚拟化网络

docker容器虚拟化

虚拟化网络

所有东西都是虚拟的,Network Namespace(网络隔离空间) 是 Linux 内核提供的功能,是实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,它们有独自网络栈信息。不管是虚拟机还是容器,运行的时候仿佛自己都在独立的网络中。而且不同Network Namespace的资源相互不可见,彼此之间无法通信。

网络隔离空间是看不见摸不着的,隔离空间,互不相干,类似于第三空间
(假如我们的物理机有4块物理网卡,我们要创建4个名称空间,而这些设备是可以单独关联至某个单独的名称空间使用的)

在这里插入图片描述
服务器最少有四个网卡(有线网卡),如果是一一对应的话,做过配置是没有问题的,因为一个设备是只能属于一个名称空间,但是如果外面所有拥有的名称空间超过了物理网卡的数量的话,就需要使用虚拟网卡设备,用纯软件的方式来模拟一组设备来使用(虚拟交换机是没有端口限制)

linux内核级支持两种级别设备的模拟:

	一种是二层设备(交换机)
	一种是三层设备(路由器)

Linux内核模拟的二层设备,每个网络接口设备是成对出现的,可以模拟为一根网线的两端,其中一端模拟主机的虚拟网卡,另一端模拟虚拟交换机,就相当于让一个主机连到一个交换机上去。Linux内核原生支持二层虚拟网桥设备,即用软件虚拟交换机的功能。
如下图所示:
在这里插入图片描述
那么此时如果再有一个名称空间,它有创建了一对虚拟网卡,一端连接名称空间,一端连接虚拟交换机,此时就相当于两个名称空间连接到了同一个交换机网络中,此时如果两个名称空间的网卡地址配置在同一网段,那么很显然他们之间是可以互相通信的。
如下图所示:
在这里插入图片描述
从网络通信的物理设备到网卡都是用纯软件的方式来实现,这种实现方式就叫做虚拟化网络

网卡是成对的,真机一端,容器一端,不懂的话,看下实例
实例:

在一个终端上面随便创建一个容器进去,我这里有一个容器,直接进去
[root@localhost ~]# docker run -it 0e2d8ebad242 /bin/sh
sh-4.4# 
进去后终端不要关,直接重新开个终端,查看端口
[root@localhost ~]# ip a

5: vethcb306bd@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether ea:36:19:5d:29:01 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::e836:19ff:fe5d:2901/64 scope link 
       valid_lft forever preferred_lft forever

看上面有一个vethcb306bd@if4,看最后的四位,@if4,再回到前面的终端查看IP
sh-4.4# ip a

4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

看最后四位和上面的四位进行对比,@if4和@if5,这就是端口成对的意思,若容器停止的话主机上面成对的IP也会没有
单节点容器间通信

如果在同一个物理机上的两个容器想通信,我们的办法就是在这台主机上建立一个虚拟交换机,而后让两个容器各自用纯软件的方式创建一对虚拟网卡,一半在容器上,一半在虚拟交换机上,从而实现通信。(纯傻瓜式的交换机,比较方便)
如下图所示:
在这里插入图片描述
这就是单节点上两个容器间的通信方式。单节点上两个容器之间的通信也有一些复杂情况,比如我们期望构建的容器要跨交换机通信呢?

在这里插入图片描述
如果要C1和C3通信又该如何实现呢?

  • 我们可以通过名称空间创建一对网卡,一端连SW1,另一端连SW2,这样一来两个交换机就连起来了

如果C1和C3在不同网络呢?

  • 我们可以通过路由转发使其通信,也就是我们得在两台交换机之间加一个路由器

此时我们可以再启动一个容器,这个容器里面就跑一个内核,并将其转发功能打开,这样一来就模拟了一台路由器,通过这台路由器来实现路由转发

如图:
在这里插入图片描述

不同节点容器间通信

在这里插入图片描述
如图所示

如果C1要与C5进行通信又该如何实现呢?

  • 我们可以通过路由转发使其通信,也就是我们得在两台交换机之间加一个路由器
  • 设想一下,如果使用桥接的方式进行使用的话,这样的话很容易产生广播风暴(就是c1和c5是在同一个网段,就是通过二层通信也就是mac地址,双方都在通信,造成两边都传递不到),所以行不通
  • 也可以使用NAT技术,c5映射一个80端口号到宿主机2上面去,c1也映射一个80到宿主机1上面去,通过DNAT进行实现 宿主机2需要做一个DNAT,宿主机1要做一个SNAT和DNAT(因为是来回,需要做两边)效率比较低
  • 一种叫做Overlay Network(叠加网络)的技术来实现不同节点间容器的相互通信功能,如图所示:
    在这里插入图片描述
    Overlay Network:会将报文进行隧道转发,也就是在报文发出去之前要为其添加一个IP首部,也就是上图的1.1和1.2这部分,这里的1.1是源,1.2是目标,当宿主机2收到报文后解封装发现要找的目标容器是C2,于是把包转发给C2

docker容器网络

Docker在安装后自动提供3种网络,可以使用docker network ls命令查看

[root@node01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
61dc50d0e565        bridge              bridge              local
2ee170d7c92b        host                host                local
a7cb765aa03b        none                null                local

Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

Docker支持的四种网络模式:
网络模式配置说明
bridge- -network bridge默认模式(网桥模式,桥接到docker0上面去的)
container- -network container:NAME_OR_ID
(NAME_OR_ID:就是后面跟上docker的ID)
容器和另外一个容器共享Network namespace
host- -network host容器和宿主机共享Network namespace
none- -network none容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等(就是没有网络的)

在这里插入图片描述

第一个是none模式,是因为他的箭头是指向自己,没有配置网卡,网关,只有默认的lo网卡

第二个是bridge模式,是因为A上面有配置的网卡(Private interface),通过容器虚拟接口(Containervirtual interface)进行共享的

第三个是container模式,是因为A上面有配置网卡(Private interface),B上面没有,所以是共享Network namespace

第四个是host模式,是因为直接与真机进行共享

bridge模式

当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
在这里插入图片描述

  1. 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。
  2. 在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名
  3. 将这个网络设备加入到docker0网桥中
  4. 通过brctl show命令查看
[root@localhost ~]#  docker run -dit -p 80 --name contos1 httpd
Unable to find image 'httpd:latest' locally
latest: Pulling from library/httpd
e5ae68f74026: Pull complete 
bc36ee1127ec: Pull complete 
d3576f2b6317: Pull complete 
f1aa5f54b226: Pull complete 
aa379c0cedc2: Pull complete 
Digest: sha256:fba8a9f4290180ceee5c74638bb85ff21fd15961e6fdfa4def48e18820512bb1
Status: Downloaded newer image for httpd:latest
e3d79a59f8f7900f27b88ebb3c48b770c3485747812ad5ce24da162564ab2d55

[root@localhost ~]# iptables -t nat -vnL |tail -1
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:49153 to:172.17.0.5:80
[root@localhost ~]# ss -anlt | grep 49153
LISTEN 0      128          0.0.0.0:49153      0.0.0.0:*          
LISTEN 0      128             [::]:49153         [::]:*          

注意:bridge模式是docker的默认网络模式,不写–network参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看

假设上图的docker2中运行了一个nginx,想一下下面几个问题:

问题一:同主机间两个容器间是否可以直接通信?比如在docker1上能不能直接访问到docker2的nginx站点?

  • 可以通信,因为是在同一个网关上面

问题二:在宿主机上能否直接访问到docker2的nginx站点?

  • 可以,做个端口映射就好了

问题三:在另一台主机上如何访问node1上的这个nginx站点呢?DNAT发布?

  • 可以但是需要使用NAT,做个端口映射端口到宿主机上面去,即docker run创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。
container模式

这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
在这里插入图片描述

[root@localhost ~]# docker run -it --name mysql busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
3aab638df1a9: Pull complete 
Digest: sha256:52817dece4cfe26f581c834d27a8e1bcc82194f914afe6d50afad5a101234ef1
Status: Downloaded newer image for 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
22: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:11:00:06 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.6/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
       
[root@localhost ~]# docker run -it --name mysql1 --network container:mysql busybox
/ # 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
22: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:11:00:06 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.6/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

host模式

如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口

使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。
在这里插入图片描述

[root@localhost ~]# docker run -it --name centos4 --rm --network host busybox
/ # 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 fq_codel qlen 1000
    link/ether 00:0c:29:cf:2d:91 brd ff:ff:ff:ff:ff:ff
    inet 192.168.230.143/24 brd 192.168.230.255 scope global dynamic noprefixroute ens33
       valid_lft 1789sec preferred_lft 1789sec
    inet6 fe80::170c:c4e8:5ea5:f2be/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue 
    link/ether 02:42:c0:32:a5:32 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
    inet6 fe80::42:c0ff:fe32:a532/64 scope link 
       valid_lft forever preferred_lft forever

从新打开一个终端进行查看
[root@localhost ~]# 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
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:cf:2d:91 brd ff:ff:ff:ff:ff:ff
    inet 192.168.230.143/24 brd 192.168.230.255 scope global dynamic noprefixroute ens33
       valid_lft 1680sec preferred_lft 1680sec
    inet6 fe80::170c:c4e8:5ea5:f2be/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:c0:32:a5:32 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
    inet6 fe80::42:c0ff:fe32:a532/64 scope link 
       valid_lft forever preferred_lft forever

none模式

container:是一个别人进不来,自己也出不去,只有lo回环网络,没有其他网卡。

none模式可以在容器创建时通过–network none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性

应用场景:

  • 启动一个容器处理数据,比如转换数据格式
  • 一些后台的计算和处理任务
    在这里插入图片描述
[root@localhost ~]# docker run -it --net=none busybox
/ # 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

可以使用 docker network inspect bridge 查看bridge网络的详细配置

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值