Ansible is a tool for automating provisioning, configuration, and deployment in multiple hosts via SSH.

Installing Ansible on Ubuntu 20.04

sudo apt update -y
sudo apt install ansible -y

Installing Ansible on CentOS 8

yum update -y
yum install epel-release -y
yum install ansible -y

Add the hosts at the end of the file /etc/ansible/hosts:

[servers]
192.168.1.1
192.168.1.2 
192.168.1.3 
192.168.1.4 
[servers:vars]
ansible_user=root

Create and transfer the root’s SSH Key:

ansible all --list-hosts
ssh-keygen -t rsa -C "[email protected]"
ssh-copy-id 192.168.1.1
ssh-copy-id 192.168.1.2
ssh-copy-id 192.168.1.3
ssh-copy-id 192.168.1.4

Using ansible for simple commands:

ansible-inventory --list -y
ansible servers -m ping
ansible servers -a "apt update"
ansible servers -a "apt upgrade -y"
ansible all -m ping -u root

Check the list of all modules on Ansible online documentation [Link].

PLAYBOOK

nano playbook1.yaml

A PlayBook is composed of one or more Plays, and each Play contains one or more tasks.

Use the template and customize as necessary:

---
 
- name: PLAYBOOK ONE
  hosts: servers
  remote_user: root
  become: true

  pre_tasks:
  - name: APT UPDATE
    apt:
      update_cache: yes
    when: ansible_distribution == "Ubuntu" 


  tasks:
  - name: INSTALL LOCATE
    apt:
      name: locate
      state: latest

  - name: COPY FILE
    tags: webserver,apache
    copy:
      src: /data/site.html
      dest: /var/www/html/index.html
      owner: root
      group: root
      mode: 0644

  - name: START SERVICE
    service:
      name: cron
      state: started

  - name: REMOVE LOCATE
    apt:
      name: locate
      state: absent
    when: ansible_distribution in ["Debian","Ubuntu"]

  - name: INSTALL UNZIP
    package:
      name: unzip

  - name: DOWNLOAD AND EXTRACT A ZIP
    src: https://example.com/file.zip
    dest: /root
    remote_src: yes
    mode: 0755
    owner: root
    group: root

  - name: START SERVICE
    service:
      name: httpd
      state: started
      enabled: yes

  - name: CHANGE VARIABLE DATA IN FILE
    lineinfile:
      path: /etc/nginx/nginx.conf
      regexp: '^server_name'
      line: server_name example.com;
    register: webserver_admin_email

  - name: RESTART IF CONFIG CHANGED ABOVE
    service:
      name: nginx
      state: restarted
    when: webserver_admin_email.changed


- name: PLAYBOOK TWO - USERS MANAGEMENT
  hosts: all
  become: true
  tasks:

    - name: CREATE USER
      user:
        name: username
        groups: groupname

    - name: ADD SSH KEY
      user:
        name: username
        key: "copy and paste the key here"

Check first, then run the PlayBook:

ansible-playbook playbook1.yaml --check
ansible-playbook playbook1.yaml

The check mode (dry-run!) can be forced on a play by using the following option:

check_mode: yes

OR

check_mode: no

More useful command:

ansible all -m gather_facts
ansible all -m gather_facts --limit 192.168.1.1
ansible all -m apt -a update_cache=true --become --ask-become-pass
ansible all -m apt -a name=locate --become --ask-become-pass
ansible all -m apt -a "name=locate state=latest" --become --ask-become-pass
ansible all -m apt -a upgrade=dist --become --ask-become-pass

ROLES

The PlayBook can be broken into pieces or sections called roles to make the file easier to manage.

- name: ROLES THAT APPLY TO SERVERS
  hosts: servers
  become: true
  roles:
    - base_role
    - server_role

- name: ROLES THAT APPLY TO WORKSTATIONS
  hosts: workstations
  become: true
  roles:
    - base_role
    - workstation_role

HANDLERS

- name: CHANGE VARIABLE DATA IN FILE
  lineinfile:
    path: /etc/nginx/nginx.conf
    regexp: '^server_name'
    line: server_name example.com;
  notify: restart_nginx

File structure for Roles with Tasks and Handlers:

roles/
      base_role/
                tasks/main.yml
                handlers/main.yml
      server_role/
                  tasks/main.yml
                  handlers/main.yml
      workstation_role/
                       tasks/main.yml
                       handlers/main.yml

PLAYBOOK OPTIMIZATION

Using callback plugins to identify tasks that might be slowing down the playbook:

At ansible.cfg add the following line:

[defaults]
inventory = ./hosts
callbacks_enabled = timer, profile_tasks, profile_roles

The default parallelism (forks) number defines how many tasks are executed at the same time.

At ansible.cfg add the following line with the desired number:

[defaults]
inventory = ./hosts
forks=25

Or dynamically at the playbook execution:

ansible-playbook playbookName.yaml --forks 25

Optimize the SSH connections  by reusing the established connections for a defined period:

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=30s

In a controlled and dynamic environment, the host SSH key check can be disabled to increase performance by:

[defaults]
host_key_checking = False

To make the tasks run freely the servers (without waiting for all to finish each task before moving to the next):

---
- name: PLAYBOOK
  hosts: all
  strategy: free

 


PULL

Instead of push configuration to many servers from a manager host, Ansible makes it possible to pull a configuration file from a git repository and execute locally:

ansible-pull -U http://example.com/file.git

BONUS

Ansible does not offer a graphical interface but using it combined with Ansible Semaphore the user experience can be strongly improved [Link].