虚拟网卡与docker

虚拟网卡的原理

qemu-kvm技术:能让你在一台巨大的物理机里,掏出一台台小的机器。

首先,虚拟机要有一张网卡,通过linux上的tun/tap技术实现的。虚拟机是物理机上跑着的一个软件,这个软件可以像其他应用打开文件一样,打开一个tun/tap的字符谁被文件,之后,就会在物理机上看到一张虚拟的tap网卡。虚拟机里的应用会把所有的网络包都往里面发。

网络包到虚拟软件这里,将网络包转换为文件流,写入字符设备,就像写一个文件一样。内核中tun/tap字符设备驱动会收到这个写入的文件流,交给虚拟网卡驱动,再次转成网络包,交给tcp/ip协议栈,从虚拟tap网卡发送出来,成为标准的网络包。

虚拟网卡连接到云

云计算网络中的注意点:

  1. 共享,虚拟机有多个网卡,但是物理机可能只有有限的网卡,那么多个虚拟网卡如何共享同一个出口。
  2. 隔离:安全隔离和流量隔离,安全隔离,两个虚拟机属于两个用户,怎么保证数据不被窃听。流量隔离,一个疯狂下载会不会导致另外一个上不了网。
  3. 互通:同一台机器上的两个虚拟机,如何通信。
  4. 灵活:会经常创建,删除。从一个机器,漂移到另一个机器。
  • 共享与互通:

    在物理机上,有一个虚拟的交换机,linux可以创建虚拟网桥,创建出来以后,两个虚拟机的虚拟网卡,都连接到虚拟网桥上,这样两个虚拟机配置相同的子网网段就可以互相通信了。

如果要访问外部,有两种方式

  1. 桥接

    在你的物理机上,会发现多了几个网卡,其实是虚拟交换机,这个交换机将虚拟机连接在一起,在桥接模式下,物理网卡也连接到虚拟交换机上。登陆虚拟机看ip地址会发现,虚拟机的地址和物理机的,以及周边同事的是一个网段,是因为,相当于将物理机和虚拟机放在同一个网桥上,相当于这个网桥有三台机器,是一个网段的。如下图

  2. NAT模式

    在这种模式下,登陆到虚拟机里查看ip地址,发现虚拟机的网络时虚拟机的,物理机的网络是物理机的,两个不同,虚拟机要访问物理机的时候,需要将地址NAT成为物理机的地址。

    另外,它还会在你的实体机里内置一个DHCP服务器,为笔记本电脑上的虚拟机动态分配ip地址。为什么桥接方式不需要呢,因为桥接将网络打平了,虚拟机的ip是由物理网络的DHCP服务器分配。

  • 隔离

    brctl创建的网桥支持VLAN功能,设置两个虚拟的tag,这样在这个虚拟网桥上,两个机器是不互通的,如果想要互通,有一个命令vconfig,基于物理网卡创建带VLAN的虚拟网卡,从这个虚拟网卡出去的包,都带这个VLAN。

首先每个用户分配不同的VLAN,不同的用户使用不同的虚拟网桥,带VLAN的虚拟网卡也连接到虚拟网桥上。网桥不通,不能相互通信,也不会转发到另一个网桥上,另外,出了物理机,也是带vlan id的,只要物理交换机支持vlan,就可以转发给相同vlan的网卡和网桥,所以跨物理机,不同的vlan也不会相互通信。

VLANid只有4096个,在大规模平台中明显不够用,另外流量的隔离还没有实现,有大量改进的空间。

容器网络

  • 封闭环境的两种技术

    1. 看起来隔离的技术,成为namespace,也即每个namespace 中的应用看到的是不同的 IP 地址、用户空间、程号等。
    2. 用起来是隔离的技术,称为cgroup,也即明明整台机器有很多的 CPU、内存,而一个应用只能用其中的一部分。
  • 命名空间 namespace

    linux下,很多资源是全局的,比如进程有全局的进程id,但是,当一台 Linux 上跑多个进程的时候,如果我们觉得使用不同的路由策略,这些 进程可能会冲突,那就需要将这个进程放在一个独立的 namespace 里面,这样就可以独立配置 网络了。 网络的 namespace 由 ip netns 命令操作。它可以创建、删除、查询 namespace。

  • 机制网络 cgroup

    cgroup全称 control groups,是linux内核提供的一种可以限制,隔离进程使用的机制。他有如下子系统:

    • CPU子系统使用调度进程为进程控制CPU的访问
    • cpuset,如果是多核心cpu,子系统会为进程分配单独的cpu和内存
    • memory子系统,设置进程的内存限制以及产生内存资源报告
    • blkio,设置限制每个块设备的输入输出控制
    • net_cls,这个子系统使用等级识别符标记网络数据包,可允许linux流量控制程序tc识别从具体cgroup中生成的数据包。

容器网络中如何融入物理网络

docker run的机构:

容器里面有张网卡,容器外有张网卡,容器外的网卡练到docker0网桥,通过这个网桥,容器直接实现相互访问。在linux下可以创建一对veth pair网卡,一边发送包,另一边就能收到。

一边可以达到docker0网桥上,另一端如何放到容器里呢。一个容器启动会对应一个namespace,先找到namespace,pid就是namespace的名字,然后就可以将另一端veth2赛道namespace里面。这样就使一台容器内不得互相访问没有问题了,那么如何访问外网?docker默认使用NAT模式,如果内部访问外部就要通过SNAT。

  1. 所有从容器内部发出来的包,都要做地址伪装,将源ip地址,转换为物理网卡的ip地址,如果有多个容器,所有的容器共享一个外网的ip地址。

  2. 当服务器返回结果的时候,到达物理机,取出原来的私网ip,通过DNAT将地址转还为私网ip,通过网桥docker0实现对内的访问。

  3. 如果在容器内部属于一个服务,例如部署一个网站,提供给外部进行访问,需要通过 Docker 的端口映射技术,将容器内部的端口映射到物理机上来。

    例如容器内部监听 80 端口,可以通 Docker run 命令中的参数 -p 10080:80,将物理机上的10080 端口和容器的 80 端口映射起来, 当外部的客户端访问这个网站的时候,通过访问物理机的 10080 端口,就能访问到容器内的 80 端口了。

docker有两种方式,一种是通过一个进程docker-proxy的方式,监听10080,转换为80端口,另一种是通过DNAT方式,将端口10080的DNAT成为容器的私有网络,这样就可以实现容器和物理网络之间的互通了。

posted @ 2019-08-06 18:14  Jimmyhe  阅读(3269)  评论(0编辑  收藏  举报