注:在这篇文章中,我主要谈论shell与ansible对比的缺点。然而,在实践中,有更糟糕的情况,如不使用任何脚本,甚至没有任何清单或任何文档。

惊喜:

    在我写了一本关于配置管理(CM)工具的书之后,我发给了大约20人,包括一些非常著名的开发人员。真正让我吃惊的是一些更著名的开发者的反应。他们基本上说,“这真的很酷,但我可能不会读它,因为我现在基于手动安装或者shell脚本的工作流程是没问题的。”

    我有点震惊,但我考虑了几分钟后,我意识到鉴于他们对配置管理工具的理解,他们的选择是完全理智和合理的。

    例如:

    Aaron Patterson (一个顶级 Ruby on Rails 的贡献者) 完美地证明了这个问题:

    在阅读了一系列Chef教程之后,我没弄明白为什么它比shell脚本好。


复杂性和成本:


对他们来说,使用配置管理(CM)工具意味着数周的努力学习复杂的概念,面对着复杂的安装过程,并要持续的维护这个复杂的系统。他们意识到了使用CM的一点好处,但是使用CM工具的成本似乎太高了,以至于不值得付出努力。

Michael Booth在他的×××新闻评论中很好地捕捉到了这种情绪:

作为Puppet的老用户,我坚信使用Puppet这样的工具,但Puppet和Chef都是为小工作而设计的(而且,也可以说,对于大多数其他工作来说),所以实际上向初学者推荐他们总是这样:

A:“我只是通过手动操作一些shell命令来建立一个云实例。”

B:“你不应该这样做,因为X和Y,Z. 你应该学习Puppet或Chef。”

A:等等……你刚才叫我去花三十个小时去做徒劳无功的事儿,以换取我甚至无法察觉的未知的好处?”

B:“为什么,是的,我相信我做到了!”

幸运的是,有一些新的CM工具,它专注于简单性和流畅的用户体验。其中最简单和最强大的一个工具就是 Ansible.

Why it Matters

Most engineers would laugh at a company that had zero tests and didn't version control or even backup their code. But that's exactly what many companies do with their systems.

And these businesses often don't realize the astronomical risks and costs of this neglect.

Your server systems are the underlying foundation of your application. They are basically the "app" that your app code runs on. As such, your systems should be version controlled and tested. There are many other benefits of course like speed, scalability, lower costs, etc, but I won't go into them all here.

At a recent client job, the former system administrator set up all of their servers manually and left ZERO documentation. I had to spend a few weeks divining what he did and try to capture everything into a CM tool (Chef in this case). Not one week after I finished doing that, one of their key servers inexplicably failed. Fortunately, I had done the work needed and they were able to bring up a replacement within minutes. Had that work not been done, the company would have been severly crippled and might have even died due to the days of downtime that would have been inevitable.

That's just a tiny example. The cost savings for a business are huge when the team uses a CM tool. When it takes a couple minutes to bring up a new server instead of hours/days/weeks, that's a huge savings (assuming your engineers cost greater than $0/hour).

Fight!

Ansible has brought the learning curve down so far that it can actually be EASIER to use Ansible than to do a manual install or a shell script.

The high cost of using a CM tool is now gone and you also get all the benefits of configuration management and remote execution.

Hopefully this will convince folks who are still on the fence to start using a CM tool like Ansible for more awesome systems.

Scenario

The great guys over at Phusion recently released an APT repository for their Passenger web/application server.

I've been looking for a good real-world example in order to compare Manual Installs vs Shell Scripts vs Ansible and this scenario seemed ideal.

Demonstration

I'm going to briefly show you setting up Phusion Passenger with a Manual Install, then create a Shell Script, then show how to do it in Ansible. The server I'm using is Ubuntu 13.04 (Raring Ringtail) with the software-properties-common package installed for some supporting utilities.

Manual Install

root@server:~# # Install the PGP key root@server:~# gpg --keyserver keyserver.ubuntu.com --recv-keys 561F9B9CAC40B2F7 root@server:~# gpg --armor --export 561F9B9CAC40B2F7 | sudo apt-key add - root@server:~# # Install https support for apt root@server:~# apt-get install apt-transport-https root@server:~# # Add the passenger apt repository root@server:~# vi /etc/apt/sources.list.d/passenger.list root@server:~# chown root: /etc/apt/sources.list.d/passenger.list root@server:~# chmod 600 /etc/apt/sources.list.d/passenger.list root@server:~# # Update the apt cache so we can use the new repo root@server:~# apt-get update root@server:~# # Install nginx root@server:~# apt-get install nginx-full passenger root@server:~# # Set up passenger in the nginx configuration root@server:~# vi /etc/nginx/nginx.conf root@server:~# # Start nginx root@server:~# service nginx restart

Shell Script

# Install the PGP key gpg --keyserver keyserver.ubuntu.com --recv-keys 561F9B9CAC40B2F7 gpg --armor --export 561F9B9CAC40B2F7 | apt-key add - # Install https support for apt apt-get install apt-transport-https -y # Add the passenger apt repository echo "deb https://oss-binaries.phusionpassenger.com/apt/passenger raring main" > /etc/apt/sources.list.d/passenger.list chown root: /etc/apt/sources.list.d/passenger.list chmod 600 /etc/apt/sources.list.d/passenger.list # Update the apt cache so we can use the new repo apt-get update # Install nginx apt-get install nginx-full passenger -y # Set up passenger in the nginx configuration sed -i "s/# passenger_root/passenger_root/" /etc/nginx/nginx.conf sed -i "s/# passenger_ruby/passenger_ruby/" /etc/nginx/nginx.conf # Start nginx service nginx restart

Assuming that's in passenger.sh, then run:

root@server:~# bash passenger.sh

Ansible

--- - hosts: all   tasks:   - name: Ensure the PGP key is installed     apt_key: >       state=present       id=AC40B2F7       url="http://keyserver.ubuntu.com/pks/lookup?op=get&fingerprint=on&search=0x561F9B9CAC40B2F7"   - name: Ensure https support for apt is installed     apt: >       state=present       pkg=apt-transport-https   - name: Ensure the passenger apt repository is added     apt_repository: >       state=present       repo='deb https://oss-binaries.phusionpassenger.com/apt/passenger raring main'   - name: Ensure nginx is installed     apt: >       state=present       pkg=nginx-full   - name: Ensure passenger is installed     apt: >       state=present       pkg=passenger       update_cache=yes   - name: Ensure the nginx configuration file is set     copy: >       src=/app/config/nginx.conf       dest=/etc/nginx/nginx.conf   - name: Ensure nginx is running     service: >       name=nginx       state=started

Assuming that's in passenger.yml, then run:

root@server:~# ansible-playbook passenger.yml
Some Differences

You may notice that I copied over the nginx config file for Ansible rather than just modifying the file directly on the server like I did for the manual install and shell script. Initially I looked into editing the file with Ansible's lineinfile module, but it just felt so wrong. That's another nice thing about Ansible, it encourages better practices. So, I decided to save the nginx config file locally so I could track it in version control and copy it over instead.

You'll also notice that I start the comments for Ansible with "Ensure". That is because Ansible will not only do the initial installation, but can also be run again and again to 'ensure' that the system is in the desired state. Ansible can perform the function of not only setting up your systems, but also testing them for correctness.

By contrast, a shell script can be very dangerous to run more than once unless you're extremely careful and know exactly what every line does. For example, what will those gpg commands do if I run them again? I have no idea. I could invest time to see if they are safe to run multiple times, or I could just use Ansible.

Note: The Ansible script can be improved. I kept it simple so it was easy to see how it correlated to the shell script. However, there are several things I could have done to make it better.

I could have added enabled=yes to the nginx service. That would have set the service to start automatically if the server is rebooted.

I could have combined the installation of the nginx-full and passengerpackages by using with_items.

I could have set a handler to notify nginx to restart whenever nginx.confis updated.

The Winner

  • Which method is most likely to end up in source control?

  • Which method can be run multiple times safely with confidence?

  • Which method can easily be run against multiple servers?

  • Which method actually verifies (tests) your server for correctness?

  • Which method can target certain servers easily (web, db, etc)?

  • Which method supports easily templating your configuration files?

  • Which method will grow to easily support your whole stack?

I didn't cover some of these topics, but the answer to all of these is: Ansible.

Not only can you start using it right away for trivial scripts like this, but it also gives you a ton of power that you can use later for free.