1、容器内部通信

Docker容器和服务如此强大的原因之一是在通过网络可以将它们连接在一起,或者将它们连接到非Docker工作负载。Docker容器和服务甚至不需要知道它们部署在Docker上,或者它们的对等体是否也是Docker工作负载。

Docker的网络子系统是可插拔的,使用驱动程序。默认情况下存在多个驱动程序,并提供核心网络功能:

bridge:默认网络驱动程序。当你的应用程序在需要通信的独立容器中运行时,通常会使用桥接网络。
host:对于独立容器,删除容器和Docker主机之间的网络隔离,并直接使用主机的网络。
container:可以多个容器共用一个网络。
overlay:覆盖网络将多个Docker守护程序连接在一起,并使群集服务能够相互通信。还可以使用覆盖网络来促进群集服务和独立容器之间的通信,或者在不同Docker守护程序上的两个独立容器之间进行通信。
macvlan:Macvlan网络允许您为容器分配MAC地址,使其显示为网络上的物理设备。Docker守护程序通过其MAC地址将流量路由到容器。macvlan 在处理期望直接连接到物理网络的传统应用程序时,使用驱动程序有时是最佳选择,而不是通过Docker主机的网络堆叠进行路由。
none:对于此容器,禁用所有网络。
network plugins:使用Docker安装和使用第三方网络插件。这些插件可从Docker Store或第三方供应商处获得。

bridge网络

如图,默认docker主机会存在三种类型的网络。

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第1张图片

如图,docker主机会有一个默认使用的桥接网卡bridge0,它是在运行docker容器时,如果不指定网络,默认使用的网络。

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第2张图片

当运行一个容器时,我们可以看到在docker主机上多了一个网卡,而且master指向docker0

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第3张图片

这时候我们在查看该容器的网络信息(ip地址和网关)。发现它的ip地址和docker0一个网段,网关则是docker0的地址

image.png

bridge网络的特点

使用一个 linux bridge,默认为 docker0
使用veth 对,一头在容器的网络 namespace中,一头在docker0上
该模式下Docker Container不具有一个公有IP,因为宿主机的IP地址与veth pair的IP地址不在同一个网段内
Docker采用NAT方式,将容器内部的服务监听的端口与宿主机的某一个端口进行“绑定”,使得宿主机以外的世界可以主动将网络报文发送至容器内部
外界访问容器内的服务时,需要访问宿主机的 IP 以及宿主机的端口 port
NAT 模式由于是在三层网络上的实现手段,故肯定会影响网络的传输效率。
容器拥有独立、隔离的网络栈;让容器和宿主机以外的世界通过NAT建立通信

我们查看iptables的nat表,可以看到,在POSTROUTING链上做了一个MASQUERADE,源是172.17.0.0/16,目标是所有网段。这样的转换后,容器就可以通过SNAT访问到外网实现通信了。

image.png

host网络

Host模式并没有为容器创建一个隔离的网络环境。该模式下的Docker容器会和host宿主机共享同一个网络namespace,所以容器可以和宿 主机一样,使用宿主机的eth0,实现和外界的通信。

特点:

这种模式下的容器没有隔离的network namespace
容器的IP地址同 Docker主机的IP地址
需要注意容器中服务的端口号不能与Docker主机上已经使用的端口号相冲突
host模式能够和其它模式共存

首先我通过ss查看一下,我的docker主机80端口并没有使用。当我启动一个提供nginx应用的容器时,在查看发现我的主机使用了80端口。

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第4张图片

我们还可以通过docker inspect nginx001查看它的网络信息。发现IP地址和网关处根本没有值。因为使用了host网络,它是共用了docker主机的网络。

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第5张图片

None模式

网络模式为 none,即不为Docker容器构造任何网络环境,不会为容器创建网络接口,一旦Docker容器采用了none网络模式,那么容器内部就只能使用loop back网络设备,不会再有其他的网络资源。

Container共享模式

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

首先我运行一个容器,执行ip a查看到ip地址为172.17.0.2。

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第6张图片

再运行一个容器,指定network类型为container,共享centos01的网络。

image.png

连接centos02,查看ip地址。发现centos02和centos01的地址是一样的。

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第7张图片

2、外部网络访问容器内应用

-P随机指定一个docker主机端口给容器中的端口做映射

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第8张图片

-p将docker主机的一个端口映射容器的一个端口

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第9张图片

访问网站测试(我的docker主机的地址为192.168.44.131,记住要在docker主机上放行32768和8000端口)

首先访问32768端口

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第10张图片

访问8000端口。(都可以正常提供服务)

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第11张图片

3、用户自定义网络

通过docker network create --driver network_type network_name命令即可创建自定义网络。其中--driver后面支持的类型有三种:bridge、macvlan、overlay。

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第12张图片

通过docker network inspect network_name可以查看该网络的信息

[root@docker001 ~]# docker network inspect my_bridge 
[
    {
        "Name": "my_bridge",
        "Id": "897ea2a24517f23144b0deab471ceefc6ee910840d2631d9429305036de075c6",
        "Created": "2018-08-19T15:16:25.49887066+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

而且通过ip addr可以看到自动在docker主机上创建了一个网卡。

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第13张图片

再次查看我们nat表,也可以看到在POSTROUTING上做的MASQUERADE

image.png

这样我们就可以运行容器使用该网络了。

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第14张图片

4、docker network管理命令的使用

分别如下。

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第15张图片

显示一个网络的信息(只截取了一部分)

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第16张图片

5、跨主机docker容器通信方案介绍

基于实现方式的分类

隧道方案(Overlay Networking):
Weave:UDP广播,本机建立新的BR,通过PCAP互通。
Open vSwitch(OVS):基于VxLAN和GRE协议,但是性能方面损失比较严重。
Flannel:UDP广播,VxLan。
路由方案:
Calico:基于BGP协议的路由方案,支持很细致的ACL控制,对混合云亲和度比较
高。
Macvlan:从逻辑和Kernel层来看隔离性和性能最优的方案,基于二层隔离,所以
需要二层路由器支持,大多数云服务商不支持,所以混合云上比较难以实现。

基于网络模型分类

Docker Libnetwork Container Network Model(CNM):
Docker Swarm overlay
Macvlan & IP network drivers
Calico
Contiv(from Cisco)
##Docker Libnetwork的优势就是原生,而且和Docker容器生命周期结合紧密;缺点也可以理解为是原生,被Docker“绑架”。
Container Network Interface(CNI):
Kubernetes
Weave
Macvlan
Flannel
Calico
Contiv
Mesos CNI
##CNI的优势是兼容其他容器技术(e.g. rkt)及上层编排系统(Kuberneres & Mesos),而且社区活
跃势头迅猛,Kubernetes加上CoreOS主推;缺点是非Docker原生。

详解:

Flannel方案为例

Flannel之前的名字是Rudder,它是由CoreOS团队针对Kubernetes设计的一个重载网络工具,它的主要思路是:预先留出一个网段,每个主机使用其中一部分,然后每个容器被分配不同的ip;让所有的容器认为大家在同一个直连的网络,底层通过UDP/VxLAN等进行报文的封装和转发

下面这张是Flannel网络的经典架构图(从网上找的)

Docker网络管理(bridge、docker自定义网络以及Flannel方案)-笔记4_第17张图片

1. 容器直接使用目标容器的ip访问,默认通过容器内部的eth0发送出去。 
2. 报文通过veth pair被发送到vethXXX。 
3. vethXXX是直接连接到虚拟交换机docker0的,报文通过虚拟bridge docker0发送出去。 
4. 查找路由表,外部容器ip的报文都会转发到flannel0虚拟网卡,这是一个P2P的虚拟网卡,然后报文就被转发到监听在另一端的flanneld。 
5. flanneld通过etcd维护了各个节点之间的路由表,把原来的报文UDP封装一层,通过配置的iface发送出去。 
6. 报文通过主机之间的网络找到目标主机。 
7. 报文继续往上,到传输层,交给监听在8285端口的flanneld程序处理。 
8. 数据被解包,然后发送给flannel0虚拟网卡。 
9. 查找路由表,发现对应容器的报文要交给docker0。 
10. docker0找到连到自己的容器,把报文发送过去。