姜继忠 分布式实验室
容器服务是一种高性能可伸缩的容器管理服务,在一组阿里云云服务器上通过Docker容器来运行或编排应用,免去了用户搭建容器集群管理服务的需求。阿里云容器服务兼容Docker Compose模板编排应用。本次分享将介绍容器服务的整体架构、Docker网络增强以及和阿里云VPC网络的结合、对分布式存储的支持、阿里云日志服务的集成。
整体架构
Dashboard:管理控制台,创建、管理应用,使用编排文件部署等。
Aliyun容器Hub:创建管理镜像、自动构建、Mirror服务,包含一个 Registry。
Cluster Provisioning:ECS机器管理,集群创建、缩容、扩容等操作都在Cluster Provisioning里完成。
Cluster Mgmt:最核心的部分,兼容Swarm API,部署应用之类的操作除了可以在控制台上完成,也可以在本地使用Docker命令或者 Docker-Compose直连Cluster Mgmt完成。
OSS、SLB、Logging等:容器服务集成的更基础的其他阿里云服务,供自动负载均衡、 日志管理、监控等功能。
右边的两个Cluster:用户集群。里面是用户自己购买的ECS机器,用户之间不存在机器共享。
物理机VS IaaS
容器服务是基于阿里云ECS的。很多人会觉得既然已经使用Docker了,就应该直接使用物理机,这样可以更有效的利用资源,避免虚拟机层引入的开销。
实际上,即使在企业场景里,先使用OpenStack构建IaaS,在IaaS的基础上构建容器服务也是个很不错的做法。IaaS可以把容器服务不用的资源给其他业务使用,不会浪费。虚拟机的运维也比物理机要方便,另外虚拟机可以实现热迁移,保证业务连续性。总的来说,如果不是极度苛求资源利用率,推荐在IaaS上构建容器服务。
单租户和多租户
为什么采用单租户的模式?使用容器隔离的安全性还不够,虽然Linux Kernel和Docker在这方面都做了很大的努力,但是安全方面的隔离还是不够成熟,用在生产环境的风险很大。有些操作必须在宿主机上完成,典型场景就是对内核的要求。
扩展即容器
我们所有的扩展服务都是以容器的形式存在的。之所以这样设计,原因有以下几个方面:
资源管理。扩展服务在容器内部,可以配置能使用的资源配额,避免影响系统上用户应用。
充分利用现有的基础设施。可以按照普通应用的方式部署和更新。举个例子,扩展服务的Compose里使用aliyun.global标签,添加新机器后自动部署到新机器上,很大程度上简化了扩展服务的实现和运维复杂度
关于网络
几乎所有的Docker用户都会遇到容器内应用互访的问题。对于一些简单的场景,Docker能很好的满足,经典的场景是Web+DB,每个应用只有一个容器,并且运行在同一台宿主机上,通过Docker的link可以解决。当Web和DB运行在不同宿主机上的时候,link就没法用了,因为link只能在单台宿主机上的容器之间做。过去对这种场景,只能在启动DB容器的时候做端口映射,Web通过宿主机的IP+Port访问DB。
再考虑一个微服务的场景。
这里有两个运行在不同宿主机上的Service和一个服务注册中心。Service B 依赖Service A。A注册到注册中心的时候,上报自己的IP是 192.168.0.1,B会用192.168.0.1这个IP访问A,由于路由器不认识 192.168.0.1这个节点,B发出去的包会被路由设备丢掉,也就是B没法访问A。
熟悉网络的同学应该看出来这里可以使用VXLAN解决。Docker 1.9推出了 Overlay Netowrk,底层使用的就是VXLAN,通过创建一个Overlay网络,实现跨宿主机的容器之间通信。这里就不细说了,具体的使用方式可以参考Docker的文档。
Overlay网络的最大问题是性能很不理想。我们做了Overlay网络和非Overlay网络在各种数据包大小情况下的性能对比,tcp payload 20 bytes,Overlay性能大约 75%,tcp payload 1kbytes,Overlay性能80%,对于大块数据传输,Overlay性能大约88%,这个数字可以认为是 Overlay性能的极限了。当然,不同的场景下具体测试数字不一定完全一致,但Overlay的开销还是很大的。
在阿里云容器服务里,我们开发了针对阿里云VPC环境的Docker Network Plugin,直接使用VPC的VSwitch和VRouter,由于没有封包开销,性能几乎和原生VPC网络一致。下图是VPC+Docker的网络结构。
关于存储
一般建议应用不要在本地生成非临时数据,原因有两个,首先,集群环境里,数据无法应用各个节点之间共享。其次,如果机器如果挂了,数据就丢失了。大家都熟悉的Wordpress是一个典型的反例,Wordpress安装之后会在本地生成的config.php,上传的附件也是存在本地的。如果你在多台机器上安装Wordpress,必须要找一个共享存储,挂载到每台机器上,然后配置Wordpress的附件要保存共享存储上。
回到Docker的场景,如果用Docker部署Wordpress,首先要考虑的是把附件放在容器外面,否则Docker容器删除的时候,会把所有的附件也删掉。通过Docker Volume,把Host上目录挂载到容器内部,可以实现持久存储。这跟前面说的单机Wordpress是一样的,同样存在:1. 容器迁移,数据无法迁移;2. 多个Docker容器之间不能共享。当然还是可以通过共享存储解决:在Host上挂载共享存储,再通过Docker Volume挂载到容器内部。
对于容器服务这样的平台来说,这个问题会更复杂。
容器依赖的存储类型多种多样,NFS OSSFS云盘等,对用户提供供统一的使用接口。
结合容器调度。容器运行前在Host上执行实际的存储挂载动作。
为了解决这个问题我们抽象了数据卷这个概念:数据卷是可挂载的外部存储,可以通过控制台创建数据卷。然后就可以在创建容器的时候通过标准的Volume命令挂载。
volumes: - o1:/aaa
底层实现上,用了Docker 1.9增加的Volume Plugin功能,我们开发了自己的Volume Plugin,支持ossfs、nfs、云盘和NAS。
前面说过,所有的扩展服务都是以容器的方式运行的,包括这个Volume Plugin,这里遇到了一个问题,因为Volume Plugin要在使用Plugin的容器启动前启动,Docker本身在Restart之后重启容器时并没有顺序问题,可能出现依赖了Volume Plugin的容器先启动了,Volume Plugin本身还没启动的情况。为了解决这个问题,我们对Docker做了定制,可以声明容器的启动顺序。