docker核心技术-容器网络
其实严格意义上讲网络这部分不属于docker的核心技术,因为容器也是使用已有的网络模型和技术,只是在容器层面做了适配,底层并没有本质变化,这里只是为了方便记录和自己学习了解docker网络的相关内容。
网络
在了解docker的网络之前,我们先看下虚拟机是怎么来实现虚拟机网络的。对于VMWare而言分别有桥接模式,NAT模式,Host-only模式。 对于KVM来说分别有桥接模式,NAT模式,路由模式,隔离模式。这里就不讨论openstack的网络模式了,因为我也还不是特别懂(大致知道是虚拟化,原理什么的就不清楚了)。
- 桥接模式: 桥接模式可以理解为宿主机和虚拟机之前通过网桥来链接,那么在这种模式下虚拟机和宿主机网络是可以互通的,这时候对于外部而言就感
觉宿主机和虚拟机在同一个子网里面。 - NAT模式: NAT(Network Address Translatation 网络地址转换)顾名思义就是网络地址进行了转换,那么这种模式的一个工作原理是,通过虚拟化技术在宿主机和虚拟机之间形成一个叫做NAT的虚拟设备,用来连接宿主姐和虚拟机。这时候外部的网络数据进入虚拟机,先通过宿主机接受,然后宿主姐交给NAT,NAT自己通过
识别讲数据包给到对应的虚拟机;虚拟机返回数据到外部,虚拟机先将数据包交给NAT,然后NAT自己添加标记并且以宿主机的名义发出去。因此在NAT的模式下,虚拟机通过NAT可以知道外部的网络,但是对于外部网络而言并不知道有虚拟机的存在,外部网络都认为请求来自于宿主机。 - Host-only模式: 可以理解为去掉NAT的NAT模式,那么这种情况下就无法和外部网络通信了,只能和宿主机通信。
但是在同一个宿主机上的多个虚拟机如果都是同一个Host-only模式,那么这些虚拟机是可以访问的;如果处于不同的Host-only模式那么虚拟机也无法访问,但是可以和宿主机进行通信。 - 隔离模式:
理解起来和VMware的Host-only模式类似,也是处于同一个隔离下的虚拟机可以通信,如果多个虚拟机分别在不同宿主机进行隔离,那么这些虚拟机也是无法互相访问的。但是都以和虚拟机本身所在的宿主机进行通信。 - 路由模式: 相比于NAT模式,在路由模式下宿主机和虚拟机之前的NAT换成了虚拟路由器,网络通过虚拟路由器来进行转发,这种模式下因为不存在网络地址转换,对于外部网路可以知道虚拟机的ip。 注:这里主要讲述几种模式的差异,用来方便理解几种网络模式的区别,即使都叫做桥接模式和NAT模式在VMware和KVM中的具体实现还是有差异的这里不做过多描述,这里主要是让我们了解到几种模式下的网络区别。关于具体细节可以[参考链接] (www.cnblogs.com/kevingrace/…)
docker网络类型
在了解了虚拟 机的网络模式后,那么我们在看看docker的网络是怎么进行处理的。在docker中我们可以设置的网络模式有:桥接模式,Host模式,Container模式,None模式,自定义
桥接模式
桥接模式是docker默认模式也是最常见的,具体实现是通过在宿主机上创建一个docker0的网桥,容器可以借助docker0网桥和宿主机/外部网络之间进行通信。
网络模型图
当Docker server启动的时候,会在主机上创建一个docker0的虚拟网桥,一般docker会选择和宿主机不同的ip地址和子网分配给docker0,然后连接到docker0的容器会从这个子网中选择一个未占用的ip使用,在这时候虽然
容器内部已经有了ip可以通过docker0来访问到外部网络,但是外部网络是无法知道容器的存在的,如果需要外部网络可以访问到容器,docker提供了端口绑定的方式可以将容器端口绑定到宿主机上(通过iptables NAT将宿主机端口流量转发到容器的端口),这也就是为什么我们在本地运行一个容器之后,如果没有指定端口绑定规则,即使容器启动成功那么我们也是无法访问的原因。
#根据镜像13227829078/Mysql:5.7.1启动容器local-mysql,并且将容器3306端口和本地3306端口进行绑定
docker run -it -d --name local-mysql -p 127.0.0.1:3306:3306 13227829078/Mysql:5.7.1
Docker启动的时候会做以下操作:
- 如果docker0不存在则创建
- 搜索一个与当前路由不冲突的ip段
- 在确定的范围中选择 ip
- 绑定ip到 docker0 然后在容器运行时,每个容器会配置相同的docker0 ip相同网段的ip地址,docker 0的ip会作为容器的默认网关。
注:docker的bridge模式和VMware的bridge模式虽然都叫做桥接模式,我们可以按照VMware的桥接模式的方式来理解docker的桥接模式,但是docker的桥接模式和VMware的桥接模式是不一样的。VMware的bridge模式下外部网络能感知到虚拟机,但是docker的bridge模式下外部网络是不感知容器的,外部网络到达宿主机然后宿主机根据端口绑定策略将流量转发到容器内部
Host模式
有些类似于VMware的桥接模式,此时容器与宿主机在同一个网络中,使用读主机的ip,容器自己没有独立的ip,并且这时候对于外部网络而言感觉容器就和宿主机是一体的。这种模式下容器内部服务端口也可以使用宿主机的端口不需要额外的制定端口绑定。这个是优点也是缺点,因为容器内部不会拥有所用端口,因为端口有可能会被其他容器或者服务占用。这种模式下容器直接使用宿主机的Network Namespace,不会拥有自己独立的Network Namespace但是容器的其他资源例如文件系统,进程列表等其他资源还是和宿主机隔离的。
网络模型图
#通过--network=host指定容器按照host模式启动
docker run -d --network host --name gogin-hostnetwork 13227829078/go-gin:v1.0
Container模式
与host模式类似host模式将容器使用host的Network namespace,container模式下将容器和其他容器共用一个Network namespace,其他例如文件系统和进程相关的还是互相隔离的。
网络模型图
None模式
为各个容器创建独立Network namespace,并且不为容器做任何网络配置,这时候就需要研发/运维自己给容器指定网卡和配置IP,这种方式有好有坏虽然需要进行额外的网络配置,但是这也可以让用户按照自己需要来选择所需的配置。
自定义
docker1.9之后新增特性,允许开发人员使用docker支持的第三方网络驱动来定制容器网络。docker 1.9以上的版本默认自带了bridge和overlay两种类型的自定义网络driver。
自定义bridge网络
docker network create -d bridge docker_b2
docker run -d --name gogin-b2 --network docker_b2 13227829078/go-gin:v1.0
查看自定义网桥和使用自定义网桥创建的容器
也可在创建网桥的时候指定子网和网关
docker network create --driver bridge --subnet 172.19.0.0/16 --gateway 172.19.0.1 mybridge_net
docker跨主机通信
上面提到了docker的网络类型和不同类型下是否可以和宿主机进行通信,在正常的工作中我们使用到docker不会是在单台主机上面跑所有容器,那么我们接下来看看当跨主机的时候容器有哪些方式可以通信。
- host模式: 得益于容器使用host的网络,host模式天生就支持跨主机通信。
- 端口绑定: 通过将容器端口和宿主机端口进行绑定,对于外部网络/容器来说可以使用宿主机ip+端口的方式来使用容器提供的服务,也可以做到跨主机通信。
- docker外定制容器网络: 在容器创建完成后,通过修改容器网络命名空间来定义容器网络(使用none模式创建容器,然后配合pipework来重新配置网络),一般情况也用不到这种。
- 自定义网络: 通过使用第三方SDN(Software Defined Network)工具,为容器构建可以跨主机的网络环境(一般操作起来比较复杂,也不常用)。
- overlay网络实现 docker1.9提出的overlay网络,原生支持容器跨主机通信。
- 基于隧道的overlay网络: Flannel
- 基于包封装的overlay网络: Weave,Flannel(早期版本)
- 基于三层实现SDN网络: Calico