Ansible for Automated Ops & Maintenance: Deployment & Checklist
Tags: devops, productivity, automation, tooling
Published: 2024-03-19 19:20:08

## What is Automated Operations?

Automated Ops refers to the automation of a large number of repetitive tasks in daily operations. Manual tasks are converted into automated operations. Automation is the sublimation of IT operations work. IT operations automation is not simply a maintenance process, but also a process of management improvement. It is a higher level of operations and the development trend of the future.

## Problems Solved By Operations Automation

- Improves the overall work efficiency of projects;
- Reduces human errors;
- Facilitates information transmission, aggregates configuration information, and makes the information chain more complete;
- Leaves traces of transactions, making it easy to track and trace;
- Makes operations work easier and more flexible;
- Improves the value of operations work and manages more resources and service objects.

## Classification of Automated Operations Tools

- System installation: PXE, MetalLB, Terraform
- Application configuration: Puppet, Ansible, Saltstack
- Command execution and control: Fabric, Ansible
- Application release: git/svn (version management), Jenkins/Gitlab Runner (continuous integration)

## Comparison of Automated Operations Tools

Here we only compare Puppet, Ansible and Saltstack

|  | Puppet | Saltstack | Ansible |
|---------|--------|------------|---------|
| Development Language | Ruby language | Python language | Python language |
| Client Support | Yes | Yes (salt-ssh has no client) | No |
| Secondary Development Support | No | Yes | Yes |
| Communication Encryption | Standard SSL encryption | AES encryption | OpenSSH |
| Platform Support | AIX, BSD, HP-UX, Linux, Mac OSX, Solaris, Windows | BSD, Linux, Mac OS X, Solaris, Windows | AIX, BSD, HP-UX, Linux, Mac OS X, Solaris |
| Web UI | Yes | Yes | Commercial |
| Configuration File Syntax | Ruby syntax format | YAML | YAML |
| Command Line Execution | No (configuration implementation) | Yes | Yes |

## Ansible

[Ansible](https://www.ansible.com/) is an automation unified configuration management tool developed using Python. It is modular and relies on the ssh protocol for implementation. Automation is mainly reflected in the fact that Ansible integrates rich modules and functional components. A series of operations can be completed through one command, which can reduce repetitive work and maintenance costs, and improve work efficiency.

### Advantages of Ansible

- Simple installation and deployment (Ansible is installed on the master node, and no additional client needs to be installed)
- Implemented based on the existing ssh protocol (1.3 and above)
- Ansible has no daemon and does not need to be started
- Logs are centralized on the master node, which is convenient for troubleshooting
- Simple and easy to use, no programming foundation required
- Powerful functions through modules

### Ansible Architecture


![Ansible Architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2j09op5qxrul6xc8g4c1.png)


1. **Inventory:** Ansible's Inventory defines the scope of hosts that Ansible needs to operate on.

2. **Playbook:** Ansible's configuration file, which defines multiple tasks in the playbook, is automatically executed by Ansible.

3. **Core Modules:** Connect to the host to implement operations. It relies on specific modules to do specific things.

4. **Custom Modules:** Write specific modules according to your own needs.

5. **Connection Plugins:** Used to connect to the host and connect to the managed end.

6. **Plugins:** Complete the function supplement of the module.

> The most important point is: Ansible is modular, and all its operations depend on modules.

### Ansible Modes

There are two modes in Ansible: **ad-hoc mode** and **playbook mode**:

Ad-hoc: In short, it is a "temporary command" that will not be saved;

Playbook: Translated into a script, the execution process is saved in the file.

### Ansible Deployment

```console
sudo yum install ansible

[root@localhost ~]# ansible --version

ansible 2.9.27
  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, Aug  7 2019, 00:51:29) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
```

![terminal output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m3oblbtw2uy3ye675rc9.png)

#### Ansible Commonly Used Parameters

```console
-m : Specifies the name of the module to be used. If not specified, the command module is used by default.
-a : Specifies the module parameters and the specific actions of the module. It specifies the specific command to be executed.
--syntax-check: Checks the syntax.
```

#### Uncommonly Used Parameters

```console
--version: Displays the Ansible version information.
-v: Displays detailed information.
-i: Specifies the host inventory file path. The default path is /etc/ansible/hosts.
-k: Prompts you to enter the SSH password instead of using SSH-based key authentication.
-C: Simulates the execution test but does not actually execute it.
-T: Specifies the timeout for executing the command.
-f: Specifies the number of results to return at a time.
```

#### Ansible Help Commands

```console
ansible-doc: Help command
ansible-doc -l: Lists all modules
ansible-doc module_name: Displays detailed information about the module
ansible-doc module_name -s: Displays the usage instructions for the module options
```

#### Ansible Host Inventory

The host asset inventory is used to define the authentication information of the managed hosts, such as the SSH login username, password, and key information.

How to Check Ansible Configuration File Path:

```console
[root@localhost ~]# rpm -qc ansible
/etc/ansible/ansible.cfg
/etc/ansible/hosts
```
Host Inventory Location:

The default location is `/etc/ansible/hosts`.

Specify Host Inventory with -i:

```console
ansible -i /path/to/inventory_file command
```

Specify Default Host Inventory File in Ansible Configuration File:

The configuration file path is `/etc/ansible/ansible.cfg`.

Example:

```console
[defaults]
inventory = /path/to/inventory_file
```

In this example, Ansible will use `/path/to/inventory_file` as the default host inventory file.


**Ansible.cfg Common Configuration Analysis**

```cfg
[defaults]
#inventory = /etc/ansible/hosts     #Specifies the host list configuration file.
#library = /usr/share/my_modules/   #Specifies the directory where the library files are stored.
#remote_tmp = ~/.ansible/tmp        #Specifies the directory where temporary py files are stored on the remote host.
#local_tmp = ~/.ansible/tmp         #Specifies the local temporary execution directory.
#forks = 5                          #Specifies the default number of concurrent processes.
#sudo_user = root                   #Specifies the default sudo user.
#ask_sudo_pass = True               #Specifies whether to ask for the sudo SSH password each time it is executed.
#ask_pass = True                    #Specifies whether to ask for the SSH password each time it is executed.
#remote_port = 22                   #Specifies the remote host port.
host_key_checking = False           #Skips checking the host fingerprint.
log_path = /var/log/ansible.log     #Specifies the Ansible log file.

[privilege_escalation]
#become = True                      #Specifies whether to enable privilege escalation.
#become_method = sudo               #Specifies the privilege escalation method.
#become_user = root                 #Specifies the user to become after privilege escalation.
#become_ask_pass = False            #Specifies whether to ask for the sudo password after privilege escalation.
```

If `host_key_checking` and `log_path` are not configured, it will cause an error.
If `host_key_checking` is not configured, it will cause an error when executing the Ansible command:

```console
172.16.11.209 | FAILED | rc=-1 >>
Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host.
```

#### Host Inventory Configuration Rules

(Configured in `/etc/ansible/hosts`)

Host:

1. You can use the hostname (domain name) or IP address.
2. Supports hostname wildcards and regular expressions.
3. Supports different variables for different hosts, including password, port number, user, etc.

1. **Single Host Configuration**

```console
# Method 1: IP + Port + Username + User Password

[root@localhost ansible]# vim /etc/ansible/hosts 
[web01]
172.16.11.209 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='123123'
[web02]
172.16.10.232 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='123123'

# Test: ansible hostname -m module_name
[root@localhost ansible]# ansible web01 -m ping
172.16.11.209 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

[root@localhost ansible]# ansible web02 -m ping
172.16.10.232 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
```

![Terminal Output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k90volos0punonkyok4q.png)

If you encounter the following error:

![Console error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gm9vq2f0zcd19a8ihzca.png)

Enable these two in the ansible.cfg configuration file: 

```console
host_key_checking = False       #Skip checking host fingerprint
log_path = /var/log/ansible.log #ansible log
```

```console
# Method Two: IP + Username and Password
[root@localhost ansible]# vim /etc/ansible/hosts 
[web01]
172.16.11.209 ansible_ssh_pass='123123'
[web02]
172.16.10.232 ansible_ssh_pass='123123'

# Test: ansible hostname -m module_name
[root@localhost ansible]# ansible web01 -m ping
172.16.11.209 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
[root@localhost ansible]# ansible web02 -m ping
172.16.10.232 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

#When no user is defined, the current logged-in user is used by default.
```

![console output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6hzvcujrvsd73j9qhkfd.png)

2. **Multi-host Configuration**

```console
# IP + Port + Password
[root@localhost ansible]# vim /etc/ansible/hosts 
[web]
172.16.11.209 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='123123'
172.16.10.232 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass='123123'

# Test: ansible hostname -m module_name
[root@localhost ansible]# ansible web -m ping
172.16.10.232 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
172.16.11.209 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
```

![terminal output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vjj52j6yfcrcv6i3rva1.png)

Host group:

1. Nested [group name: children]

2. Define variables for the group [group name: vars]

```console
# Host Group Variables + Host + Password
[root@localhost ansible]# vim /etc/ansible/hosts 
[web_group]
172.16.11.209
172.16.10.232

[web_group:vars]
ansible_ssh_pass='123123'


# Test: ansible hostname -m module_name
[root@localhost ansible]# ansible web_group -m ping
172.16.10.232 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
172.16.11.209 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
```

```console
# Define multiple groups, nested groups

# The webservers group includes two subgroups [apache, nginx]
[root@localhost ansible]# vim /etc/ansible/hosts 
# Define total ip
[web_group]
172.16.11.209
172.16.10.232
172.16.10.129

# Two Apache servers
[apache]
172.16.11.209
172.16.10.232

# One Nginx server
[nginx]
172.16.10.129 ansible_ssh_pass='csnginx123'

# Define password
[apache:vars]
ansible_ssh_pass='123123'

[web_group:children]
apache
nginx



# Test: ansible hostname -m specify module
[root@localhost ansible]# ansible web_group -m ping
172.16.11.209 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
172.16.10.232 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
172.16.10.129 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

[root@localhost ansible]# ansible apache -m ping
172.16.11.209 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
172.16.10.232 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

[root@localhost ansible]# ansible nginx -m ping
172.16.10.129 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
```
In addition to using a password to connect, you can also configure a secret key for password free login. At this time, there is no need to specify a password in the host configuration file.

```console
1. Generate key pair
[root@localhost ansible]# ssh-keygen
 
2. Share public key
[root@localhost ansible]# ssh-copy-id 172.16.11.209
[root@localhost ansible]# ssh-copy-id 172.16.10.232
```