About this book

Ansible provides a clear and concise way to manage the configuration of your Linux infrastructure. It can help in making your infrastructure more maintainable, quicker to deploy, and easier to understand.

"Ansible Configuration Management" will take you from your very first command all the way to extending the very capabilities of Ansible itself. It takes a practical approach with hands-on examples, which ensures that the readers walk away with all the knowledge and skills they will need to harness Ansible.

"Ansible Configuration Management" starts with an explanation of the basics and builds the reader’s knowledge through step-by-step guidelines.

The book concentrates on discussions related to realistic worked examples. Using this approach we discuss how to perform ad-hoc actions, script actions together to set up services, and how to script more complicated tasks. The discussion carries onto explanation of organising your configurations for large deployments and warps up with examples of how to extend the capabilities of Ansible.

"Ansible Configuration Management" provides the knowledge you require to effectively manage your systems in a simple, quick, and maintainable way.

Publication date:
November 2013


Chapter 1. Getting Started with Ansible

Ansible is profoundly different from other configuration management tools available today. It has been designed to make configuration easy in almost every way, from its simple English configuration syntax to its ease of set up. You'll find that Ansible allows you to stop writing custom configuration and deployment scripts and lets you simply get on with your job.

Ansible only needs to be installed on the machines that you use to manage your infrastructure. It does not need a client to be installed on the managed machine nor does it need any server infrastructure to be set up before you can use it. You should even be able to use it merely minutes after it is installed, as we will show you in this chapter.

You will be using Ansible from the command line on one machine, which we will call the controller machine, and use it to configure another machine, which we will call the managed machine. Ansible does not place many requirements on the controller machine and even less on the managed machine.

The requirements for the controller machine are as follows:

  • Python 2.6 or higher

  • paramiko

  • PyYAML

  • Jinja2

The managed machine needs Python 2.4 or higher and simplejson; however, if your Python is 2.6 or higher, you only need Python.

The following are the topics covered in this chapter:

  • Installing Ansible

  • Configuring Ansible

  • Using Ansible from the command line

  • How to get help


Installation methods

If you want to use Ansible to manage a set of existing machines or infrastructure, you will likely want to use whatever package manager is included on those systems. This means that you will get updates for Ansible as your distribution updates it, which may lag several versions behind other methods. However, it doesn't mean that you will be running a version that has been tested to work on the system you are using.

If you run an existing infrastructure but need a newer version of Ansible, you can install Ansible via pip. Pip is a tool used to manage packages of Python software and libraries. Ansible releases are pushed to pip as soon as they are released, so if you are up to date with pip, you should always be running the latest version.

If you imagine yourself developing lots of modules and possibly contributing back to Ansible, you should be running a checked-out version. As you will be running the latest and least tested version of Ansible, you may experience a hiccup or two.


Installing from your distribution

Most modern distributions include a package manager that automatically manages package dependencies and updates for you. This makes installing Ansible via your package manager by far the easiest way to get started with Ansible; usually it takes only a single command. It will also be updated as you update your machine, though it may be a version or two behind. The following are the commands to install Ansible on the most common distributions. If you are using something different, refer to the user guide for your package or your distribution's package lists.

  • Fedora, RHEL, CentOS, and compatible: $ yum install ansible

  • Ubuntu, Debian, and compatible: $ apt-get install ansible


Installing from pip

Pip, like a distribution's package manager, will handle finding, installing, and updating the packages you ask for and its dependencies. This makes installing Ansible via pip as easy as installing from your package manager. It should be noted, however, that it will not be updated with your operating system. Additionally, updating your operating system may break your Ansible installation; however, this is unlikely. The following is the command to install Ansible via pip:

$ pip install ansible

Installing from the source code

Installing from the source code is a great way to get the latest version, but it may not be tested as correctly as released versions. You also will need to take care of updating to newer versions yourself and making sure that Ansible will continue to work with your operating system updates. To clone the git repository and install it, run the following commands. You may need root access to your system to do this:

$ git clone git://github.com/ansible/ansible.git
$ cd ansible
$ sudo make install

Setting up Ansible

Ansible needs to be able to get an inventory of the machines that you want to configure in order to manage them. This can be done in many ways due to inventory plugins. Several different inventory plugins are included with the base install. We will go over these later in the book, but for now we will cover the simple hosts file inventory.

The default Ansible inventory file is named hosts and placed in /etc/ansible. It is formatted like an INI file. Group names are enclosed in square braces, and everything underneath it, down to the next group heading, gets assigned to that group. Machines can be in many groups at one time. Groups are used to allow you to configure many machines at once. You can use a group instead of a hostname as a host pattern in later examples, and Ansible will run the module on the entire group at once.

In the following example, we have three machines in a group named webservers, namely site01, site02, and site01-dr. We also have a production group that consists of site01, site02, db01, and bastion.



Once you have placed your hosts in the Ansible inventory, you can start running commands against them. Ansible includes a simple module called ping that lets you test connectivity between yourself and the host. Let's use Ansible from the command line against one of our machines to confirm that we can configure them.

Ansible was designed to be simple and one of the ways the developers have done this is by using SSH to connect to the managed machines. It then sends the code over the SSH connection and executes it. This means that you don't need to have Ansible installed on the managed machine. It also means that Ansible can use the same channels that you are already using to administer the machine.

First, we check connectivity to our server to be configured using the Ansible ping module. This module simply connects to the following server:

$ ansible site01 -u root -k -m ping

This should ask for the SSH password and then produce a result that looks like the following code:

site01 | success >> {
  "changed": false,
  "ping": "pong"

If you have an SSH key set up for the remote system, you will be able to leave off the -k argument to skip the prompt and use the keys. You can also configure Ansible to use a particular username all the time by either configuring it in the inventory on a per host basis or in the global Ansible configuration.

To set the username globally, edit /etc/ansible/ansible.cfg and change the line that sets remote_user in the [defaults] section. You can also change remote_port to change the default port that Ansible will SSH to. These will change the default settings for all the machines, but they can be overridden in the inventory file on a per server or per group basis.

To set the username in the inventory file, simply append ansible_ssh_user to the line in the inventory. For example, the next code section shows an inventory where the site01 host uses the username root and the site02 host uses the username daniel. There are also other variables you can use. The ansible_ssh_host file allows you to set a different hostname and the ansible_ssh_port file allows you to set a different port; this is demonstrated on the site01-dr host. Finally, the db01 host uses the username fred and also sets a private key using ansible_ssh_private_key_file.

[webservers]      #1
site01 ansible_ssh_user=root     #2
site02 ansible_ssh_user=daniel      #3
site01-dr ansible_ssh_host=site01.dr ansible_ssh_port=65422      #4
[production]      #5
site01      #6
site02      #7
db01 ansible_ssh_user=fred ansible_ssh_private_key_file=/home/fred/.ssh.id_rsa bastion      #8

If you aren't comfortable with giving Ansible direct access to the root account on the managed machines, or your machine does not allow SSH access to the root account (such as Ubuntu's default configuration), you can configure Ansible to obtain root access using sudo. Using Ansible with sudo means that you can enforce auditing the same way you would otherwise. Configuring Ansible to use sudo is as simple as it is to configure the port, except that it requires sudo to be configured on the managed machine.

The first step is to add a line to the /etc/sudoers file; this may already be set up if you choose to use your own account. You can use a password with sudo, or you can use a passwordless sudo. If you decide to use a password, you will need to use the -k argument to Ansible, or set the ask_sudo_pass value to true in /etc/ansible/ansible.cfg. To make Ansible use sudo, add --sudo to the command line.


First steps with Ansible

Ansible modules take arguments in key value pairs that look similar to key=value, perform a job on the remote server, and return information about the job as JSON. The key value pairs allow the module to know what to do when requested. They can be hard coded values, or in playbooks they can use variables, which will be covered in Chapter 2, Simple Playbooks. The data returned from the module lets Ansible know if anything changed or if any variables should be changed or set afterwards.

Modules are usually run within playbooks as this lets you chain many together, but they can also be used on the command line. Previously, we used the ping command to check that Ansible had been correctly setup and was able to access the configured node. The ping module only checks that the core of Ansible is able to run on the remote machine but effectively does nothing.

A slightly more useful module is called setup. This module connects to the configured node, gathers data about the system, and then returns those values. This isn't particularly handy for us while running from the command line, however, in a playbook you can use the gathered values later in other modules.

To run Ansible from the command line, you need to pass two things, though usually three. First is a host pattern to match the machine that you want to apply the module to. Second you need to provide the name of the module that you wish to run and optionally any arguments that you wish to give to the module. For the host pattern, you can use a group name, a machine name, a glob, and a tilde (~), followed by a regular expression matching hostnames, or to symbolize all of these, you can either use the word all or simply *.

To run the setup module on one of your nodes, you need the following command line:

$ ansible machinename -u root -k -m setup

The setup module will then connect to the machine and give you a number of useful facts back. All the facts provided by the setup module itself are prepended with ansible_ to differentiate them from variables. The following is a table of the most common values you will use, example values, and a short description of the fields:






The architecture of the managed machine



The Linux or Unix distribution on the managed machine



The version of the preceding distribution



The domain name part of the server's hostname



This is the fully qualified domain name of the managed machine


["lo", "eth0"]

A list of all the interfaces the machine has, including the loopback interface



The kernel version installed on the managed machine



The total memory in megabytes available on the managed machine



The total CPUs available on the managed machine



Whether the machine is a guest or a host machine



The type of virtualization setup on the managed machine

These variables are gathered using Python from the host system; if you have facter or ohai installed on the remote node, the setup module will execute them and return their data as well. As with other facts, ohai facts are prepended with ohai_ and facter facts with facter_. While the setup module doesn't appear to be too useful on the command line, once you start writing playbooks, it will come into its own.

If all the modules in Ansible do as little as the setup and the ping module, we will not be able to change anything on the remote machine. Almost all of the other modules that Ansible provides, such as the file module, allow us to actually configure the remote machine.

The file module can be called with a single path argument; this will cause it to return information about the file in question. If you give it more arguments, it will try and alter the file's attributes and tell you if it has changed anything. Ansible modules will almost always tell you if they have changed anything, which becomes more important when you are writing playbooks.

You can call the file module, as shown in the following command, to see details about /etc/fstab:

$ ansible machinename -u root -k -m file -a 'path=/etc/fstab'

The preceding command should elicit a response like the following code:

machinename | success >> {
  "changed": false, 
  "group": "root", 
  "mode": "0644", 
  "owner": "root", 
  "path": "/etc/fstab", 
  "size": 779, 

Or like the following command to create a new test directory in /tmp:

$ ansible machinename -u root -k -m file -a 'path=/tmp/test state=directory mode=0700 owner=root'

The preceding command should return something like the following code:

machinename | success >> {
  "changed": true, 
  "group": "root", 
  "mode": "0700", 
  "owner": "root", 
  "path": "/tmp/test", 
  "size": 4096, 
  "state": "directory"

The second command will have the changed variable set to true, if the directory doesn't exist or has different attributes. When run a second time, the value of changed should be false indicating that no changes were required.

There are several modules that accept similar arguments to the file module, and one such example is the copy module. The copy module takes a file on the controller machine, copies it to the managed machine, and sets the attributes as required. For example, to copy the /etc/fstab file to /tmp on the managed machine, you will use the following command:

$ ansible machinename -m copy -a 'path=/tmp/fstab mode=0700 owner=root'

The preceding command, when run the first time, should return something like the following code:

machinename | success >> {
  "changed": true, 
  "dest": "/tmp/fstab", 
  "group": "root", 
  "md5sum": "fe9304aa7b683f58609ec7d3ee9eea2f", 
  "mode": "0700", 
  "owner": "root", 
  "size": 637, 
  "src": "/root/.ansible/tmp/ansible-1374060150.96-77605185106940/source", 
  "state": "file"

There is also a module called command that will run any arbitrary command on the managed machine. This lets you configure it with any arbitrary command, such as a preprovided installer or a self-written script; it is also useful for rebooting machines. Please note that this module does not run the command within the shell, so you cannot perform redirection, use pipes, and expand shell variables or background commands.

Ansible modules strive to prevent changes being made when they are not required. This is referred to as idempotency and can make running commands against multiple servers much faster. Unfortunately, Ansible cannot know if your command has changed anything or not, so to help it be more idempotent you have to give it some help. It can do this either via the creates or the removes argument. If you give a creates argument, the command will not be run if the filename argument exists. The opposite is true of the removes argument; if the filename exists, the command will be run.

You run the command as follows:

$ ansible machinename -m command -a 'rm -rf /tmp/testing removes=/tmp/testing'

If there is no file or directory named /tmp/testing, the command output will indicate that it was skipped, as follows:

machinename | skipped

Otherwise, if the file did exist, it will look as follows:

ansibletest | success | rc=0 >>

Often it is better to use another module in place of the command module. Other modules offer more options and can better capture the problem domain they work in. For example, it would be much less work for Ansible and also the person writing the configurations to use the file module in this instance, since the file module will recursively delete something if the state is set to absent. So, this command would be equivalent to the following command:

$ ansible machinename -m file -a 'path=/tmp/testing state=absent'

If you need to use features usually available in a shell while running your command, you will need the shell module. This way you can use redirection, pipes, or job backgrounding. You can pick which shell to use with the executable argument. However, when you write the code, it also supports the creates argument but does not support the removes argument. You can use the shell module as follows:

$ ansible machinename -m shell -a '/opt/fancyapp/bin/installer.sh > /var/log/fancyappinstall.log creates=/var/log/fancyappinstall.log'

Module help

Unfortunately, we don't have enough space to cover every module that is available in Ansible; luckily though, Ansible includes a command called ansible-doc that can retrieve help information. All the modules included with Ansible have this data populated; however, with modules gathered from elsewhere you may find less help. The ansible-doc command also allows you to see a list of all modules available to you.

To get a list of all the modules that are available to you along with a short description of each type, use the following command:

$ ansible-doc -l

To see the help file for a particular module, you supply it as the single argument to ansible-doc. To see the help information for the file module, for example, use the following command:

$ ansible-doc file


In this chapter, we have covered which installation type to choose, installing Ansible, and how to build an inventory file to reflect your environment. After this, we saw how to use Ansible modules in an ad hoc style for simple tasks. Finally, we discussed how to learn which modules are available on your system and how to use the command line to get instructions for using a module.

In the next chapter, we will learn how to use many modules together in a playbook. This allows you to perform more complex tasks than you could do with single modules alone.

About the Author

  • Daniel Hall

    Daniel Hall started as a systems administrator at RMIT University after completing his bachelor's in computer science in 2009. After spending 5 years improving deployment processes at realestate.com.au, he became the sole Systems Engineer at Melbourne lighting startup LIFX. Like many system administrators, he is constantly trying to make his job easier, and has been using Ansible to this effect. Daniel also wrote the first edition of this book.

    Browse publications by this author
Book Title
Unlock this book and the full library for FREE
Start free trial