Merge pull request #1919 from bazz2/master

[translated]The Why and How of Ansible and Docker
This commit is contained in:
bazz2 2014-10-30 13:12:51 +08:00
commit ac2fb8d8ed
2 changed files with 103 additions and 104 deletions

View File

@ -1,104 +0,0 @@
[bazz222222222222222222222]
The Why and How of Ansible and Docker
================================================================================
There is a lot of interest from the tech community in both [Docker][1] and [Ansible][2], I am hoping that after reading this article you will share our enthusiasm. You will also gain a practical insight into using Ansible and Docker for setting up a complete server environment for a Rails application.
Many reading this might be asking, “Why dont you just use Heroku?”. First of all, I can run Docker and Ansible on any host, with any provider. Secondly, I prefer flexibility over convenience. I can run anything in this manner, not just web applications. Last but not least, because I am a tinkerer at heart, I get a kick from understanding how all the pieces fit together. The fundamental building block of Heroku is the Linux Container. The same technology lies at the heart of Dockers versatility. As a matter of fact, one of Dockers mottoes is: “Containerization is the new virtualization”.
### Why Ansible? ###
After 4 years of heavy Chef usage, the **infrastructure as code** mentality becomes really tedious. I was spending most of my time with the code that was managing my infrastructure, not with the infrastructure itself. Any change, regardless how small, would require a considerable amount of effort for a relatively small gain. With [Ansible][3], theres data describing infrastructure on one hand, and the constraints of the interactions between various components on the other hand. Its a much simpler model that enables me to move quicker by letting me focus on what makes my infrastructure personal. Similar to the Unix model, Ansible provides simple modules with a single responsibility that can be combined in endless ways.
Ansible has no dependencies other than Python and SSH. It doesnt require any agents to be set up on the remote hosts and it doesnt leave any traces after it runs either. Whats more, it comes with an extensive, built-in library of modules for controlling everything from package managers to cloud providers, to databases and everything else in between.
### Why Docker? ###
[Docker][4] is establishing itself as the most reliable and convenient way of deploying a process on a host. This can be anything from mysqld to ![](Docker container as a VM. The)redis, to a Rails application. Just like git snapshots and distributes code in the most efficient way, Docker does the same with processes. It guarantees that everything required to run that process will be available regardless of the host that it runs on.
A common but understandable mistake is to treat a Docker container as a VM. The [Single Responsibility Principle][5] still applies, running a single process per container will give it a single reason to change, it will make it re-usable and easy to reason about. This model has stood the test of time in the form of the Unix philosophy, it makes for a solid foundation to build on.
### The Setup ###
Without leaving my terminal, I can have Ansible provision a new instance for me with any of the following: Amazon Web Services, Linode, Rackspace or DigitalOcean. To be more specific, I can have Ansible create a new DigitalOcean 2GB droplet in Amsterdam 2 region in precisely 1 minute and 25 seconds. In a further 1 minute and 50 seconds I can have the system setup with Docker and a few other personal preferences. Once I have this base system in place, I can deploy my application. Notice that I didnt setup any database or programming language. Docker will handle all application dependencies.
Ansible runs all remote commands via SSH. My SSH keys stored in the local ssh-agent will be shared remotely during Ansibles SSH sessions. When my application code will be cloned or updated on remote hosts, no git credentials will be required, the forwarded ssh-agent will be used to authenticate with the git host.
### Docker and application dependencies ###
I find it amusing that most developers are specific about the version of the programming language which their application needs, the version of the dependencies in the form of Python packages, Ruby gems or node.js modules, but when it comes to something as important as the database or the message queue, they just use whatever is available in the environment that the application runs. I believe this is one of the reasons behind the devops movement, developers taking responsibility for the applications environment. Docker makes this task easier and more straightforward by adding a layer of pragmatism and confidence to the existing practices.
My application defines dependencies on processes such as MySQL 5.5 and Redis 2.8 by including the following `.docker_container_dependencies` file:
gerhard/mysql:5.5
gerhard/redis:2.8
The Ansible playbook will notice this file and will instruct Docker to pull the correct images from the Docker index and start them as containers. It also links these service containers to my application container. If you want to find out how Docker container linking works, refer to the [Docker 0.6.5 announcement][6].
My application also comes with a Dockerfile which is specific about the Ruby Docker image that is required. As this is already built, the steps in my Dockerfile will have the guarantee that the correct Ruby version will be available to them.
FROM howareyou/ruby:2.0.0-p353
ADD ./ /terrabox
RUN \
. /.profile ;\
rm -fr /terrabox/.git ;\
cd /terrabox ;\
bundle install --local ;\
echo '. /.profile && cd /terrabox && RAILS_ENV=test bundle exec rake db:create db:migrate && bundle exec rspec' > /test-terrabox ;\
echo '. /.profile && cd /terrabox && export RAILS_ENV=production && rake db:create db:migrate && bundle exec unicorn -c config/unicorn.rails.conf.rb' > /run-terrabox ;\
# END RUN
ENTRYPOINT ["/bin/bash"]
CMD ["/run-terrabox"]
EXPOSE 3000
The first step is to copy all my applications code into the Docker image and load the global environment variables added by previous images. The Ruby Docker image for example will append PATH configuration which ensures that the correct Ruby version gets loaded.
Next, I remove the git history as this is not useful in the context of a Docker container. I install all the gems and then create a `/test-terrabox` command which will be run by the test-only container. The purpose of this is to have a “canary” which ensures that the application and all its dependencies are properly resolved, that the Docker containers are linked correctly and all tests pass before the actual application container will be started.
The command that gets run when a new web application container gets started is defined in the CMD step. The `/run-terrabox` command was defined part of the build process, right after the test one.
The last instruction in this applications Dockerfile maps port 3000 from inside the container to an automatically allocated port on the host that runs Docker. This is the port that the reverse proxy or load balancer will use when proxying public requests to my application running inside the Docker container.
### Running a Rails application inside a Docker container ###
For a medium-sized Rails application, with about 100 gems and just as many integration tests running under Rails, this takes 8 minutes and 16 seconds on a 2GB and 2 core instance, without any local Docker images. If I already had Ruby, MySQL & Redis Docker images on that host, this would take 4 minutes and 45 seconds. Furthermore, if I had a master application image to base a new Docker image build of the same application, this would take a mere 2 minutes and 23 seconds. To put this into perspective, it takes me just over 2 minutes to deploy a new version of my Rails application, including dependent services such as MySQL and Redis.
I would like to point out that my application deploys also run a full test suite which alone takes about a minute end-to-end. Without intending, Docker became a simple Continuous Integration environment that leaves test-only containers behind for inspection when tests fail, or starts a new application container with the latest version of my application when the test suite passes. All of a sudden, I can validate new code with my customers in minutes, with the guarantee that different versions of my application are isolated from one another, all the way to the operating system. Unlike traditional VMs which take minutes to boot, a Docker container will take under a second. Furthermore, once a Docker image is built and tests pass for a specific version of my application, I can have this image pushed into a private Docker registry, waiting to be pulled by other Docker hosts and started as a new Docker container, all within seconds.
### Conclusion ###
Ansible made me re-discover the joy of managing infrastructures. Docker gives me confidence and stability when dealing with the most important step of application development, the delivery phase. In combination, they are unmatched.
To go from no server to a fully deployed Rails application in just under 12 minutes is impressive by any standard. To get a very basic Continuous Integration system for free and be able to preview different versions of an application side-by-side, without affecting the “live” version which runs on the same hosts in any way, is incredibly powerful. This makes me very excited, and having reached the end of the article, I can only hope that you share my excitement.
I gave a talk at the January 2014 London Docker meetup on this subject, [I have shared the slides on Speakerdeck][7].
For more Ansible and Docker content, subscribe to [The Changelog Weekly][8] — it ships every Saturday and regularly includes the weeks best links for both topics.
[Use the Draft repo][9] if youd like to write a post like this for The Changelog. Theyll work with you through the process too.
Until next time, [Gerhard][a].
--------------------------------------------------------------------------------
via: http://thechangelog.com/ansible-docker/
作者:[Gerhard Lazu][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译,[Linux中国](http://linux.cn/) 荣誉推出
[a]:https://twitter.com/gerhardlazu
[1]:https://www.docker.io/
[2]:https://github.com/ansible/ansible
[3]:http://ansible.com/
[4]:http://docker.io/
[5]:http://en.wikipedia.org/wiki/Single_responsibility_principle
[6]:http://blog.docker.io/2013/10/docker-0-6-5-links-container-naming-advanced-port-redirects-host-integration/
[7]:https://speakerdeck.com/gerhardlazu/ansible-and-docker-the-path-to-continuous-delivery-part-1
[8]:http://thechangelog.com/weekly/
[9]:https://github.com/thechangelog/draft

View File

@ -0,0 +1,103 @@
Ansible和Docker的作用和用法
================================================================================
在 [Docker][1] 和 [Ansible][2] 的技术社区内存在着很多好玩的东西,我希望在你阅读完这篇文章后也能获取到我们对它们的那种热爱。当然,你也会收获一些实践知识,那就是如何通过部署 Ansible 和 Docker 来为 Rails 应用搭建一个完整的服务器环境。
也许有人会问:你怎么不去用 Heroku首先我可以在任何供应商提供的主机上运行 Docker 和 Ansible其次相比于方便性我更偏向于喜欢灵活性。我可以在这种组合中运行任何程序而不仅仅是 web 应用。最后我骨子里是一个工匠我非常理解如何把零件拼凑在一起工作。Heroku 的基础模块是 Linux Container而 Docker 表现出来的多功能性也是基于这种技术。事实上Docker 的其中一个座右铭是:容器化是新虚拟化技术。
### 为什么使用 Ansible ###
我重度使用 Chef 已经有4年了LCTTChef 是与 puppet 类似的配置管理工具),**基础设施即代码**的观念让我觉得非常无聊。我花费大量时间来管理代码,而不是管理基础设施本身。不论多小的改变,都需要相当大的努力来实现它。使用 [Ansible][3],你可以一手掌握拥有可描述性数据的基础架构,另一只手掌握不同组件之间的交互作用。这种更简单的操作模式让我把精力集中在如何将我的技术设施私有化,提高了我的工作效率。与 Unix 的模式一样Ansible 提供大量功能简单的模块,我们可以组合这些模块,达到不同的工作要求。
除了 Python 和 SSHAnsible 不再依赖其他软件,在它的远端主机上不需要部署代理,也不会留下任何运行痕迹。更厉害的是,它提供一套内建的、可扩展的模块库文件,通过它你可以控制所有:包管理器、云服务供应商、数据库等等等等。
### 为什么要使用 Docker ###
[Docker][4] 的定位是:提供最可靠、最方便的方式来部署服务。这些服务可以是 mysqld可以是 redis可以是 Rails 应用。先聊聊 git它的快照功能让它可以以最有效的方式发布代码Docker 的处理方法与它类似。它保证应用可以无视主机环境,随心所欲地跑起来。
一种最普遍的误解是人们总是把 Docker 容器看成是一个虚拟机当然我表示理解你们的误解。Docker 满足[单一功能原则][5],在一个容器里面只跑一个进程,所以一次修改只会影响一个进程,而这些进程可以被重用。这种模型参考了 Unix 的哲学思想,当前还处于试验阶段,并且正变得越来越稳定。
### 设置选项 ###
不需要离开终端,我就可以使用 Ansible 来生成以下实例Amazon Web ServicesLinodeRackspace 以及 DigitalOcean。如果想要更详细的信息我于1分25秒内在位于阿姆斯特丹的2号数据中心上创建了一个 2GB 的 DigitalOcean 虚拟机。另外的1分50秒用于系统配置包括设置 Docker 和其他个人选项。当我完成这些基本设定后就可以部署我的应用了。值得一提的是这个过程中我没有配置任何数据库或程序开发语言Docker 已经帮我把应用所需要的事情都安排好了。
Ansible 通过 SSH 为远端主机发送命令。我保存在本地 ssh 代理上面的 SSH 密钥会通过 Ansible 提供的 SSH 会话分享到远端主机。当我把应用代码从远端 clone 下来,或者上传到远端时,我就不再需要提供 git 所需的证书了,我的 ssh 代理会帮我通过 git 主机的身份验证程序的。
### Docker 和应用的依赖性 ###
我发现有一点挺有意思的大部分开发者非常了解他们的应用需要什么版本的编程语言这些语言依赖关系有多种形式Python 的包、Ruby 的打包系统 gems、node.js 的模块等等,但与数据库或消息队列这种重要的概念相比起来,这些语言就处于很随便的境地了——随便给我个编程语言环境,我都能把数据库和消息队列系统跑起来。我认为这是 DevOps 运动它旨在促进开发与运维团队的和谐相处的动机之一开发者负责搭建应用所需要的环境。Docker 使这个任务变得简单明了直截了当,它为现有环境加了实用的一层配置。
我的应用依赖于 MySQL 5.5和 Redis 2.8,依赖关系放在“.docker_container_dependencies”文件里面
gerhard/mysql:5.5
gerhard/redis:2.8
Ansible 会查看这个文件,并且通知 Docker 加载正确的镜像,然后在容器中启动。它还会把这些服务容器链接到应用容器。如果你想知道 Docker 容器的链接功能是怎么工作的,可以参考[Docker 0.6.5 发布通知][6].
我的应用包括一个 Dockerfile它详细指定了 Ruby Docker 镜像的信息,这里面的步骤能够保证把正确的 Ruby 版本加载到镜像中。
FROM howareyou/ruby:2.0.0-p353
ADD ./ /terrabox
RUN \
. /.profile ;\
rm -fr /terrabox/.git ;\
cd /terrabox ;\
bundle install --local ;\
echo '. /.profile && cd /terrabox && RAILS_ENV=test bundle exec rake db:create db:migrate && bundle exec rspec' > /test-terrabox ;\
echo '. /.profile && cd /terrabox && export RAILS_ENV=production && rake db:create db:migrate && bundle exec unicorn -c config/unicorn.rails.conf.rb' > /run-terrabox ;\
# END RUN
ENTRYPOINT ["/bin/bash"]
CMD ["/run-terrabox"]
EXPOSE 3000
第一步是复制应用的所有代码到 Docker 镜像,加载上一个镜像的全局环境变量。这个例子中的 Ruby Docker 镜像会加载 PATH 配置,这个配置能确保镜像加载正确的 Ruby 版本。
接下来,删除 git 历史Docker 容器不需要它们。我安装了所有 Ruby 的 gems创建一个名为“/test-terrabox”的命令这个命令会被名为“test-only”的容器执行。这个步骤的目的是能正确解决应用和它的依赖关系让 Docker 容器正确链接起来,保证在真正的应用容器启动前能通过所有测试项目。
CMD 这个步骤是在新的 web 应用容器启动后执行的。在测试环节结束后马上就执行`/run-terrabox`命令进行编译。
最后Dockerfile 为应用指定了一个端口号将容器内部端口号为3000的端口映射到主机运行着 Docker 的机器)的一个随机分配的端口上。当 Docker 容器里面的应用需要响应来自外界的请求时,这个端口可用于反向代理或负载均衡。
### Docker 容器内运行 Rails 应用 ###
没有本地 Docker 镜像,从零开始部署一个中级规模的 Rails 应用大概需要100个 gems进行100次整体测试在使用2个核心实例和2GB内存的情况下这些操作需要花费8分16秒。装上 Ruby、MySQL 和 Redis Docker 镜像后部署应用花费了4分45秒。另外如果从一个已存在的主应用镜像编译出一个新的 Docker 应用镜像出来只需花费2分23秒。综上所述部署一套新的 Rails 应用,解决其所有依赖关系(包括 MySQL 和 Redis只需花我2分钟多一点的时间就够了。
需要指出的一点是我的应用上运行着一套完全测试套件跑完测试需要花费额外1分钟时间。尽管是无意的Docker 可以变成一套简单的持续集成环境当测试失败后Docker 会把“test-only”这个容器保留下来用于分析出错原因。我可以在1分钟之内和我的客户一起验证新代码保证不同版本的应用之间是完全隔离的同操作系统也是隔离的。传统虚拟机启动系统时需要花费好几分钟Docker 容器只花几秒。另外,一旦一个 Dockedr 镜像编译出来,并且针对我的某个版本的应用的测试都被通过,我就可以把这个镜像提交到 Docker 私服 Registry 上,可以被其他 Docker 主机下载下来并启动一个新的 Docker 容器,而这不过需要几秒钟时间。
### 总结 ###
Ansible 让我重新看到管理基础设施的乐趣。Docker 让我有充分的信心能稳定处理应用部署过程中最重要的步骤——交付环节。双剑合璧,威力无穷。
从无到有搭建一个完整的 Rails 应用可以在12分钟内完成这种速度放在任何场合都是令人印象深刻的。能获得一个免费的持续集成环境可以查看不同版本的应用之间的区别不会影响到同主机上已经在运行的应用这些功能强大到难以置信让我感到很兴奋。在文章的最后我只希望你能感受到我的兴奋。
我在2014年1月伦敦 Docker 会议上讲过这个主题,[已经分享到 Speakerdeck][7]了。
如果想获得更多的关于 Ansible 和 Docker 的内容,请订阅 [changlog 周报][8],它会在每周六推送一周最有价值的关于这两个主题的新闻链接。
如果你想为我们的 Changlog 写一篇文章,请[使用 Draft repo][9],他们会帮到你的。
下次见,[Gerhard][a]。
--------------------------------------------------------------------------------
via: http://thechangelog.com/ansible-docker/
作者:[Gerhard Lazu][a]
译者:[bazz2](https://github.com/bazz2)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译,[Linux中国](http://linux.cn/) 荣誉推出
[a]:https://twitter.com/gerhardlazu
[1]:https://www.docker.io/
[2]:https://github.com/ansible/ansible
[3]:http://ansible.com/
[4]:http://docker.io/
[5]:http://en.wikipedia.org/wiki/Single_responsibility_principle
[6]:http://blog.docker.io/2013/10/docker-0-6-5-links-container-naming-advanced-port-redirects-host-integration/
[7]:https://speakerdeck.com/gerhardlazu/ansible-and-docker-the-path-to-continuous-delivery-part-1
[8]:http://thechangelog.com/weekly/
[9]:https://github.com/thechangelog/draft