docker误区

来源:互联网 发布:874是什么意思网络用语 编辑:程序博客网 时间:2024/05/16 19:47

docker非常高调地冲击了系统环境。docker对于系统的进步是非常惊喜的,但是我们对它的认识也存在一些误区。

特定场合下的建议
本文关于docker的讨论仅限于设置有多主机配置的关键任务系统上(主要是web服务)。请记住,我的建议可能并不适用于你在docker上其它场景的应用。

docker背景
本文假设读者对于什么是docker以及如何使用docker大体上有一个基本的理解。
本文不会对docker做全面的讲解。如果你不知道什么是docker,请先仔细阅读以下资料:
What is Docker?
Docker Basics

误区
在许多场景下,docker是一个神奇的工具。但是我们在平时使用docker时存在一些误区。

误区:如果我学了docker,我就不需要再去学其它系统了。
也许将来有一天,这样的事情会发生。但现在,这样是不行的。最好把docker看作是一个高级优化。确定,它非常酷、功能强大。但是,如果你是一个知道怎么把docker所有潜在的属性用于使产品更安全的系统管理专家,你会发现docker使系统更加复杂,你应该只把它用于任务关键系统。
目前,如果要使用docker,你需要更多系统专业技能,而不是更少。几乎你看到的所有关于docker的文章,都会给你展示一些非常简单的用例,却没有将docker用于多主机生产系统上的这种复杂用例。
要想在一个多主机产品环境中安全稳定地运行docker,必须许多方面必须小心地管理:
安全的私人镜像文件仓库
零停机时间的容器部署
支持回滚的容器部署
容器与多个宿主机之间的网络连接
管理容器日志
管理容器数据(数据库等)
创建能够正常初始化、记日志的镜像文件
更多。。。

做到所有这些并不现实。因为一些大公司已经把docker用到它们的产品中去了,这显然很重要。随着docker日渐成熟的生态体系(通过Flynn, Docker容器主机等),这种情况将会改善。但是目前,如果你真的打算把docker用于你的产品,你必须对于系统管理和统筹相当熟练。
为了表达我的观点,请参考下面这些文章。在我查阅的文章当中,它们能最好地说明产品可靠性(仍然后缺失了一些重要的元素)
《Easily Deploy Redis Backed Web Apps With Docker》
《Integrating Docker with Jenkins for Continuous Deployment of a Ruby on Rails App》
《Using Docker with Github and Jenkins for Repeatable Deployments》
《Fixing the Docker Ubuntu image on Rackspace Cloud》

如果你不想学习怎样管理服务器,你需要使用一个像Heroku这样的平台服务(PaaS)。docker并不提供这样的解决方案。

误区:每个docker容器中只能有一个进程
如果把docker看作是一个基于角色的虚拟机而不是部署的只有一个目的的进程,管理docker会更容易。理解这一点很重要。
举个例子,你要创建了一个类似于app虚拟机的app容器,同时还要在容器中创建init,cron, ssh等进程。请不把试图为每一个进程都创建一个容器并把这些进程分别放入各自的容器中。
有一些很好的理论支持每个容器一个进程,但实际上,如果真的这样管理将会是一场噩梦。也许在规模非常大的情况下,这种方法会更有意义。但是对于大多数系统,你会更希望是基于角色的容器(应用, 数据库, 文件管理等)
如果你仍然不能接受这一观点,读一读这篇关于微服务的文章。它指出许多相似的管理问题《微服务不是免费的午餐》

误区:如果使用Docker,就不需要配置管理(CM)工具
这观点不完成错。由于你的服务放在docker里,你可能不需要那么多的配置管理工具,但你一定会需要一个部署工具用于规定、部署和管理你的服务。

这就是docker和ansible非常像的地方。ansible主要是一个统筹工具,同时也能够做配置管理。这意味着你可以在准备你的宿主服务器、部署和管理docker容器和管理网络时所有需要使用ansible的步骤中都可以使用它。
那么,如果你打算把docker用到产品中,首先要学像ansible这样的工具。还有许多其它的统筹工具(甚至有些是专门用于docker的),但没有一个像ansible这样简单、易学、强大。与其选择一个功能不能满足所有需求的工具(你最终不得不学更多的工具来弥补其它工具的不足),不如只学一种统筹工具。

误区:我必须马上使用docker
我看到许多人过早地使用docker。在你决定把Docker用到你的产品中之前,你必须保证你的系统是能够很好地工作的。
你的系统需要具备:
安全的最低优先级权限(基于key的登陆、防火墙、fail2ban等)
可恢复的安全的离线数据库备份
自动化的系统配置(使用Ansible, Puppet等)
自动化的部署
自动化的准备
监视所有的关键服务
更多(文档等)

如果在你的基础架构里存在临界孔,就不适合使用docker。这就好像把一个法拉利停在一个不稳定的悬崖。
docker是一个好的优化,但它需要一个好的基础来支撑。

误区:我不得不使用docker来获取它的速度和一致性优势!
我在下面列举了一些可以代替docker得到同样性和一致性的优化。事实上,大多数高级别的公司使用至少以下一种方式优化他们的系统。

配置管理工具(ansible/puppet等)
如果你的系统通过CM工具构造,你就可以很方便地创建和管理它们。尤其是在云中,可以很便宜且方便地创建或者销毁一个服务实例。

云镜像
许多云服务器都提供把服务器配置保存为镜像文件的能力。从一个镜像文件创建一个新的服务实例通常比使用CM工具配置一个服务器实例更快。
一种方法就是使用你的CM工具为你的服务器角色(应用、数据库,缓存)创建一个基础镜像文件。当你要从这个镜像文件上提出一个新的服务,你可以通过你的CM工具验证和管理它们。
如果需要对你的服务做一些小小的改动,你可以仅仅使用你的CM工具来管理这些改动。
渐渐地,这些镜像文件会与你当前的服务器配置偏离,所以需要周期性地创建新的服务器镜像文件。
这是黄金镜像模式的一个变种,它让你有使用镜像文件的速度,却帮你避免单调地为小改动重复创建镜像文件的问题。

版本打桩
大多数环境移植问题都是因为软件版本的差异。因此,为了增加docker一致性的优势,应对所有重要的软都显式地说明它们的版本。举个例子,在你的CM工具中,不要使用安装’nginx’,而是安装’nginx version 1.4.6-1ubuntu3’
如果你使用Ansible,使用脚本安装开发环境,在vagrant中安装会比在产品中安装稍微容易一点。如果你在你所有的环境中使用同一个操作系统版本(比如ubuntu 12.04 x86等),你的系统一致性会很高,由于环境差异导致的问题会非常少。

版本控制部署
如果你使用git(或类似的版本管理工具),你就可以把你的应用软件放到服务器上,然后每次以很小的差异更新。这一点和docker的镜像文件层映射类似。举个例子,如果你的代码基础版本是50MB大小,你想要更新你的代码。代码的改动只涉及某几个文件中几行的小小改动,如果你只是通过git从服务器上更新代码,你只会下载这个小的变化来更新你的代码基础版本。这使得部署很快。
包部署(主要是应用层代码)
如果软件部署需要像编译、最小化这CSS和JS资产这样比较耗时的步骤,考虑预编译和代码打包。用这种方法就像把代码打包成一个压缩包一样简单。别一种方法是使用一个例如dpkg或者rpm这样的实际的包管理来管理部署。
如果你使用git(或者其它版本控制工具),你自己建立一个只是用于编译的仓库(可以与代码相同或者分离)。
要想速度更快,要确保包(不管以什么形式)存在于你的服务器的本地。位于同一网络有时只是提升一点点速度,所以只需要考虑在服务器外部的网络是否有下载资源的瓶颈。

什么时候使用Docker?
那么,当你在你的开发环境中使用Vagrant时,你就可以开始使用Docker了。vagrant(1.6或更高版本)已经把docker当作一个虚拟机提供方(像virtual box和VMWare一样)了。它可以把docker的复杂性提取出去,所以你可发使用这个速度快又对资源要求不高的docker而不需要学习了。
对于多主机产品的使用,我会建议尽量使用我前面提到的其它更好的方法。当你的服务器数量达到一定量级这些方法不再适用时,那么考虑使用docker提供的更高级的优化。目前,在你得到docker的之前,你会让你的系统的大大增加。在接下来的几个月或几年中,随着docker和它的产品、模式的成熟,这一点可能会有改变。
当然,这个参议的前提是你的系统已经非常健壮并且充分脚本化、自动、安全、有备份、有监管等

结论
docker真的是一个让人震惊和项目。它代表了系统管理上一个巨大的进步。它很强大,它的使用用例不止于我今天在这里讨论的。我的重点是评估docker作为发而网络应用的服务器。然后,我的建议在其它的部分里不适用。
这是一套新的优化并且让人期待。但是请记住,使用和管理docker很快会变得复杂,而不是像大多数介绍Docker的文章里举的小例子那样。
docker的进步非常快,所以我的一些建议可能很快就会过时(希望如此)。我非常希望在多主机生产系统中使用docker的复杂性降低而可用性提升。到现在为止,我认为使用docker的代码比docke带来的好处更重要。

备注:
在产品中简化使用docker的一些建议
如果你的系统管理专家,并且你的系统量级已经到了在权衡docker代价和好处的时候,那么考虑这些建议来简化

你不需要把所有东西都docker化
只把docker使用在能从中获利的服务器角色。举个例子,假如你有几千个应用服务器,你使用Docker来优化App的部署。在这种情况下,只把应用服务器docker化,而继续像往常一个管理其它服务器。

使用基于角色的docker镜像文件
我在本文前面提到过这一点,这里只是再次强调。如果使用像应用、数据库、映射等这亲的角色而不是单个进程(sshd, nginx等),管理docker会更容易。
你通常会通过角色得到服务器脚本,这使得进程docker化更容易。
而且,如果达到一定量级,基本上每个服务器上只会有一个角色(应用服务器只是一个应用服务器, 不会提供数据库服务器)。这就意味着一个服务器一个Docker容器。一个服务器一个容器使用网络大大地简化(不用担心商品冲突等)。

尽可能地显式
如果你没有显示容器里的服务器端口,docker会为它们随机分配端口号。在某些场景中,这样当然是有用的(避免同一个主机上多个容器的端口冲突)。但是如果每个主机服务器只有一个容器角色,管理会更简单容易。如果你这么做,你就可以显式地分配端口号,不需要因为试图与随机的端口号通讯带来的复杂性而混乱。
有一些很好的工具,比如etcd, zookeeper, serf等。它们为系统提供服务发现功能。不再需要为了服务器的定位而困难地编程,你的应用可以通过询问这些服务发现应用来得到各种服务器的地址。当你的服务器达到一定量级,服务器发现工具非常有用。在这种情况下,管理硬编码服务器地址需要花费很大的代码且容易出问题。但是服务器发现工具会带来更多的复杂和麻烦,所以,如果不是一定需要就不要用它。相反,尽可能地在配置文件中显式地定义你的服务器。使用类似于ansible模板中的清单变量没有什么用。

不要把数据存入容器
不要把数据存入容器,除非你真的知道你在做什么。如果你不小心把一个在运行的容器停止了,里面的数据就永远地消失了。通过一个共享路径把数据直接存储到主机上是更安全简单的做法。
对于日志,既可以使用与主机共享路径的方法,也可以使用像logstash或者papertrail这样的远程日志收集服务。
对于用户上传的数据,使用专用的存储服务或者文件存储服务,比如亚马逊的S3、谷歌的云存储。
是的,确实有一些方法可以把数据存储到专门用于存储数据而不会被运行的容器中。但是除非数据的保密性要求非常高,把数据存储到主机服务器上或者其它什么地方就可以了。

使用私有索引服务
亲自建立一个以自己为主机的安全私有的docker索引是很麻烦的工作。使用私有docker索引服务来做这件事会更方便。

建立私有仓库
docker确定提供一种用于建立自己的仓库的镜像文件,但还有另一种管理方法。在建立时需要你做一些选择。你可能更愿意以建立仓库索引作为开始,除非你的镜像文件包含非常敏感的配置(例如数据库密码等)。当然,你不应该把敏感数据放到你的应用或者docker镜像文件中,而是建立一个更干净的方法,就像Ansible设置环境变量的敏感部分一样。

基于专业知识
Phusion(一家提供乘客网络服务的公司)创建了一个高级的docker镜像文件,你可以把它作为你的服务的基础。然后花一点时间解决许多创建docker镜像文件时遇到的通用的问题。它们的文档写得非常好,可以作为你的镜像文件的基础。
https://phusion.github.io/baseimage-docker/

https://github.com/phusion/baseimage-docker

https://github.com/phusion/passenger-docker

https://github.com/phusion/open-vagrant-boxes
说明:这篇文章来自于我的一本书《Taste Test: Puppet, Chef, Salt, Ansible》
原创:2014/6/9

0 0
原创粉丝点击