You are currently viewing Ansible – 4 Different Techniques To Run Playbook Locally

Ansible – 4 Different Techniques To Run Playbook Locally

Introduction

Ansible by default executes the task against the list of hosts given in the host directive. But sometimes we want to restrict the task execution on a specific host or only run the tasks in localhost from where the playbook is executed. A good use case for running a playbook locally is when you wish to configure your personal linux desktop workstation which involves just a single machine.

There are a couple of methods available to restrict the playbook to run only on localhost. I will demonstrate all those methods in the upcoming sections and you can choose the one that suits your need.

I have a 4-node docker container lab setup and all the containers are grouped under the “servers” group in the inventory file.

$ ansible-inventory --graph
@all:
  |--@servers:
  |  |--ansalpine
  |  |--anscontroller
  |  |--ansrocky
  |  |--ansubuntu
  |  |--localhost
  |--@ungrouped:

A Simple & Straightforward Approach

The most straightforward approach in running the playbook locally is to configure the inventory and the host directive in the playbook only with localhost. 

# hosts file
localhost ansible_connection=local

# sample playbook
---
- name: Restrict to localhost
  hosts: localhost
  connection: local
  gather_facts: False

  tasks:
    - name: Get the hostname from the container
      ansible.builtin.shell: hostname
      register: host
  
    - name: Print the hostname
      ansible.builtin.debug:
        var: host.stdout

Run the playbook with the following commands.

# syntax check
$ ansible-playbook --syntax-check playbook_name.yml 

# Execute playbook
$ ansible-playbook playbook_name.yml

Ansible Connection Plugins

In the previous section I have set the “connection: local” in the playbook and “ansible_connection: local” in the hosts file. 

Before running a task against a given host, ansible connects to the host using the connection plugin. These connection plugins come by default with ansible. You can run the following command to get the list of connection plugins installed on your machine.

$ ansible-doc -t connection -l
ansible.builtin.local          execute on controller                                                                
ansible.builtin.paramiko_ssh   Run tasks via python ssh (paramiko)                                                  
ansible.builtin.psrp           Run tasks over Microsoft PowerShell Remoting Protocol                                
ansible.builtin.ssh            connect via SSH client binary                                                        
ansible.builtin.winrm          Run tasks over Microsoft's WinRM  

By default, ansible uses the paramiko_ssh plugin to connect to a target machine and you need to have an ssh password or key-based authentication setup for the task to run successfully. 
Alternatively, you can also use the “local” connection plugin which will run the task on the controller node(localhost) without any password or keys.

Run Ansible Playbook Locally Using Limit Flag

In the last section, the playbook is explicitly configured to run only against localhost. When you have multiple hosts in your inventory and wish to restrict the execution to localhost then you can use the limit flag.

The ansible-playbook command offers the “-l” or “–limit” flag which restricts the playbook execution only for the given host. When I say given host it can be any hostname in the inventory including the localhost. 

You have to pass the hostname to the limit flag. In our case, it is going to be localhost.

-l SUBSET, --limit SUBSET further limit selected hosts to an additional pattern

I am using the same playbook from the last section but here the host directive is set to “*” which means the tasks will be running on all the hosts by default.

---
- name: Using limit to restrict the host
  hosts: "*"
  gather_facts: False

  tasks:
    - name: Get the hostname from the container
      ansible.builtin.shell: hostname
      register: host
  
    - name: Print the hostname
      ansible.builtin.debug:
        var: host.stdout

In the following output, you can see both tasks are restricted to localhost when the limit flag is used.

$ ansible-playbook run_playbook_locally.yml --limit localhost

PLAY [Using limit to restrict the host] *********************************************************************************

TASK [Get the hostname from the container] ******************************************************************************
changed: [localhost]

TASK [Print the hostname] ***********************************************************************************************
ok: [localhost] => {
    "host.stdout": "73c75bd5ce74"
}

You can also pass the –connection=local flag to set the connection to local instead of using an ssh connection.

$ ansible-playbook run_playbook_locally.yml --limit localhost --connection=local

Run Ansible Playbook Locally Using delegate_to Directive

In the last two sections, we have seen how to run the entire playbook locally. In this section, we will see how to restrict a particular task to run locally using the delegate_to directive. 

I am using the same example but the host directive is now set to all and “delegate_to: localhost” is added at the task level.

---
- name: Control task execution using delegation
  hosts: "*"
  gather_facts: False

 tasks:
   - name: Get the hostname from the container
     ansible.builtin.shell: hostname
     register: host
     delegate_to: localhost

   - name: Print the hostname
     ansible.builtin.debug:
       var: host.stdout
     delegate_to: localhost

When you run this playbook you will see the task gets executed locally but against the N number of hosts configured in the inventory. This is the default behavior of the delegate_to directive. 

To control this behavior and make the task run only once use the directive “run_once: True”

Instead of applying the delegate_to and run_once directives against all tasks, you can group them under a tasks file and use imports or includes.

- import_tasks: task.yml
  delegate_to: localhost
  run_once: True

Delegation is mostly used when the playbook has to run against multiple hosts and delegate a few tasks alone to specific hosts. If your entire playbook runs only on localhost then delegation is not a preferred method. 

Run Ansible Playbook Locally Using Local Action

The ansible local_action directive can be used as an alternate directive to delegate_to. The difference here is any hostname from the inventory can be passed to the delegate_to directive but local_action will run only on localhost. Similar to the delegate_to directive you have to set run_once for the local_action directive too.

 tasks:

   - name: Get the hostname from the container
     local_action:
       module: ansible.builtin.shell
       cmd: hostname
     register: host
  
   - name: Print the hostname
     local_action:
       module: ansible.builtin.debug
       var: host.stdout

Wrap-Up

In this article, we have seen different approaches to running playbooks and tasks locally. If your requirement is to run the entire playbook locally then simply set the host to localhost and run the playbook. If your use case needs to run only a particular task against localhost then the delegate_to directive is the preferred choice. 

Leave a Reply

14 + twenty =