王振威: 我之前在开源中国工作过一段时间,后来机缘巧合就加入了Coding。Coding是初创,我有幸作为创始团队成员之一,我们几个创始人做了一些比较基础的研发工作,今年就转职做运维和基础架构改进开发。从去年年底到现在我一直在做我们的运维平台的容器技术,也就是Docker的架构引进,以及做一些开发工具相关的工作。
王振威: 我们之所以选择Docker作为我们下一步的架构的计划,主要是因为我们之前遇到了一些问题,我们系统比较复杂,牵扯到各种各样的编程语言和框架,这些框架和编程语言做出来的软件、服务程序,交给运维去处理的时候非常痛苦,因为运维不清楚软件具体需要什么样的环境。有了Docker以后,它把整个软件、环境都打包成一个整体。作为运维来讲,对于任何一个程序我们都认为它是一个基础的容器,我们只需要给它分配相应的资源它就可以运行。首先容器在概念上跟我们遇到的问题是比较吻合的,所以我们选择了这样一个解决方案。Docker也是容器里面目前最成功的,所以我们选择了Docker。Docker本身有一个口号,叫做build,ship and run,我们也是基于这个出发点将我们的架构一步一步演化的。
4. 你对Docker的理解其实还是基于它的Slogan?
王振威: 对,我认为docker的核心就是build,ship and run,它的其他高级的功能我们之前也尝试了,最后都放弃了,应用的最终结果就认为,它最核心也最属于中间力量的功能就是这个build,ship and run
王振威: OK,我们现在用Docker是采用了自己写了一套简易的编排软件,比较像Docker官方的compose工具。用的Docker也就是一些比较基础的功能,比如打包,用它的网络也是用host模式,我们没有用它提供的日志功能用的自己文件系统mount进去,也就是说我们并没有使用Docker比较高级的功能,只使用它比较基础、比较可靠的功能作为我们的服务支撑。我们在Coding的架构演化主要遵循的理念就是平滑演进,能从传统架构慢慢变到最终的Docker环境里面。我们用Docker的过程中也会遇到一些问题,两个问题,一个是在Docker的可能是1.9版本以前,具体我不太记得,有这样一个Bug,它的容器的标准输出在输出大量数据的时候,容器会挂掉,甚至Docker daemon会挂掉,内存会出现爆炸式的上涨,直到docker daemon被操作系统oom。我们找到重现方案,并给官方提供了重现方式,他们在1.9.1,也可能这个修复还没有上到最新的release里面,但是这个Bug已经被他们修复了,这是其中一个。另外我们之前有一个应用场景,用户每进来一个请求我们都要启一个新的容器的场景,我们每天都有几十万的请求的量,后台只有三、四台服务器处理这样的请求,最后导致Docker daemon内存会缓慢增长。另外它的文件系统出问题了,container在停掉的时候,会残留很多小文件,最终导致文件系统的inode结点被占满,从而导致Docker daemon无法正常工作。这是另外一个问题,后来我们还是采用了使用单个进程处理的方式解决。Docker可能在某种条件下不适合用每一个请求都起一个container这种完全理想的状态下去处理我们的业务逻辑。
王振威: 我们都是直接用文件系统mount到Docker容器里面,包括数据库也是这么干的,近期,我们上个月才完成了一次把我们主站的数据库迁移进Docker的工作,也是使用文件系统直接把数据库的文件目录mount进容器里面启动。
7. 挂载完之后如果要做数据迁移呢?你们可以直接做吗?
王振威: 如果是做热迁移,我们就使用数据库的镜像机制,直接把数据同步到另外一个slave机,再通过业务层面迁过去。如果是冷迁移也好办,就是把容器停掉,把目录通过工具再传输到另外一个服务器上去。大致就是这样。
王振威: 我们现在的组件已经进行到大概90%都是在的Docker中运行。在Docker中构建分为两部分,一个是生产环境,一个是开发环境的构建。现在开发环境正在推进一种叫Coding local的机制,就是开发环境所有的测试、调试组件都运行在Docker里面,而且编译在Docker里面。为什么编译在Docker里面?存在一个问题,我们的生产部署环境都是 Linux,但是本地的开发环境可能有Windows、mac,我们担心因为编译工具链包括编译环境不同会导致一些问题,所以强制要求开发者都把程序原码放在Docker容器中构建。很简单,把Docker原码目录mount进Docker容器。比如说golang,你把golang的原码mount进去,然后使用golang1.5 Docker基础镜像,里面已经装好了Docker相关的工具链,编译好以后把二进制文件拷贝出来,这个二进制文件就是一个在Linux上ready to run的包,再把这个包打包进Docker image,我们的构建工作就完成了。生产环境和开发环境我们的目标期待是一样的,但是现在还存在一些便利性的问题,生产环境可能不需要考虑便利性,只是要最终的安全、稳定,但是本地很多时候要考虑一些便利性的问题,所以目前两者还没有完全融合到一起,但这是我们的一个目标。
王振威: 我们之前也遇到过关于编译器的版本,比如说Java JDK7和JDK8,它们编出来的class文件是不兼容的,我们系统中也有不同的应用会用到JDK7和JDK8,我们自己会维护一个基于官方的JDK7和jdk8衍生的基础镜像,在这个基础镜像里面我们会做其他的定制,比如说时区、local的设定,让它更适合于我们的条件,开发者把程序交付给运维的时候,必须告知我们这个程序要在什么环境下编译是用maven或者gradle。我们会选择合适的image把原码打包进去进行构建。要求的是生产环境和开发环境都是一致的。
王振威: 刚才我也大致提到这一点,问题在于很多时候我们本地的电脑上可能只允许你安装一套JDK,或者你也可以装多套开发环境,比如说ruby很多版本你可以装rvm解决,JDK很多版本可以通过其他方式解决,但是如果有了Docker这些问题就天然解决了。
11.
王振威: 这跟环境变量没有什么关系,比如说我们需要JDK7编译时候,就把Docker file中的JDK1.8改成1.7就可以了,需要1.8的时候,就把1.7改成1.8。编译出来的文件是相应环境下的二进制文件。
12. 这个Docker image是同一个吗?
王振威: 不是同一个,不同的环境肯定要打包不同的。
王振威: 我们做过一些考量,比如K8S我们有在内部尝试用它,但是发现它非常不接地气,具体来讲,第一它有很多高级复杂的功能我们目前是用不到的。第二我们需要的一些功能它是没有的。另外一个问题如果我们整站或者说整体一套系统迁移到K8S我们的成本跨度非常大,这是最重要的原因。我们没有办法一步一步把我们环境演进成K8S。所以我们做的是基于现有的架构慢慢把我们现有的进程、服务搬到Docker。现在主要做的这样一个工作。
王振威: 我觉得真正深入的去使用Docker这种团队,最终不一定会选K8S的原因在于我们都是基于现有的架构去演化,并不是全新的从零开始的一套东西,如果从零开始的话,整个程序最开始设计就可能会考虑使用K8S,或者应用设计会更倾向于向它靠拢,这样的话用起来就会非常方便,它也会成倍提升开发和运维的效率。但是如果是一个既有的系统一下子跨度到K8S,迁移成本太高,而且风险太大,一般公司无法承担。
15. 大家对K8S的稳定性和与自己系统的适配是有疑虑的。
王振威: 对。
王振威: Docker的问题在于现在扩的面有点太宽了,需要更注重作为容器的基础功能的研发。比如说它现在一些比较杂乱的没有什么意义的功能,不过也可能我是从使用者角度考虑,他们从Docker公司领导者的角度考虑,可能会有不同的意见。我认为他们做的一些,比如像Docker machine、swarm,包括Docker的多种网络模式,这些跟容器本身没有太大的关系,Docker本身需要更专注于搞容器技术,他的口号喊的比较好,快速交付。另外一个容器本身就是为了解决隔离性和安全性的问题,我觉得他们需要更多的着重这方面。
王振威: 关于安全性问题,尤其对容器或者对镜像签名的工具我认为是有必要的,尤其在公有云上,比如我们下载一个软件,Docker image编译到最后它也是一个程序包,就是一个程序,这个程序不管传到哪,可能在某个过程中就被人篡改了,会出现一些问题,所以签名也是必要的,但是签名有没有必要用硬件确实是另外一个程度的考量,比如我们可以用PGP之类工具来做这个工作,因为它毕竟是一个文件,跟其他的文件没有什么区别。另外一个在私有云里面,可能需要更关注的是关于网络,包括资源的隔离性这方面的一些考量。
王振威: 现在容器也有好几家在做,包括一些业界的巨头,他们共同成立了一个组织叫open container,这可能是容器未来的发展方向,Docker也会渐渐向open container接口靠拢,以后容器可能就不再是Docker一家独大,像一些企业,比如说vmware、GOOGLE,他们内部的容器如果能接入open container的接口,那我们的选择就会更多。
20.
王振威: 大家都遵循这种公开的接口,我们不会受一家所累,因为大家的接口都统一的,比如虚拟机你用AWS的虚拟主机,某一天想迁移到ucloud或者阿里云,在底层来讲他们虚拟机的镜像都是可以共享的,所以是有这种迁移能力的,因为他们遵循了同样的接口。
InfoQ: 好,谢谢你接受我们今天的采访!