【编者按】 Shopify是一家提供电商网店解决方案的公司,目前服务的网店数有10万家以上(Tesla 也是它的用户)。网站主要的框架是Ruby on Rails,1700个内核和6TB RAM,每秒可以响应8000个用户请求。为了更易扩展和管理业务,Shopify开始使用Docker和CoreOS技术,Shopify软件工程师Graeme Johnson将撰写一系列文章分享其经验,本文是系列中的第二篇,重点介绍了Shopify在生产环境中是如何使用容器技术。 这是第一篇召集群里(230365411)的同学们一起翻译的文章,谢谢大家的义务帮助,本次参与翻译的同学包括王大隆、孙宏亮、吴京润、吴方洲、周敬滨、赵文举。我们也欢迎你的加入! 以下为翻译原文: 为什么使用容器技术?在我们深入到构建容器的机制之前,首先讨论一下这么做的动机。容器在数据中心拥有的潜能就像游戏机之于游戏。在PC游戏的初期,通常在你开始玩一款游戏之前,都需要安装视频或音频驱动。然而,游戏机提供了不同的体验,与Docker很类似:
引导程序为了努力实现容器化,你需要同时具备开发和运维技能。首先,与你的运维团队交流,你需要确信你的容器能够完全复制于你的生产环境。如果你运行在OSX(或windows)桌面操作系统,但部署在Linux上,使用一个虚拟机(比如Vagrant)作为本地测试环境。第一步,更新你的操作系统和安装支持包。挑选一个基础镜像匹配你的生产环境(我们使用Ubuntu14.01),不能出差错——你不会想处理容器化和操作系统/包在同一时间升级所带来的麻烦。
选择容器类型 在容器类型方面Docker为你提供了足够的选择空间,从一个单进程的“瘦”容器到一个让你觉得类似于传统虚拟机的“胖”容器(例如,Phusion)。 我们选择去遵循“廋”容器方式,从容器内部去除一些无关的组件。虽然从两种方式作出选择是困难的,但是我们更青睐于小的那种,因为容器简单化会消耗更少的CPU和内存。这种方式被详细的说明在 Docker blog中。 环境配置在生产环境中,我们使用Chef这一部署工具来管理系统的各个节点。这样的话,我们可以轻松做到在一个容器之中运行Chef,然而我们并不希望某些服务在每一个容器中都运行,比如:日志的索引服务,运行状态采集服务等。而Chef的使用无疑使得很多服务都会重复安装在不必要的容器中,由于无法忍受以上徒劳的重复工作,我们选择在每一台运行Docker的宿主机上共享同一份这些服务的副本。 如何将容器做得轻量级,关键是:将Chef部署工具的运行脚本转换为一个Dockerfile(这部分内容,我们后来将其替换为一个自定义的Docker build流程,之后的文章会涉及)。Docker的诞生,可以说是天赐良机,使运维人员评估内部的生产环境,并回顾以及整理整个系统生命周期中到底需要什么。在这一环节中,对于系统的的割舍请尽量无情,同时也要保证在code review过程中尽量做到谨慎。 其实,整个过程,并没有听起来那么艰难。最终,我们团队以一个125行Dockerfile的形式告终,而该Dockerfile则是定义了在Shopify上所有容器需要共享的基础镜像。该基础镜像包含了25 个包,这些包中包括跨度较大的编程语言运行时(Ruby、Python和Node),还有多种开发工具(Git、Vim、build-essential和Go),也有一些需要共享使用的库文件。同时,基础镜像中还包含了一系列工具脚本用以任务的运行,比如通过调整参数来启动Ruby,或者向Datadog发送监控数据等。 在以上环境下,我们的应用可以很随意在这个基础镜像上添加自身的特定需求。尽管如此,我们最大的应用也仅仅是添加了一些操作系统的依赖包,所以总体来讲,我们的基础镜像还是相对简洁精干的。 容器的100定律在选择将何种服务容器化时,可以首先假设你有100个小容器运行在同一个host上,然后想一下是否真的有必要运行100个服务的副本,还是大家共享一个单独的host更好。 以下是一些实例说明我们如何根据100定律来决定如何使用容器的: 日志索引:日志对于诊断错误至关重要,尤其在容器退出,文件系统消失后显得更为重要。我们特意避免了修改应用程序的日志行为(比如强制它们重新定向到系统日志),并且允许它们继续写日志到文件系统。运行100个日志代理似乎是错误的做法,所以我们创建一个后台程序去处理以下重要任务:
统计:Shopify在几个级别(系统,中间件和应用程序)上都生成了运行时统计,得到的结果通过代理或应用程序代码转述。
Kafka:我们使用Kafka来实时处理从Shopify堆栈到合作伙伴的事件。我们使用Ruby on Rail代码来发布Kafka事件,生成信息,然后放到SysV消息队列。一个Go语言写的后台程序会在队列中取出消息发送给Kafka。这减少了Ruby进程的时间,我们也能更好地应对Kafka服务器的事故。有一点不好的是,SysV消息队列是IPC namespace的一部分,所以我们不能用来连接container:host。我们的解决方案是在host上添加一个socket端,用来将消息放到SysV队列。 100定律的使用需要一定的灵活性。一些情况下,仅仅需要写一下组件的“黏合器”,也可以通过配置来达到目的。最终,你应该获得一个容器,内含你的应用程序运行所需的东西,以及一个提供了Docker托管和共享服务的主机环境。 |