Introduction
This tutorial will guide you through using Ansible vars_files for efficient configuration management. Ansible is a powerful automation tool that helps manage infrastructure through simple, human-readable YAML files. The vars_files feature allows you to keep your configuration data separate from your automation logic, making your Ansible projects more organized and maintainable.
By the end of this tutorial, you will learn how to create and organize vars_files, incorporate them into playbooks, and leverage them to manage different environments effectively. This knowledge will help you build more scalable and maintainable infrastructure automation.
Installing Ansible and Creating Your First vars_file
In this first step, we will install Ansible on our system and create our first vars_file to store configuration data.
Installing Ansible
Let's start by installing Ansible on our Ubuntu system:
sudo apt update
sudo apt install -y ansible
After installation completes, verify that Ansible is installed correctly:
ansible --version
You should see output similar to this, showing the Ansible version and configuration:
ansible [core 2.12.x]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/labex/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /home/labex/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.10.x (default, Mar 14 2023, 14:21:35) [GCC 11.3.0]
jinja version = 3.0.3
libyaml = True
Creating a Project Directory Structure
Let's create a directory structure for our Ansible project:
mkdir -p ~/project/ansible-vars-demo/vars
cd ~/project/ansible-vars-demo
Understanding Ansible vars_files
Ansible vars_files are YAML files that store variable definitions which can be imported into playbooks. These files allow you to:
- Separate configuration data from automation logic
- Reuse the same variables across multiple playbooks
- Maintain different configurations for different environments
Creating Your First vars_file
Let's create our first vars_file to store web server configuration settings. Using the WebIDE, create a new file at ~/project/ansible-vars-demo/vars/webserver.yml with the following content:
---
## Web Server Configuration
http_port: 80
server_name: example.com
document_root: /var/www/html
max_clients: 200
This vars_file defines four variables that might be used in configuring a web server:
http_port: The port the web server will listen onserver_name: The domain name for the web serverdocument_root: The directory where website files will be storedmax_clients: The maximum number of simultaneous client connections
To help understand what this looks like in the WebIDE, navigate to the file explorer on the left side, expand the project folder, then ansible-vars-demo, then vars, and you should see your webserver.yml file. Click on it to view or edit its contents.
Creating an Inventory File
Next, we need to create an inventory file to tell Ansible which hosts to manage. In a real environment, this would contain actual server addresses, but for this tutorial, we'll use localhost.
Create a new file at ~/project/ansible-vars-demo/inventory.ini with the following content:
[webservers]
localhost ansible_connection=local
This simple inventory defines a group called webservers that includes only our local machine.
Understanding the Project Structure
At this point, your project structure should look like this:
ansible-vars-demo/
├── inventory.ini
└── vars/
└── webserver.yml
This basic structure separates our inventory (which hosts to manage) from our variable definitions (how to configure those hosts).
Creating a Basic Playbook with vars_files
Now that we have our vars_file created, let's build a simple Ansible playbook that uses these variables. This will demonstrate how to import and use configuration data from vars_files.
Understanding Ansible Playbooks
Ansible playbooks are YAML files that define a set of tasks to be executed on managed hosts. Playbooks are the core of Ansible's functionality, allowing you to automate complex configuration processes.
Creating a Simple Playbook
Let's create a playbook that will simulate configuring a web server using the variables we defined in our vars_file. Create a new file at ~/project/ansible-vars-demo/webserver_setup.yml with the following content:
---
- name: Configure Web Server
hosts: webservers
vars_files:
- vars/webserver.yml
tasks:
- name: Display web server configuration
debug:
msg: "Web server will be configured with: Port={{ http_port }}, ServerName={{ server_name }}, DocumentRoot={{ document_root }}"
- name: Create a directory for document root
file:
path: "/tmp/{{ document_root }}"
state: directory
mode: "0755"
- name: Create a sample index.html file
copy:
content: |
<html>
<head>
<title>Welcome to {{ server_name }}</title>
</head>
<body>
<h1>Welcome to {{ server_name }}</h1>
<p>This server is configured to handle {{ max_clients }} simultaneous connections.</p>
</body>
</html>
dest: "/tmp/{{ document_root }}/index.html"
mode: "0644"
Let's understand what this playbook does:
hosts: webservers- Specifies that this playbook should run on all hosts in the "webservers" group from our inventory.vars_files: - vars/webserver.yml- Imports variables from our vars_file.- The first task uses the
debugmodule to display a message showing the variables. - The second task creates a directory structure that would be used for the web server document root.
- The third task creates a sample HTML file that includes the variables from our vars_file.
Running the Playbook
Now, let's run the playbook to see it in action:
cd ~/project/ansible-vars-demo
ansible-playbook -i inventory.ini webserver_setup.yml
You should see output similar to this:
PLAY [Configure Web Server] ****************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Display web server configuration] ****************************************
ok: [localhost] => {
"msg": "Web server will be configured with: Port=80, ServerName=example.com, DocumentRoot=/var/www/html"
}
TASK [Create a directory for document root] ************************************
changed: [localhost]
TASK [Create a sample index.html file] *****************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Verifying the Results
Let's verify that our playbook has created the expected files:
ls -la /tmp/var/www/html/
cat /tmp/var/www/html/index.html
You should see the directory structure and the contents of the index.html file, which should include the values from our vars_file:
<html>
<head>
<title>Welcome to example.com</title>
</head>
<body>
<h1>Welcome to example.com</h1>
<p>This server is configured to handle 200 simultaneous connections.</p>
</body>
</html>
Understanding the Workflow
Let's recap what we've accomplished:
- We stored configuration data in a separate vars_file (
vars/webserver.yml). - We created a playbook that imports and uses this configuration data.
- We ran the playbook to execute tasks that use the variables.
This separation of configuration data (vars_files) from automation logic (playbooks) makes our Ansible code more maintainable and reusable. We can now update the configuration by editing just the vars_file, without changing the playbook itself.
Working with Multiple vars_files
Now that we understand the basics of vars_files, let's explore how to use multiple vars_files to manage different environments. This is a common practice in real-world scenarios where you might have different configurations for development, staging, and production environments.
Creating Environment-Specific vars_files
Let's create vars_files for different environments. First, let's create a development environment configuration:
Create a new file at ~/project/ansible-vars-demo/vars/dev_environment.yml with the following content:
---
## Development Environment Configuration
environment_name: development
debug_mode: true
log_level: debug
backup_frequency: weekly
max_memory: 512MB
Next, let's create a production environment configuration:
Create a new file at ~/project/ansible-vars-demo/vars/prod_environment.yml with the following content:
---
## Production Environment Configuration
environment_name: production
debug_mode: false
log_level: error
backup_frequency: daily
max_memory: 2048MB
Creating a Playbook with Multiple vars_files
Now, let's create a playbook that uses both our webserver configuration and environment-specific configurations. Create a new file at ~/project/ansible-vars-demo/environment_setup.yml with the following content:
---
- name: Configure Environment
hosts: webservers
vars:
env: dev
vars_files:
- vars/webserver.yml
- "vars/{{ env }}_environment.yml"
tasks:
- name: Display environment details
debug:
msg: >
Setting up {{ environment_name }} environment with the following parameters:
- Web Server: {{ server_name }} on port {{ http_port }}
- Debug Mode: {{ debug_mode }}
- Log Level: {{ log_level }}
- Backup Frequency: {{ backup_frequency }}
- Max Memory: {{ max_memory }}
- Max Clients: {{ max_clients }}
- name: Create environment config file
copy:
content: |
## Environment Configuration for {{ server_name }}
ENVIRONMENT={{ environment_name }}
DEBUG={{ debug_mode }}
LOG_LEVEL={{ log_level }}
BACKUP_FREQUENCY={{ backup_frequency }}
MAX_MEMORY={{ max_memory }}
HTTP_PORT={{ http_port }}
MAX_CLIENTS={{ max_clients }}
dest: "/tmp/{{ environment_name }}_config.env"
mode: "0644"
This playbook introduces several new concepts:
- We set a variable
env: devwithin the playbook itself. - We include both our webserver vars_file and an environment-specific vars_file.
- The environment vars_file path includes a variable:
"vars/{{ env }}_environment.yml", which evaluates tovars/dev_environment.yml. - The tasks use variables from both vars_files.
Running the Playbook with Different Environments
Let's run the playbook first with the development environment (which is already the default):
cd ~/project/ansible-vars-demo
ansible-playbook -i inventory.ini environment_setup.yml
You should see output that includes the development environment settings:
TASK [Display environment details] ********************************************
ok: [localhost] => {
"msg": "Setting up development environment with the following parameters:\n- Web Server: example.com on port 80\n- Debug Mode: True\n- Log Level: debug\n- Backup Frequency: weekly\n- Max Memory: 512MB\n- Max Clients: 200"
}
Now, let's run the same playbook but override the env variable to use the production environment:
ansible-playbook -i inventory.ini environment_setup.yml -e "env=prod"
You should see output that includes the production environment settings:
TASK [Display environment details] ********************************************
ok: [localhost] => {
"msg": "Setting up production environment with the following parameters:\n- Web Server: example.com on port 80\n- Debug Mode: False\n- Log Level: error\n- Backup Frequency: daily\n- Max Memory: 2048MB\n- Max Clients: 200"
}
Verifying the Configuration Files
Let's verify that our playbook created the environment configuration files:
cat /tmp/development_config.env
cat /tmp/production_config.env
You should see two different configuration files, each with settings from the respective environment vars_file.
Understanding Variable Precedence
It's important to understand that when using multiple vars_files, Ansible follows a specific order of precedence for variables. If the same variable name appears in multiple places, the value defined later will override earlier definitions.
In our example, if we had defined http_port in both the webserver.yml and dev_environment.yml files, the value from dev_environment.yml would take precedence because it's included later in the vars_files list.
This behavior allows you to define common defaults in one file and then override specific values for different environments.
Advanced vars_files Techniques
In this final step, we'll explore some advanced techniques for working with vars_files in Ansible, including organizing variables hierarchically and implementing role-based variable organization.
Organizing Variables Hierarchically
In complex projects, it's often helpful to organize variables hierarchically. Let's create a structure where we have:
- Common variables that apply to all environments
- Environment-specific variables
- Application-specific variables
First, let's create a common variables file:
Create a new file at ~/project/ansible-vars-demo/vars/common.yml with the following content:
---
## Common variables for all environments
organization: "Example Corp"
admin_email: "admin@example.com"
timezone: "UTC"
Next, let's create application-specific variables:
Create a new file at ~/project/ansible-vars-demo/vars/database.yml with the following content:
---
## Database application variables
db_port: 3306
db_user: "dbuser"
db_name: "appdb"
db_max_connections: 100
Creating a Hierarchical Playbook
Now, let's create a playbook that demonstrates using these hierarchical variables. Create a new file at ~/project/ansible-vars-demo/hierarchical_setup.yml with the following content:
---
- name: Hierarchical Variable Demo
hosts: webservers
vars:
env: dev
app: database
vars_files:
- "vars/common.yml"
- "vars/{{ env }}_environment.yml"
- "vars/{{ app }}.yml"
tasks:
- name: Display hierarchical configuration
debug:
msg: >
Configuration for {{ app }} in {{ environment_name }} environment:
- Organization: {{ organization }}
- Admin Email: {{ admin_email }}
- Timezone: {{ timezone }}
- Debug Mode: {{ debug_mode }}
- Log Level: {{ log_level }}
- DB Port: {{ db_port }}
- DB User: {{ db_user }}
- DB Max Connections: {{ db_max_connections }}
- name: Create hierarchical config file
copy:
content: |
## {{ organization }} Configuration
## {{ environment_name }} Environment
## Common Settings
ADMIN_EMAIL={{ admin_email }}
TIMEZONE={{ timezone }}
## Environment Settings
DEBUG={{ debug_mode }}
LOG_LEVEL={{ log_level }}
BACKUP_FREQUENCY={{ backup_frequency }}
## {{ app | capitalize }} Settings
DB_PORT={{ db_port }}
DB_USER={{ db_user }}
DB_NAME={{ db_name }}
DB_MAX_CONNECTIONS={{ db_max_connections }}
dest: "/tmp/{{ environment_name }}_{{ app }}_config.conf"
mode: "0644"
Understanding Group and Host Variables
In addition to vars_files, Ansible also supports storing variables in special directories called group_vars and host_vars. Let's see how these work:
Create a directory structure for group and host variables:
mkdir -p ~/project/ansible-vars-demo/group_vars
mkdir -p ~/project/ansible-vars-demo/host_vars
Now, create a group variables file for the 'webservers' group:
Create a new file at ~/project/ansible-vars-demo/group_vars/webservers.yml with the following content:
---
## Variables for all webservers
firewall_enabled: true
ssh_port: 22
monitoring_enabled: true
And create a host variables file for 'localhost':
Create a new file at ~/project/ansible-vars-demo/host_vars/localhost.yml with the following content:
---
## Variables specific to localhost
local_backup_path: "/tmp/backups"
is_development_machine: true
Creating a Playbook with All Variable Types
Let's create a final playbook that demonstrates using all the variable types together. Create a new file at ~/project/ansible-vars-demo/complete_setup.yml with the following content:
---
- name: Complete Variable Demo
hosts: webservers
vars:
env: prod
app: database
vars_files:
- "vars/common.yml"
- "vars/{{ env }}_environment.yml"
- "vars/{{ app }}.yml"
tasks:
- name: Display complete configuration
debug:
msg: >
Complete configuration for {{ inventory_hostname }}:
- Organization: {{ organization }}
- Environment: {{ environment_name }}
- Debug Mode: {{ debug_mode }}
- Firewall Enabled: {{ firewall_enabled }}
- SSH Port: {{ ssh_port }}
- Monitoring Enabled: {{ monitoring_enabled }}
- Local Backup Path: {{ local_backup_path }}
- Is Development Machine: {{ is_development_machine }}
- name: Create complete config file
copy:
content: |
## {{ organization }} - {{ environment_name }} Environment
## Host: {{ inventory_hostname }}
## Common Settings
ADMIN_EMAIL={{ admin_email }}
TIMEZONE={{ timezone }}
## Environment Settings
DEBUG={{ debug_mode }}
LOG_LEVEL={{ log_level }}
## Server Settings
FIREWALL_ENABLED={{ firewall_enabled }}
SSH_PORT={{ ssh_port }}
MONITORING_ENABLED={{ monitoring_enabled }}
## Host-specific Settings
LOCAL_BACKUP_PATH={{ local_backup_path }}
IS_DEVELOPMENT_MACHINE={{ is_development_machine }}
## {{ app | capitalize }} Settings
DB_PORT={{ db_port }}
DB_USER={{ db_user }}
DB_NAME={{ db_name }}
dest: "/tmp/complete_config.conf"
mode: "0644"
Running the Advanced Playbooks
Let's run our hierarchical playbook:
cd ~/project/ansible-vars-demo
ansible-playbook -i inventory.ini hierarchical_setup.yml
You should see output that includes variables from all three vars_files.
Now, let's run our complete playbook:
ansible-playbook -i inventory.ini complete_setup.yml
This time, you should see output that includes variables from vars_files, group_vars, and host_vars.
Verifying the Configuration Files
Let's check the configuration files created by our advanced playbooks:
cat /tmp/dev_database_config.conf
cat /tmp/complete_config.conf
Understanding Variable Precedence in Ansible
When using multiple variable sources, Ansible follows a specific order of precedence:
- Command line variables (
-eor--extra-vars) - Variables defined in the play
- Variables from included files and roles
- Host facts
- Host vars
- Group vars
- Inventory vars
- Role default vars
This means that variables defined in host_vars will override the same variables defined in group_vars, which will override the same variables defined in vars_files.
This hierarchical structure gives you a powerful way to manage configuration across different environments, hosts, and applications.
Summary
In this tutorial, you have learned how to effectively use Ansible vars_files for configuration management. You have:
- Installed Ansible and created your first vars_file to store configuration data
- Created and run a basic playbook that uses vars_files to separate configuration from automation logic
- Worked with multiple vars_files to manage different environments
- Explored advanced techniques including hierarchical variable organization and using group_vars and host_vars
These skills provide a solid foundation for building scalable and maintainable Ansible automation. By separating your configuration data from your automation logic, you can:
- Make your playbooks more reusable across different environments
- Simplify the process of updating configuration values
- Manage complex configurations in a structured way
- Improve collaboration by clearly organizing configuration data
As you continue working with Ansible, remember that effective variable management is key to building maintainable automation. The techniques you've learned in this tutorial will help you organize your Ansible projects as they grow in complexity.


