Image taken from the RedHat Blog
In this post, we will introduce Ansible: a tool for configuring multiple machines remotely. Once we’ve covered what Ansible is, we will set up a target environment using Docker and SSH. We will then use Ansible to install and setup an nginx server. This will demonstrate how Ansible works, and its key features.
What is Ansible?
Ansible is a configuration tool that allows us to define and remotely apply a desired state to managed nodes. This means we can configure a number of machines easily, with confidence that these machines are as expected.
Ansible is agent-less, meaning that it doesn’t need anything other than SSH to work. It is also idempotent, meaning that if no changes are needed, Ansible knows not to do anything.
Playbook
A Playbook is a YAML file that tells Ansible how to configure the targets.
It consists of “Plays”, which describes which “Tasks” should apply to which Nodes.
A Task is an operation that Ansible should perform.
In a Playbook, we refer to Nodes as “hosts”.
Tutorial
Creating the target machine
This step is to give us something to target. You can use any linux machine with SSH to target, but using a Docker container gives us a quick and easy way of testing out Ansible.
⚠️ For simplicity’s sake, we will use the root user and an SSH password, but this isn’t considered best practices, and shouldn’t be done in a real system.
First, ensure you have docker installed
If you don’t, you will need to install it before continuing.
Let’s spin up a ubuntu Docker container, and use sleep infinity to keep the container running until we stop it.
We’ll also map the container’s port 80 to our host machine’s port 8080. This will allow us to communicate the nginx server we will install.
Log into the VM to setup SSH
Inside the container:
We will also allow SSH access to the root user. Once again, this is generally a bad idea, but for our example it will be OK.
Add these lines to this config:
Close the file, and then run this to start SSH server
Press Ctrl+D to exit Docker.
Setup Ansible on your local machine
Now we are out of our container, we need to setup Ansible locally.
Get the container’s IP:
You should see an IP like 172.17.0.2. Note this down, as we will need it later.
Install sshpass to allow us to use password with SSH.
Create a hosts file with the content. Change the IP and password as needed.
Run this command to check that Ansible can communicate with the container.
You should see a Pong from the container. This verifies that Ansible is working, and it can connect to the container. As we did not install anything on the container, it shows us that Ansible is agent-less: it works with only SSH access.
If you receive an error at this step, go to the Troubleshooting section
Creating a Playbook
Now we’ll define the state that we want the managed node to be in, which we will use Ansible to enforce.
Create a file called setup-nginx.yml.
This is our Playbook: It contains a single Play which targets our single managed node: ‘test’. It contains a single Task, with the human readable name “Ensure nginx is installed”. This uses apt to check that nginx is present, and will install it if not. update_cache: yes ensures that Ansible updates its local database of available packages before installing the package (similar to running apt update yourself). The become: yes line tells Ansible to use escalated privileges, as they are needed to install nginx.
Applying a Playbook
Once we have created a simple Playbook, we can apply it with
You should then see output like this
We can see that Ansible has changed the target machine, and also installed a missing dependency! How useful.
If we then run the command again
The output shows that Ansible has checked, and knows that no changes are made. (changed=0)
This shows us that Ansible is idempotent: it won’t make changes that aren’t needed.
To test our nginx server, we can try to connect to it with
However, we receive the error curl: (56) Recv failure: Connection reset by peer.
This is because the server isn’t running! We can either SSH in and start it… or update our Ansible config to start the server.
Modifying a Playbook
Edit setup-nginx.yml to look like this:
This now both installs and ensures the server is running. Again, if the service isn’t running, then Ansible knows to start it.
We can now apply this new config
In the output, we can see that once again nginx is already installed, but we see another task that starts the nginx server.
And now if we try to access the server again with
We see a response!
We can also see this if we use a browser to access localhost:8080:
Tidy up
Finally, stop the container with
If you wanted, you could also uninstall the packages we installed on your local machine:
- ansible
- sshpass
Conclusion
After setting up a test environment (a Docker container with SSH enabled), we have seen how to
- Install Ansible
- Add a host
- Write a Play
- Idempotently apply the Play
- Apply a modified play
- Verified that our changes were made successfully.
Of course, we’ve only brushed the surface of Ansible’s capabilities. You can read about inventories, roles, and templates on the Ansible documentation.
Troubleshooting
Permission Denied when trying to ping the container
If you receive a “Permission denied” error while trying to ping the container, ensure you have configured SSH as described. Remember to:
- Edit /etc/ssh/sshd_config on the container as described
- Restart the SSH service after modifications
- Install sshpass on your local machine
If this doesn’t work, make sure the password in the hosts file is correct.
Fingerprint Error when trying to ping the container
This is likely because the fingerprint was generated for an old container. If you think it’s safe, you can run this command to accept the new fingerprint: