阅读更多

1顶
0踩

开源软件
摘要:Shopify是一家为数十万家网店提供解决方案的公司,网站主要的框架是Ruby on Rails,为了更易扩展和管理业务,开始使用Docker和CoreOS技术。Shopify软件工程师Graeme Johnson介绍了如何在生产环境中使用容器技术。
【编者按】 Shopify是一家提供电商网店解决方案的公司,目前服务的网店数有10万家以上(Tesla 也是它的用户)。网站主要的框架是Ruby on Rails,1700个内核和6TB RAM,每秒可以响应8000个用户请求。为了更易扩展和管理业务,Shopify开始使用Docker和CoreOS技术,Shopify软件工程师Graeme Johnson将撰写一系列文章分享其经验,本文是系列中的第二篇,重点介绍了Shopify在生产环境中是如何使用容器技术。

以下为翻译原文:



为什么使用容器技术?

在我们深入到构建容器的机制之前,首先讨论一下这么做的动机。容器在数据中心拥有的潜能就像游戏机之于游戏。在PC游戏的初期,通常在你开始玩一款游戏之前,都需要安装视频或音频驱动。然而,游戏机提供了不同的体验,与Docker很类似:

  • 可预见性:游戏带它自带游戏,随时可运行,不需要下载或更新;
  • 迅速:游戏带采用只读存储器,从而获得了如同闪电的速度;
  • 简单:游戏带是健壮的,并且很大程度上拥有儿童防护措施,它们是真正的即插即用;
  • 可预见性、迅速、简单,在扩展规模方面都是好东西。 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个日志代理似乎是错误的做法,所以我们创建一个后台程序去处理以下重要任务:

  • 运行在host端,并订阅Docker event;
  • 在容器启动时,配置日志索引来监视容器;
  • 容器销毁时,删除索引指令。
  • 为了确保容器退出时,所有的日志都被编入索引,你可能需要稍微延迟容器的销毁。

统计:Shopify在几个级别(系统,中间件和应用程序)上都生成了运行时统计,得到的结果通过代理或应用程序代码转述。

  • 许多我们的统计结果可以通过StasD传输,幸运的是我们可以配置Datadog的host端去接收容器传来的流量,通过适当的配置,就可以将StasD接收的地址传给容器;
  • 由于容器从本质上来说就是进程树,所以一个host端的系统监控代理可以看到容器边界共享一个单一的系统监控也是自由的;
  • 从一个更加以容器为中心的角度出发,来考虑Docker和Datadog的集成,会添加Docker metrics到host端的监控代理;
  • 应用级别的metrics大多数运行得还可以,它们或者通过StasD发送事件,或者直接和其它服务对话。为一个容器指定名字很重要,这样一来metrics也更容易读。

Kafka:我们使用Kafka来实时处理从Shopify堆栈到合作伙伴的事件。我们使用Ruby on Rail代码来发布Kafka事件,生成信息,然后放到SysV消息队列。一个Go语言写的后台程序会在队列中取出消息发送给Kafka。这减少了Ruby进程的时间,我们也能更好地应对Kafka服务器的事故。有一点不好的是,SysV消息队列是IPC namespace的一部分,所以我们不能用来连接container:host。我们的解决方案是在host上添加一个socket端,用来将消息放到SysV队列。

100定律的使用需要一定的灵活性。一些情况下,仅仅需要写一下组件的“黏合器”,也可以通过配置来达到目的。最终,你应该获得一个容器,内含你的应用程序运行所需的东西,以及一个提供了Docker托管和共享服务的主机环境。

将你的应用容器化

随着环境的就绪,我们可以把注意力转到程序的容器化上来。

我们更倾向于thin container能准确地做一件事。例如一个unicorn(Unicorn是一个Unix和局域网/本地主机优化的HTTP服务器)master和工作线程服务web请求,或者一个Resque(Resque使用Redis创建后台任务,存储进队列,并随后执行。它是Rails下最常用的后台任务管理工具之一)工作线程服务一个特定的队列。thin container允许细粒度的缩放比例(一般是指远程方法调用的接口的颗粒大小),以满足需求。例如,我们可以增加检查垃圾邮件攻击响应的 Resque工作线程的数目。

我们发现采取一些标准约定对于在容器中的代码布局会有用处:

  • 应用程序总是root在容器内部的/app下;
  • 应用程序通常通过单个端口发布服务;

我们还确立了一些容器化git repo(repo封装了对git的操作)的约定:
  • /container/files 拥有一个在其建立时就被直接复制进容器的文件树,举个例子,请求 Splunk 索引的应用程序日志,它添加/container/files/etc/splunk.d/inputs.conf 文件进你的git repo就足够了(控制日志索引的责任转移到开发者,这是一个微妙而重大的转变,过去这都是运维管理员的工作);
  • /container/compile是一个 shell 脚本,编译您的应用程序,并生成一个随时可运行的容器。建立此文件并适应您的应用程序,是最复杂的地方;
  • /container/roles.json保存命令行以机器可读的形式用来运行该工作负载。很多我们的应用程序以多个角色,运行相同代码库,一些处理 web 流量同时处理后台任务。这部分的灵感来自 Heroku 的 procfile。以下是一个示例的roles.json文件:


我们用一个简单的Makefile驱动建立,也可以本地运行。我们的 Dockerfile 看起来像这样:取消编译阶段的目标是产生一个是即刻准备运行的容器。Docker关键的优势之一就是在容器启动时超级快速启动而不被损坏因为额外的工作。为了实现这一目标您需要了解您的整个部署过程。 举几个例子:

  • 我们正在使用Capistrano(Capistrano是一种在多台服务器上运行脚本的开源工具,它主要用于部署web应用)将代码部署到机器,并且asset编译以前发生的事情作为部署的一部分。通过移动资产编译到容器里生成,部署新代码由更简单、快几分钟。
  • 我们的unicorn 主机启动来从table 模型中获取数据(Table 对象代表一个 HTML 表格。)不只这是缓慢的,而且我们更小的容器大小意味着将需要更多的数据库连接。另一方面,它是可能做到这一点(获取数据)的在容器建立的时候,以加速启动。

在本例中,编译阶段包括以下的逻辑步骤:

  • bundle install
  • asset compile
  • database setup

为了保持这一公告(邮件)的大小合理,我们简化了一些细节。密钥管理是一个主要的细节,我们还没有在这里讨论。不要将其登记入源码管理。我们已经获取了用来加密密钥的代码,致力于该主题的博客帖子很快就会来了。

调试和细节

运行在容器中的应用程序和容器之外的表现绝大多数情况是相同的。此外,你的大多数调试工具(例如:strace,gdb,/proc/filesystem)是运行在Docker所在的host上。还有大家熟悉的工具nsenter或nsinit,可以用他们挂载到一个运行中的容器里进行调试。

docker exec,作为docker 1.3.0版本中提供的新工具,能够被用来向运行的容器中注入进程。但是,不幸的是,如果你注入进程需要root权限,你还是需要通过nsenter,有些地方的情况可能不会像人们预料的那样。

进程分层

尽管我们运行轻量级的容器,仍然需要初始化进程(pid=1)从而与监控工具,后台管理,服务发现等做到紧密集成,也能给我们细粒度的健康监测。

除了初始化进程,我们在每个容器中添加了一个ppidshim进程(pid=2),应用程序进程的pid=3。由于ppdishim进程的存在,应用程序没有直接继承自初始化进程,避免它们以为自己是后台守护进程,造成错误的后果。

最终的进程层次是这样的:

Signals

如果你在使用容器技术,你很可能会修改现有的运行脚本或写一套新的脚本,其中包含了docker run的调用。默认的情况下,docker run会代理signal到你的应用程序,所以你必须理解应用程序是如何解读signal的。

标准的UNIX做法是发送SIGTERM去请求有序地关闭一个进程。为了确保应用程序遵守这个惯例,Resque使用SIGQUIT来有序地关闭进程,SIGTERM来紧急关闭进程。幸运的是,Resque可以被配置使用SIGTERM来优雅地关闭进程。

Hostnames

我们选择容器名称来描述工作负载(例如 unicorn-1, resque-2),并结合这些主机名来进行简单追溯。最终的结果会是这样:unicorn-1.server2.shopify.com.我们使用Docker的主机名标签将结果传入容器中,这使大多数应用程序报告出正确的值。一些程序(Ruby)询问主机名来得到缩略名(unicorn-1),而不用询问预期的FQDN。由于Docker管理着/etc/resolv.conf 文件,我们当前版本不允许任意变更,所以我们通过LD_PRELOAD,重写了gethostname()和uname()的方法,并注入到library中。最终结果会是,监控工具发布我们想要得到的主机名却不用去更改应用程序代码。

注册和部署

我们发现构建容器的过程中复制‘bare metal’的行为相当于一个不断调试的过程。如果你是理智的的,你肯定想自动化的去构建容器。

为了每个人都能push,我们使用github commit hook去触发一个容器的构建,构建过程中我们会提交状态日志来判定是否构建成功。我们使用git提交SHA到容器的“docker tag”,所以你能准确的看到什么样的代码版本被包含在容器中。为了更容易被脚本调试和使用,我们同样也把SHA放到容器里的一个文件中(/app/REVISION)。

一旦你的构建是正常的,你会想把容器push到一个中央的注册表仓库。为了提高部署速度和减少外部依赖我们选择运行数据中心中自己的库。 我们在Nginx反向代理(其中缓存了GET请求的内容)背后运行多个标准Python注册表的副本,如下图所示:



当多个Docker主机请求相同的镜像时,我们发现大型网络接口(10 Gbps)和反向代理,在解决”thundering herd“这样的代码部署相关的问题是很有效的。代理方法还允许我们运行多种类型的库,并在发生故障的情况下,提供自动故障转移。

如果遵循这个蓝图,你可以自动化去构建容器,并且安全地把容器存储在一个中央仓库注册表中,这些都可以融入你的部署过程。

在本系列的下一篇文章,作者将描述如何管理应用程序的秘密。

原文链接:Docker at Shopify: How we built containers that power over 100,000 online shops
  • 大小: 106.7 KB
  • 大小: 66.1 KB
来自: CSDN
1
0
评论 共 1 条 请登录后发表评论
1 楼 dsjt 2014-11-26 16:49
docker 最近新闻真多

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • [转载]有“容”乃大:Docker容器,十万网店轻松托管

    Shopify是一家提供电商网店解决方案的公司,目前服务的网店数有10万家以上(Tesla 也是它的用户)。网站主要的框架是Ruby on Rails,1700个内核和6TB RAM,每秒可以响应8000个用户请求。为了更易扩展和管理业务,...

  • 《Neo4j 3.x入门经典》已正式出版,各大网店均有售!

    《Neo4j 3.x入门经典》已正式出版,各大网店均有售!   大家好,由我参与翻译(第二译者)的《Neo4j 3.x入门经典》已拿到批号正式出版,在各大网店均有售! 京东链接: https://item.jd.com/41497370796.html ...

  • 总结云计算/OpenStack/Docker的概念理解

     Docker 是 PaaS 提供商 dotCloud 开源的一个基于 LXC 的高级容器引擎,源代码托管在 Github 上, 基于go语言并遵从Apache2.0协议开源。 OpenStack与Docker的结合使用  为什么流行两者的结合: ...

  • Docker日知录(一)

    方便快捷已经是 Docker的最大优势,过去需要用数天乃至数周的 任务,在Docker容器的处理下,只需要数秒就能完成。 2、避免选择恐惧症: 如果你有选择恐惧症,还是资深患者。Docker 帮你 打包你的纠结!比如...

  • ApacheCN PHP 译文集 20211101 更新

    十六、添加依赖注入容器 十七、结论 十八、附录 A:典型遗留页面脚本 十九、附录 B:网关前的代码 二十、附录 C:网关后的代码 二十一、附录 D:事务脚本后的代码 二十二、附录 E:采集表示逻辑前的代码 二十三、...

  • Spark 2.3.0+Kubernetes应用程序部署

    Spark2.3.0+Kubernetes应用程序部署...目前Kubernetes调度是实验性的,在未来的版本中,Spark在配置、容器映像、入口可能会有行为上的变化。(1) 先决条件。运行在Spark 2.3 或更高版本上。运行Kubernetes cluster ...

  • 玩转Python必备:史上最全的Python库,【值得收藏,事半功倍】

    MapReduce是Google提出的一个软件[架构],用于大规模数据集(大于1TB)的并行运算。概念“Map(映射)”和“Reduce(归纳)”,及他们的主要思想,都是从函数式编程语言借来的MapReduce函数库。Framworks and ...

  • 基于阿里云Serverless架构下函数计算的最新应用场景详解(一)

    摘要: Serverless概念是近年来特别火的一个技术概念,基于这种架构能构建出很多应用场景,适合各行各业,只要对轻计算、高弹性、无状态等场景有诉求的用户都可以通过本文来普及一些基础概念,看看这些场景是否对...

  • Serverless应用场景

    场景二:利用弹性扩容(视频直播多人连麦场景) 场景三:物联网数据处理场景 场景四:共享派单系统详解 总结 更多信息 Serverless架构是近年来迅速兴起的一个技术概念。基于这种架构能构建出多种应用场景,适用...

  • 程序员干货学习资源(持续更新)

    前言(程序员学习资料汇总->... 记录一些作为一名程序员在学习道路上经常用到的一些资料,以备...CSDN:号称全球最大的中文IT社区,很多业界大牛在上面开通有博客 云栖社区:云栖社区是面向开发者的开放型技...

  • 基于Serverless架构最新应用场景详解

    摘要: Serverless概念是近年来特别火的一个技术概念,基于这种架构能构建出很多应用场景,适合各行各业,只要对轻计算、高弹性、无状态等场景有诉求的用户都可以通过本文来普及一些基础概念,看看这些场景是否对...

  • 服务器网站权限,在服务器上设置网站权限

    在服务器上设置网站权限 ...您可通过以下步骤实现网站文件托管:以下代码展示了如何实现网站文件托管:上例中您可以使用https://bucketname.your-endpoint/test.html在浏览器直接访问托管的开发过程中,您有任何问...

  • 51单片机控制步进电机三轴联动51单片机控制步进电机三轴联动51单片机控制步进电机3轴联动c语言,抛砖引玉供大家参考。.zip

    51单片机控制步进电机三轴联动51单片机控制步进电机三轴联动51单片机控制步进电机3轴联动c语言,抛砖引玉供大家参考。

  • 数据库管理工具:dbeaver-ce-23.0.1-linux.gtk.aarch64-nojdk.tar.gz

    1.DBeaver是一款通用数据库工具,专为开发人员和数据库管理员设计。 2.DBeaver支持多种数据库系统,包括但不限于MySQL、PostgreSQL、Oracle、DB2、MSSQL、Sybase、Mimer、HSQLDB、Derby、SQLite等,几乎涵盖了市场上所有的主流数据库。 3.支持的操作系统:包括Windows(2000/XP/2003/Vista/7/10/11)、Linux、Mac OS、Solaris、AIX、HPUX等。 4.主要特性: 数据库管理:支持数据库元数据浏览、元数据编辑(包括表、列、键、索引等)、SQL语句和脚本的执行、数据导入导出等。 用户界面:提供图形界面来查看数据库结构、执行SQL查询和脚本、浏览和导出数据,以及处理BLOB/CLOB数据等。用户界面设计简洁明了,易于使用。 高级功能:除了基本的数据库管理功能外,DBeaver还提供了一些高级功能,如数据库版本控制(可与Git、SVN等版本控制系统集成)、数据分析和可视化工具(如图表、统计信息和数据报告)、SQL代码自动补全等。

  • 数据库管理工具:dbeaver-ce-23.1.5-macos-x86-64.dmg

    1.DBeaver是一款通用数据库工具,专为开发人员和数据库管理员设计。 2.DBeaver支持多种数据库系统,包括但不限于MySQL、PostgreSQL、Oracle、DB2、MSSQL、Sybase、Mimer、HSQLDB、Derby、SQLite等,几乎涵盖了市场上所有的主流数据库。 3.支持的操作系统:包括Windows(2000/XP/2003/Vista/7/10/11)、Linux、Mac OS、Solaris、AIX、HPUX等。 4.主要特性: 数据库管理:支持数据库元数据浏览、元数据编辑(包括表、列、键、索引等)、SQL语句和脚本的执行、数据导入导出等。 用户界面:提供图形界面来查看数据库结构、执行SQL查询和脚本、浏览和导出数据,以及处理BLOB/CLOB数据等。用户界面设计简洁明了,易于使用。 高级功能:除了基本的数据库管理功能外,DBeaver还提供了一些高级功能,如数据库版本控制(可与Git、SVN等版本控制系统集成)、数据分析和可视化工具(如图表、统计信息和数据报告)、SQL代码自动补全等。

  • java某百货店POS积分管理系统-积分点更新生成以及通票回收处理(源代码+论文)

    java某百货店POS积分管理系统_积分点更新生成以及通票回收处理(源代码+论文)

  • 南京邮电大学电工电子实验B实验二(传输网络的幅频和相频特性)

    南京邮电大学电工电子实验B实验二(传输网络的幅频和相频特性)

  • 模电LM324.ms14

    大二模电课设——基于四运放芯片LM324的组合电路

Global site tag (gtag.js) - Google Analytics