Automate management with Ansible


Automate management with Ansible

In the previous article, we examined in sufficient detail the issues related to the automation of management and software configuration in medium and large networks. We reviewed Vagrant and the basic methods of working with virtual infrastructure. In this article, we will talk in detail about using such an interesting tool as Ansible.

This solution allows you to automate the deployment and configuration of resources on the network, the preparation of containers and virtual machines, and much more. The Ansible application itself operates in what is known as push mode. All work with the infrastructure is carried out from the management server. And from this machine, settings are applied to managed nodes.

This article will not have long introductions about why Ansible is needed at all, how it differs from other similar solutions, and so on. Instead, I suggest going straight to practice and deploying the required test environment.

First, we will need to deploy the Ansible control server. As OS I will use Ubuntu 22.04. After doing the upgrade and update, run the following command:

Installation should not cause any difficulties. After its completion, we will receive a control node with all the necessary software for administering target nodes. As real DevOps, we will work through the console and first we need to make changes to the inventory file /etc/ansible/hosts. This file contains information about the hosts that we will manage, configuration parameters and variables.

As an example, let’s write two servers .150 and .137 into this file. We will also write the path to the Python interpreter.

[servers]

server1 ansible_host=192.168.222.150

server2 ansible_host=192.168.222.137

[all:vars]

ansible_python_interpreter=/usr/bin/python3

With this parameter value, the remote server uses the /usr/bin/python3 Python 3 executable, which may not be present in some versions of Ubuntu.

About Authentication

With default settings, Ansible attempts to connect to all nodes using SSH and key authentication. However, it is not always possible to authenticate with keys, and as an alternative, you can specify a password when connecting. But to use password authentication, you must first install the sshpass utility on the Ansible control server:

However, passwords are not the best security mechanism and SSH keys are more secure. To set up key authentication. To do this, perform the following steps:

On the Ansible control server, display the public key in the terminal:

If there is no such file, you can create it:

Next, you need to go to the client machine, go to the root session and open the file nano ~/.ssh/authorized_keys and put the public key of the management server into it:

To check the results of the configuration, we will find out which kernel versions are on the managed machines.

We use playbooks

We have learned how to execute commands on managed servers and receive responses from their operating systems. However, this is clearly not enough for true automation. This is where playbooks come to the rescue – the basic components that record and execute the Ansible configuration, which allows you to truly automate the execution of tasks on managed machines.

A little about terminology. Recently, there has been a tendency to abandon English terms, therefore, in some sources, especially those related to information security, you can find the replacement of the foreign word “playbook” with the Russian counterpart – a response map. However, in this article, we will use the term playbook.

So, what is a playbook: in fact, it is a set of scripts that are executed in a given order. A script is a list of tasks for a specific group of hosts.

The tool for creating playbooks is the YAML language. When writing scripts, indentation is of great importance, which must be done only with spaces, TAB cannot be used. Identical elements should also have the same indents. Here is an example of Hello world in Ansible:

– hosts: all

tasks:

– name: Print message

debug:

msg: Hello Ansible World

In this script, we are targeting all hosts in our hosts file. The name of the task is Print message, and the output of the Hello Ansible World message.

Let’s save this playbook to a file and run it for execution.

Task completed successfully. If we need to execute the playbook on only one managed node, we must specify the –limit parameter and the name of this node specified in the hosts file.

Next, let’s look at working with variables in Ansible. In the following example, we will work with two types of variables at once: Ansible’s built-in variable and the one defined in our playbook.

Before the beginning of the block of variables defined in the playbook, we specify vars:, then we specify the variables themselves and their values. In our example, we define a txt variable with a value of IP_address. In the tasks block, in the msg section, variables are specified in double curly braces, indented on each side. First we specify our txt variable and then the inline variable ansible_default_ipv4.address. You do not need to define this variable, as it is already defined in Ansible itself.

– hosts: all

vars:

txt:IP_address

tasks:

– name: print facts

debug:

msg: “{{ txt }}: {{ ansible_default_ipv4.address }}”

Let’s save the created file and execute the playbook for all nodes.

Playbooks allow us to use conditions, that is, we can endow our scripts with certain execution logic. For example, let’s say we need to check for the presence of a certain file on the nodes and, if it does not exist, create this file.

To do this, we first define the variables user and file_name

vars:

-user:otus

– file_name:test1

Then run the ls command

command: ls /home/{{ user }}/{{ file_name }}

Next, we use the register keyword, which creates a new variable file_exists and assigns the output from the command to it.

One important thing to note is that, by default, Ansible aborts the playbook if the command you use to evaluate the condition fails. For this reason, we use the ignore_errors directive set to yes, and this will cause Ansible to move on to the next task and continue.

register: file_exists

ignore_errors: yes

In Ansible, you can define conditions that will be evaluated before the task is executed. When the condition is not met, the task is skipped. This is done with the when keyword, which accepts expressions that are usually based on a variable or fact.

Next, if fail_exists is set to failed, we create a new file.

– name: create file for user

file:

path: /home/{{ user }}/{{ file_name }}

state:touch

when: file_exists is failed

If the file already exists, we simply print the appropriate message:

– name: show message if file exists

debug:

msg: The user file already exists.

when: file_exists is succeeded

The following is the full text of the entire playbook:

– hosts: all

vars:

-user:otus

– file_name:test1

tasks:

-name: Check if file already exists

command: ls /home/{{ user }}/{{ file_name }}

register: file_exists

ignore_errors: yes

– name: create file for user

file:

path: /home/{{ user }}/{{ file_name }}

state: touch

when: file_exists is failed

– name: show message if file exists

debug:

msg: The user file already exists.

when: file_exists is succeeded

Let’s run our playbook for execution:

As you can see, at the first launch, we received curses about the absence of a file with that name. However, all of these messages were successfully ignored and script execution continued.

When restarting the playbook:

We get messages that the files already exist.

Loops in Ansible

Another important task of automation is the need to repeat the same task, using different values. For example, you may need to change permissions on multiple files or create multiple users. To avoid repeating a task multiple times in your playbook file, it’s best to use loops for this.

In the following example, we declare the value ansible in the file_name variable, then create files with names containing the value file_name and, hyphenated, the value of one of the variables inside the loop.

– hosts: all

vars:

-user:otus

– file_name: ansible

tasks:

– name: creates user files

file:

path: /home/{{ user }}/{{ file_name }}-{{ item }}

state:touch

loop:

-test10

-test20

-test30

Let’s run the resulting playbook:

As a result of the script, we get three files with names that match the given pattern:

Conclusion

In this article, we covered the main points related to installing Ansible and performing basic tasks. But this is only a small part of what this system can do, for example, managing nodes under Windows, raising privileges, installing updates, and much more is left behind the scenes. So we will definitely return to the consideration of using Ansible.

I would also recommend to everyone free lesson DevOps practices and tools course from OTUS, where my colleagues will talk about 3 basic principles of infrastructure security. There will be a demo in the lesson, where OTUS experts will analyze one problem on the infrastructure – a very interesting Diffie-Hellman protocol using the example of large numbers with reference to elliptic curves and cryptography. The teacher will show how the algorithm works and how to fix the problem associated with it in nginx.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *