Hostman Blog
Infrastructure

Ansible: What It Is and How to Use It

26 Sep 2025
Hostman Team
Hostman Team

Ansible is an open-source tool used for automating tasks related to management, configuration, and maintenance of servers or network devices.

Official website and documentation: https://docs.ansible.com/

How Ansible Works
Copy link

So, what does Ansible do? It connects to selected nodes (hosts) from your inventory and sequentially executes tasks to bring them into the desired state.

  • playbook: a file describing tasks and their sequence
  • task: a task, a single action for verification or execution
  • inventory: grouping and list of managed nodes (hosts)

Advantages
Copy link

  • The simplest yet most powerful automation tool
  • Does not require additional software installed on managed nodes (only Python is needed, which usually comes “out of the box”)
  • Uses the standard SSH protocol for connections
  • Only necessary changes are applied
  • Operations can be safely re-run (the system won’t make redundant changes)
  • Ensures consistent system state
  • Allows clear and convenient infrastructure descriptions

In addition, Ansible has a large community that develops and supports various modules.

Where Is Ansible Used?
Copy link

Main use cases:

  • System preparation and configuration
  • Automated software deployment, package and service management
  • Automation of CI/CD processes
  • Network device configuration (network management)
  • System auditing, applying security policies, and automatic compliance enforcement

It’s important to understand that Ansible is just a tool. Choosing the right tool depends on the task at hand. For example, theoretically, you can use Ansible to manage Kubernetes (k8s) configurations, but there are better tools for that purpose: Helm, helmwave, and kustomize.

Another example: with Ansible, you can create virtual machines and containers in clouds or hypervisors, but Terraform is better suited for such tasks.

Installing Ansible
Copy link

Ansible can be installed as a standalone package or via Python libraries.

Installation instructions for different operating systems are available in the documentation.

For installation, the following VPS at Hostman is sufficient:

  • OS: Ubuntu 24.04
  • CPU: 1 × 3.3 GHz
  • RAM: 1 GB
  • NVMe: 15 GB

Ansible Configuration Settings: Key Files and Parameters
Copy link

Configuration File
Copy link

Path to the configuration file:

/srv/ansible/ansible.cfg

Example configuration:

[defaults]
inventory = ./hosts.yaml
host_key_checking = False
log_path = /var/log/ansible.log
vault_password_file = ./vault.key
force_color = 1
callback_result_format = yaml

[ssh_connection]
timeout = 10
retries = 2
server_alive_interval = 60
pipelining = True
ssh_args = "-o StrictHostKeyChecking=no"
scp_if_ssh = True
allow_world_readable_tmpfiles = True

Section [defaults]

  • inventory = ./hosts.yaml: specifies the path to the hosts file. This file stores information about all managed hosts and organizes them into logical groups.

  • host_key_checking = False: by default, Ansible enables host key checking. Host key checking protects against server spoofing. Not recommended in production, but convenient for development.

  • log_path = /var/log/ansible.log: path to the log file.

  • vault_password_file = ./vault.key: path to the master password file, used for Ansible Vault encryption.

  • force_color = 1: enables colored logs for readability.

  • callback_result_format = yaml: formats output results as YAML.

Some parameters can be set as environment variables, for example:

ANSIBLE_HOST_KEY_CHECKING=False
ANSIBLE_FORCE_COLOR=1

Other parameters, such as inventory or vault_password_file, can be set in the command line when launching:

ansible-playbook ansible/debug.yaml -i ansible/hosts.yaml

But it is more convenient and clearer to store basic settings in the file ansible/ansible.cfg.

Ansible Inventory: Managing Hosts
Copy link

To manage hosts, the file ansible/hosts.yaml is used.

Example:

all:
  vars:
    ansible_user: ansible
  hosts:
    5.181.182.204: # your host IP or domain
      ansible_user: root
      # ansible_password: 'SuperPass'
      ansible_ssh_private_key_file: ./ansible/ssh/id_rsa

As connection points, you can use either an IP address or a domain name. In this example, there is no domain name, so we specify the external IP address obtained when creating the Hostman VM.

Note: the user password must be enclosed in quotes.

Connections usually use either a password or a certificate (public key must be pre-installed on remote nodes).

For experiments, it’s easier to use a password. When using a private key, you must check file permissions for id_rsa; only the owner should have read access; no one else can copy or modify the key:

chmod -R 400 ./ansible/ssh/id_rsa

In the file ansible/hosts.yaml, the variable vars.ansible_user is set for demonstration. Inside hosts.ansible_user, the same variable is redefined as root. If you don’t override it and only define it at the higher vars level, you can avoid duplicating common variables across different hosts.

Basic Commands and Usage Examples
Copy link

Let’s start with simple tasks that don’t make changes to the system but help to understand the structure of commands.

For example, we have the ansible/debug.yaml file, a simple playbook example.

Run it:

ansible-playbook ansible/debug.yaml

In the output, we’ll see various system information and go through the commands from the file ansible/debug.yaml in order:

- hosts: all
  vars:
    my_variable: aaaawww

  tasks:
    - name: Show ansible variable
      debug:
        msg: "variable: {{ my_variable }}"

    - name: Show environment variable
      debug:
        var: lookup('env', 'ANSIBLE_CONFIG')

    - name: Show OS release info
      debug:
        msg: "{{ ansible_distribution }} {{ ansible_distribution_version}} {{ansible_distribution_release}}"
  • hosts: defines which nodes (hosts) to run commands on. Since we specified only one host in ansible/hosts.yaml, all tasks will be executed on that host.

  • vars: allows us to set variables at the playbook level.

  • tasks: sequence of tasks to run.

Output of the variable set in vars:

- name: Show ansible variable
  debug:
    msg: "variable: {{ my_variable }}"

Output of an environment variable:

- name: Show environment variable
  debug:
    var: lookup('env', 'ANSIBLE_CONFIG')

Output of OS and hardware info:

- name: Show OS release info
  debug:
    msg: "{{ ansible_distribution }} {{ ansible_distribution_version}} {{ansible_distribution_release}}"

- name: Show total CPU + RAM
  debug:
    msg: |
      CPU cores: {{ ansible_processor_cores * ansible_processor_count }}
      Total memory: {{ ansible_memtotal_mb }} MB

Where does Ansible get this data?

By default, unless gather_facts: false is set, Ansible automatically collects system information when connecting to a host.

To view all collected information, you can use this task:

tasks:
  - name: Show all facts
    debug:
      var: ansible_facts

Each task is described using a module and its parameters:

  • name: task name (arbitrary)

  • debug: name of the module (from the list of available ones, depending on goals)

  • debug.var: module parameter

In the documentation, you may also see examples like:

tasks:
  - name: Show all facts
    ansible.builtin.debug:
      var: ansible_facts

ansible.builtin.debug is the same as the debug module (the ansible.builtin prefix can be omitted).

debug and other standard modules are part of Ansible’s core. All built-in modules can be found in the documentation.

apt Module (Debian/Ubuntu Package Manager)

See Documentation for the module.

- name: Install packages
  apt:
    pkg:
      - htop
      - curl

Even without documentation, it’s clear that this task will install the htop and curl packages (equivalent to apt install -y htop curl).

Checking Variables with when and assert

Goal: Check that the variable my_age contains a number between 18 and 100.

- name: Check var
  hosts: all
  vars:
    my_age: 42

  tasks:
    - name: Checking the type of a variable
      fail:
        msg: "The variable must be an integer"
      when: my_age is not integer

    - name: The value of the my_age variable must be between 18 and 100
      assert:
        that:
          - my_age <= 100
          - my_age >= 18
        fail_msg: "Incorrect my_age value - must be from 0 to 100"
        success_msg: "The value of my_age is correct"
  • At the start, the variable my_age = 42 is set.

  • The first task checks with when if it’s actually an integer; if not, the playbook stops with an error.

  • The second task checks if the value is within the range.

If you run the playbook, it will succeed. But if you override the variable in the launch command:

ansible-playbook ansible/playbooks/assert.yaml --extra-vars "{ my_age: 769 }"

You’ll get an error and the playbook will stop:

TASK [The value of the my_age variable must be between 18 and 100] **************
fatal: [5.181.182.204]: FAILED! =>
    assertion: my_age <= 100
    changed: false
    evaluated_to: false
    msg: Incorrect my_age value - must be from 0 to 100

Loops

Loops in Ansible look like this:

- hosts: all

  tasks:
    - name: Register loop output as a variable
      shell: "echo {{ item }}"
      loop:
        - "test"
        - "test2"
        - "test3"
      register: echo

In this task, the echo command will run for each element in the loop list.

Additional functions:

  • map: a basic for loop; iterates over list items.

  • select / reject: conditional for; creates a subset of a list matching (or not matching) conditions.

  • selectattr / rejectattr: similar, but works on specific attributes of list elements.

Ansible selectattr: Filtering Data in Playbooks

Example: select only red fruits from a list using selectattr.

- hosts: all
  vars:
    fruits_list:
      - name: apple
        color: red
      - name: banana
        color: yellow
      - name: cherry
        color: red

  tasks:
    - name: Selectattr show red fruits
      debug:
        msg: "{{ item.name }} is red."
      loop: "{{ fruits_list | selectattr('color', '==', 'red') | list }}"

copy Module

Playbook: ansible/playbooks/copy.yaml

See Documentation for the module.

- name: Copy files to remote locations
  hosts: all

  tasks:
  - name: Copy file with owner and permissions
    copy:
      src: ../files
      dest: /tmp
      owner: root
      group: root
      mode: '0644'

This task copies the directory from ansible/files to /tmp/files on the remote host.

If src is a directory, it is copied recursively. If the path ends with /, only the contents are copied into the destination. This behavior is similar to rsync.

To copy files from a remote host back to local, use the fetch module (see documentation).

template Module

See Documentation for the module.

Templates let you create dynamic files by inserting variable values. Ansible uses the Jinja2 templating engine.

Example template file ansible/files/simple_template.j2 (not required to use .j2 extension, but recommended):

# This is a simple example of using a template.

name: {{ name }}
task: {{ task }}

Playbook using the template:

- name: Template a file out to a target host
  hosts: all

  tasks:
    - name: Simple template a file
      template:
        src: ../files/simple_template.j2
        dest: /tmp/test.conf
      vars:
        name: "Ansible"
        task: "Template"

As the result, the remote host receives the file with substituted variables.

0a2ae01e 1080 419a B5ad 41595af8de51.png

You may want to check an online service for creating and testing templates: tech-playground.com.

8c6a99c5 53d3 4fc4 914a 50c075bcc91e.png

Ansible Web UI
Copy link

The main way to run and use Ansible is the command line, but there are projects that provide a graphical interface for managing tasks:

  • Ansible AWX (free, Apache License 2.0)
  • Red Hat Ansible Tower (commercial)
  • Semaphore (free, MIT License)

0a3e1ef6 Db67 4467 A4c9 920f139756b7.png

Semaphore UI

Ansible vs Other Automation Systems
Copy link

Infrastructure automation tools fall into two main categories:

Configuration management tools:

  • Ansible
  • Chef
  • SaltStack
  • Puppet

Their main job: configuring and managing software on already existing servers. They automate software installation, package updates, and system settings.

Provisioning tools:

  • Terraform
  • Pulumi

Their job: creating the infrastructure itself: virtual machines, networks, databases. This is a broader approach that starts from the foundation of IT systems.

Often, these tools are combined, with Terraform + Ansible being the most common pairing.

Feature Highlights

Ansible

  • Easiest to start with
  • No extra software required on nodes (besides Python)
  • Uses SSH protocol for connections

Chef

  • Uses cooking metaphors (recipes, cookbooks)
  • Suitable for complex infrastructures
  • Strong support for configuration testing
  • Steeper learning curve

SaltStack

  • High performance thanks to optimized architecture
  • Good for large-scale solutions
  • Modules are written in Python
  • Works well in distributed systems

Puppet

  • Powerful for large enterprises
  • Well documented
  • More complex to learn, but very powerful
  • Great for standardizing configurations

In any case, we recommend starting with Ansible when learning infrastructure automation.

Summary
Copy link

In this article, we aimed to show Ansible’s built-in modules and basic usage examples as clearly as possible. However, the most effective way to learn such tools is practice.

Ansible skills are often required in job postings for system administrators, DevOps engineers, and SREs.

Next steps for learning:

  • Roles
  • Encryption with ansible-vault
  • Community Collections