设计可伸缩、可移植的Docker容器网络

Docker 容器包装一系列运行程序到一个完整的文件系统中,包含代码、runtime运行时、系统工具、系统库等,这保证了程序能够运行在相同且独立的环境。通常情况下,容器将程序与底层架构隔离,提供了相对统一的一层封装。

如何让运行在容器中的程序相互之间通信,如何与宿主机Host通信,如何与外部网络通信呢?
如何设计一个适合程序迁移、提供服务发现、负载均衡、安全、高效、扩展性良好的网络呢?

容器和微服务下的网络挑战

微服务的流行使得应用的扩展性对于连接的透明程度有着更高的要求了。容器网络的设计哲学是应用程序驱动的,它目标能向运维提供一个自由且能高度定制化的网络抽象,也能使得对开发者保持透明

正向其他设计一样,网络的设计同样是一种权衡的哲学。有如下几个问题是设计容器网络需要考虑的:

  • Portability: 移植性,如何保证我能够在不同网络环境下使用特定的网络特性
  • 服务发现:如何知道一个服务是否存活
  • 负载均衡: 我如何分享在不同服务之间分享我们的负载均衡实例
  • 安全:如何限制一个错误的容器被访问
  • 安全:如何保证一个保证一个容器的项目通知是安全的
  • 性能:如何能提供一个高级网络服务来做压缩流量和增大带宽
  • 扩展性:在跨多个主机来应用程序时,如何确保不会牺牲上述这些特性

CNM Container Networking Model

  • Sandbox:一个Sandbox包含了一个容器所有相关的网络栈设置,包括容器接口的管理、路由表设置、DNS设置。一个Sandbox可能有多个Endpoints
  • Endpoint: 一个Endpoint代表了一个Sandbox加入一个Network的口子。Endpoint代表一个可以交由容器程序连接网络的结构,它并不关心使用什么样的网络驱动来连接网络
  • Network:CNM模型没有明确指明网络具体是由什么实现的,无论是Linux Bridge还是VLAN,如果Endpoint没有连通性的话,是没法直接连接到网络上的。

网络驱动

  • Host 这种设置下,容器可以使用宿主机的网络栈,这样就没有Namespace隔离的效果,所有宿主机上能用的网络接口都可以被容器使用
  • Bridge 这种驱动会在宿主机上创建Linux Bridge。默认情况下,所有在bridge上的容器都可以相互通信,外部网络的访问需要设置成Bridge,这是默认的
  • Overlay 这种驱动会构建一个支持多宿主机的网络,它联合使用了local Linux bridge 和 vxlan来底层物理网络上实现容器间通信
  • MACVLAN 这种会直接提供IP,并且建立容器和宿主机的端口通信,设置路由表
  • None 这种会给容器提供单独的网路栈和网络Namespace,但是不会再容器上设置端口了,如果不做任何配置,container将会同主机完全独立