In Ansible, both import_role and include_role are used to execute roles within a playbook. However, there are significant differences between the two in terms of how and when they load the tasks, which can affect task execution order, behavior, and performance.
import_role
The import_role directive is used to statically import a role into a playbook. This means that the role is imported and its tasks are included into the playbook at the time of the playbook’s initial parsing. When Ansible begins executing the playbook, all of the tasks from the imported role are already part of the playbook.
Key Characteristics of import_role:
- Static loading: The role’s tasks are loaded when the playbook is parsed.
- All tasks are included: All tasks from the imported role are included at the start of playbook execution, even if they are not conditionally required later.
- No runtime evaluation: Since tasks are loaded before playbook execution, conditionals (like when statements) are not applied to the role, but rather to individual tasks within the role.
- hosts: localhost
tasks:
- import_role:
name: my_role
In this example, the role my_role is statically imported at the beginning of playbook execution, and all its tasks will be evaluated during playbook execution.
When to Use:
- Use import_role when you want to ensure that the tasks within a role are loaded in advance and executed in sequence with the rest of the playbook.
- Best for scenarios where task order matters, and you need all tasks loaded early.
include_role
The include_role directive is used to dynamically load a role at runtime. This means that the role’s tasks are included in the playbook as they are encountered during execution. Ansible reads and includes the role only at the point of execution when it reaches the include_role directive.
Key Characteristics of include_role:
- Dynamic loading: The role is included dynamically during playbook execution, meaning tasks from the role are only loaded when Ansible encounters the include_role statement.
- Conditional loading: Because include_role works dynamically, you can apply conditionals (when statements, loops, etc.) directly to the include_role directive, allowing you to conditionally include or exclude an entire role.
- Lazy evaluation: The tasks in the role are not processed or evaluated until the include_role directive is encountered.
- hosts: localhost
tasks:
- include_role:
name: my_role
Here, the role my_role is dynamically included when Ansible reaches the include_role directive.
When to Use:
- Use include_role when you need more dynamic behavior, such as conditionally including or skipping entire roles based on runtime information (e.g., facts or variables).
- It’s suitable for scenarios where the role should be included under certain conditions or should only be loaded when needed.
Example of import_role and include_role in a playbook
First, let’s define the structure:
project_root/
├── playbook.yml
└── roles/
├── common/
│ └── tasks/
│ └── main.yml
├── webserver/
│ └── tasks/
│ └── main.yml
└── deploy_app/
├── tasks/
│ └── main.yml
└── vars/
└── main.yml
Now, let’s create the content for each file:
playbook.yml
:
---
- name: Deploy Web Application
hosts: webservers
gather_facts: true
vars:
app_version: "1.2.3"
environment: "production"
tasks:
- name: Import common role
import_role:
name: common
- name: Setup webserver
import_role:
name: webserver
- name: Deploy application
include_role:
name: deploy_app
vars:
deploy_version: "{{ app_version }}"
when: environment == "production"
roles/common/tasks/main.yml
:
---
- name: Update apt cache
apt:
update_cache: yes
become: true
- name: Install common packages
apt:
name:
- htop
- vim
- curl
state: present
become: true
roles/webserver/tasks/main.yml
:
---
- name: Install Nginx
apt:
name: nginx
state: present
become: true
- name: Start Nginx service
systemd:
name: nginx
state: started
enabled: yes
become: true
roles/deploy_app/tasks/main.yml
:
---
- name: Create app directory
file:
path: /var/www/myapp
state: directory
become: true
- name: Deploy application files
copy:
src: "files/app-{{ deploy_version }}/"
dest: /var/www/myapp
become: true
- name: Configure Nginx for the app
template:
src: nginx_site.conf.j2
dest: /etc/nginx/sites-available/myapp
notify: Reload Nginx
become: true
- name: Enable Nginx site
file:
src: /etc/nginx/sites-available/myapp
dest: /etc/nginx/sites-enabled/myapp
state: link
notify: Reload Nginx
become: true
handlers:
- name: Reload Nginx
systemd:
name: nginx
state: reloaded
become: true
roles/deploy_app/vars/main.yml
:
---
deploy_version: "1.0.0" # Default version, can be overridden
Explanation of import_role
and include_role
usage:
import_role
forcommon
andwebserver
roles:- We use
import_role
for these roles because they contain tasks that we always want to run and validate statically. - The
common
role sets up basic system configurations and installs common packages. - The
webserver
role installs and configures Nginx, which is a static requirement for our web application. - These roles are imported at playbook parse time, ensuring they are always executed in the defined order.
- We use
include_role
fordeploy_app
role:- We use
include_role
for thedeploy_app
role because it involves dynamic decisions:- It uses a variable
deploy_version
that can be set at runtime. - It has a conditional
when: environment == "production"
to only deploy in the production environment.
- It uses a variable
- This allows for flexibility in deployment scenarios, such as:
- Deploying different versions of the application.
- Skipping the deployment in non-production environments.
- The role is included at runtime, allowing for these dynamic decisions.
- We use
Summary
- import_role is used when you need static inclusion of roles, where all tasks from the role are loaded upfront at playbook parsing time. It’s ideal when task order is critical.
- include_role is used for dynamic inclusion, allowing you to conditionally load and execute roles during playbook execution based on runtime conditions, offering more flexibility and potentially better performance.
In general, use import_role for predictable, ordered role execution and use include_role for more dynamic, conditional behavior within your Ansible playbooks.
That’s all for now.
Thank you for reading!!
Stay tuned for more articles on Cloud and DevOps. Don’t forget to follow me for regular updates and insights.