Ansible is an easy-to-use automation software that can update a server, configure tasks, manage daily server functions and deploys jobs as needed on a schedule of your choosing. It is usually administered from a single location or control server and uses SSH to connect to the remote servers. Because it employs SSH to connect, it is very secure and, there is no software to install on the servers being managed. It can be run from your desktop, laptop or other platforms to assist with automating the tedious tasks which every server owner faces.
Once it is configured, Ansible performs tasks based on an ordered list of assignments in what is called a Playbook. The Playbook outlines what tasks need to be run on the remote server and in what order. Once this is configured, Ansible acts like a bash for-loop command that allows a section of code to be repeated over and over again. The difference between using a bash command and Ansible is that Ansible is idempotent. The term Idempotent sounds a little scary, but it merely means that you can make the same type of request over and over again and unless something has changed, you will get the same result.
Source Server Requirements
Ansible requires the installation of Python 2.7 or Python 3.5 on the source server. The source server is where you will be running the tasks in the playbook for the remote servers. The remote servers receive commands defined in the playbook. A playbook is a file which defines the scripts that will be run on the remote servers.
Let’s start by installing Python on the source server.
root@test:~# apt-get install python
Target Server Requirements
The only requirement from the target server is an open SSH port. Access can also be granted for scp (secure copy) and/or SFTP connections if configured in the /etc/ansible/ansible.cfg file.
Install Ansible On Ubuntu 16.04
To install Ansible on a source Ubuntu server, let’s follow these steps:
root@test:~# apt-get update root@test:~# apt-get install software-properties-common root@test:~# apt-add-repository ppa:ansible/ansible root@test:~# apt-get update root@test:~# apt-get install ansible (install text)After this operation, 42.0 MB of additional disk space will be used. Do you want to continue? [Y/n] y
Answer “Y” to the prompt. The install will complete and take you back to the command prompt. Now, let’s check the version of Ansible installed.
Check Ansible Version
root@test:~# ansible --version ansible 2.7.0 config file = /etc/ansible/ansible.cfg configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python2.7/dist-packages/ansible executable location = /usr/bin/ansible python version = 2.7.12 (default, Dec 4 2017, 14:50:18) [GCC 5.4.0 20160609]
As an alternative, you can also install Ansible on your CentOS 7 server.
Ansible also can be installed on RedHat, Debian, MacOS, and any of the BSD flavors!
Install Ansible on CentOS 7
In order to install Ansible on a source CentOS 7 server, follow these steps.
First, we need to make sure that the CentOS 7 EPEL repository is added:
[root@test ~]# cat /etc/redhat-release CentOS Linux release 7.5.1804 (Core)
[root@test ~]# yum install epel-release Loaded plugins: fastestmirror, priorities, universal-hooks Loading mirror speeds from cached hostfile … ... Resolving Dependencies --> Running transaction check ---> Package epel-release.noarch 0:7-11 will be installed --> Finished Dependency Resolution Dependencies Resolved ========================================================================= Package Arch Version Repository Size ========================================================================= Installing: epel-release noarch 7-11 system-extras 15 k Transaction Summary ========================================================================= Install 1 Package Total download size: 15 k Installed size: 24 k Is this ok [y/d/N]: y Downloading packages: epel-release-7-11.noarch.rpm | 15 kB 00:00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : epel-release-7-11.noarch 1/1 Verifying : epel-release-7-11.noarch 1/1 Installed: epel-release.noarch 0:7-11 Complete!
Select “y”. The EPEL repo will then be added. Once the repository is enabled, we can install Ansible with yum:
root@test:~# yum install ansible Loaded plugins: fastestmirror, priorities, universal-hooks Loading mirror speeds from cached hostfile epel/x86_64/metalink | 18 kB 00:00:00 * EA4: 220.127.116.11 * cpanel-addons-production-feed: 18.104.22.168 * epel: mirrors.liquidweb.com epel | 3.2 kB 00:00:00 (1/3): epel/x86_64/group_gz | 88 kB 00:00:00 (2/3): epel/x86_64/updateinfo (3/3): epel/x86_64/primary | 3.6 MB 00:00:00 epel 12756/12756 Resolving Dependencies … (dependencies check) Dependencies Resolved ======================================================================== Package Arch Version Repository Size ======================================================================== Installing: ansible noarch 22.214.171.124-2.el7 system-extras 7.6 M Installing for dependencies: 21 k Transaction Summary ======================================================================== Install 1 Package (+17 Dependent packages) Total download size: 12 M Installed size: 58 M Is this ok [y/d/N]:
Select “y” to start the Ansible install:
Is this ok [y/d/N]: y … Downloading 18 packages: --------------------------------------------------------------- Total 30 MB/s | 12 MB 00:00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction … (installing 18 python related software) ... Installed: ansible.noarch 0:126.96.36.199-2.el7 Dependency Installed: ... (dependencies verified) Complete!
Check Ansible Version on CentOS 7
Now, let’s verify the version installed:
root@test ~]# ansible --version ansible 188.8.131.52 config file = /etc/ansible/ansible.cfg configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python2.7/site-packages/ansible executable location = /usr/bin/ansible python version = 2.7.5 (default, Jul 13 2018, 13:06:57) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
Setting Up Ansible Connections
Initially, we will be adding server names or IP’s to the /etc/ansible/hosts file to identify which “ungrouped” servers and “groups” of servers we are going to be connecting to. We mention ungrouped and grouped in this specific order because this is the way the Ansible hosts file is usually arranged.
We can use any name we like for the hosts file itself but typically it is just called hosts. Ansible also states that the hosts file can also be identified as an inventory file and, you can have multiple inventory files.
Let's start by opening the hosts file with vim and inserting some entries into the file.
root@test:~# vim /etc/ansible/hosts
Here is what the default hosts file will look like:
# This is the default ansible 'hosts' file. # # It should live in /etc/ansible/hosts # # - Comments begin with the '#' character # - Blank lines are ignored # - Groups of hosts are delimited by [header] elements # - You can enter hostnames or ip addresses # - A hostname/ip can be a member of multiple groups # Example 1: Ungrouped hosts, specify before any group headers. #green.example.com #blue.example.com #192.168.100.1 #192.168.100.10 # Example 2: A collection of hosts belonging to the 'webservers' group #[webservers] #alpha.example.org #beta.example.org #192.168.1.100 #192.168.1.110 # If you have multiple hosts following a pattern you can specify # them like this: #www[001:006].example.com # Example 3: A collection of database servers in the 'dbservers' group #[dbservers] # #db01.intranet.mydomain.net #db02.intranet.mydomain.net #10.25.1.56 #10.25.1.57 # Here's another example of host ranges, this time there are no # leading 0s: #db-[99:101]-node.example.com
As you can see, there are individual servers “#green.example.com”, and groups like #[webservers] which have multiple servers under the group and, another section with multiple servers listed like #db-[99:101]-node.example.com which identifies all of the individual servers from 99-101; eg.
#[webserver1] #alpha.example.org #beta.example.org #192.168.1.100 #192.168.1.110gamma.example.com
Now, simply save the file using :wq.
You can set up public SSH keys from the control server to log in to those remote servers noted in the hosts file. In this case, you simply want to make sure your local SSH keys are located in the /root/.ssh/authorized_keys file on the remote systems. (Depending on your setup, you may wish to use Ansible’s --private-key option to specify a .pem file instead)
Verify Ansible Connections
The ansible inventory file (/etc/ansible/hosts) contains the server names you will have control over and can run tasks against. To verify Ansible’s connectivity, run:
ansible remote -m ping
Ansible playbooks (also called inventory files) define the tasks ran on the remote servers. You can have one playbook or multiple playbooks to accomplish different tasks on different servers. To easily apply a task to all of the servers in a pool, use the ‘group’ name to apply the task for that group (using the example above, you would use the [webserver1] in the command.
Create a Playbook
Step 1: In order to create a playbook, let’s create a new file in the /etc/ansible/playbooks/ folder:
mkdir -p /etc/ansible/playbooks/ && touch /etc/ansible/playbooks/playbook.yml && vim /etc/ansible/playbooks/playbook.yml
Step 2: Let's add a server and file entry into the playbook filer:
(Click the insert key to open VIM’s edit access on the file)
- hosts: gamma.example.com tasks: - name: Create file file: path: /tmp/test.txt state: touch
Once we have added the entry, let’s save the file using :wq.
Step 3: Now, to set up 0644 permissions on that file, we can reopen it and add another line defining the permission set.
- hosts: gamma.example.com tasks: - name: Create file file: path: /tmp/test.txt state: touch mode: "u=rw,g=r,o=r"
Again, let’s save the file using:wq.
Step 4: Next, let’s create a folder and then place a text file in it using Ansible. We will add another section defining the element needed.
- hosts: gamma.example.com Tasks: - name: Create folder path: /home/tmp/ state: directory mode: 0755 - name: Create file file: path: /home/tmp/test.txt state: touch mode: "u=rw,g=r,o=r"
Once we have added this entry, save the file using:wq.
Running a Playbook
To start a playbook, simply run:
Or if you have multiple playbooks in a folder, can run a specific playbook using the -i <path> option from the command line:
ansible-playbook -i /etc/ansible/playbooks/playbook1.yml
Schedule a Playbook Using Cron
As an additional option, you can schedule a playbook to run at a specific time using your servers cron command! To accomplish this, log in to your server as root and run the following command:
This command opens a temporary cron file in your system’s default text editor and then simply add a line like so:
0 4 * * * /usr/bin/ansible-playbook /etc/ansible/playbooks/playbook.yml
This will run the/etc/ansible/playbooks/playbook.yml file at 0400 a.m. using the ansible-playbook command.
Troubleshooting A Playbook
Sometimes, a set of commands in the playbook file may fail. If it does, you have several options to address this. Generally, playbooks will simply stop completing the commands in the playbook. If this occurs, you can define a follow-up task in the playbook to overlook the error by adding another section like so:
- name: ignore this error command: /bin/false ignore_errors: yes
this command will only work when the task is run but returns a "failed" value.
If Ansible fails to connect to a server, it will set the host as being ‘UNREACHABLE’. This effectively removes the server temporarily from the list of active hosts for that task. To correct this, we can use an entry to reactivate them and have all current hosts previously indicated as being unreachable cleared, so subsequent tasks can use the playbook again.
Handlers and Failure
A handler is simply a specially named task that runs when told to by another task. Handlers are executed at the end of the playbook by default as opposed to other tasks, which are executed immediately when defined within the playbook. This behavior can be modified by using the
command-line option, or by including
in a playbook, or adding
force_handlers = True
in the ansible.cfg file.
If you want to force a handler to run in the middle of two separate tasks instead of at the end of the playbook, you will need to add this entry between the two tasks:
- meta: flush_handlers
When handlers are “forced” like this, they will run when notified even if a task fails on that host.
Handlers will only be visible in the output if they have actually been executed. Also, handlers are only fired when there are changes made by a task. For example, a task may update a specific configuration file and then notify a handler to restart a service. If a task in the same playbook fails later on, the service will not be restarted despite the previous configuration change.
Overall, Ansible is an indispensable tool for managing and administrating a single server or an entire group of geographically diverse servers.
Our Sales and Support teams are available 24 hours by phone or e-mail to assist.