Skip to content

Ansible

Chapter 48: Ansible for Linux Administration - Deep Dive

Section titled “Chapter 48: Ansible for Linux Administration - Deep Dive”

Mastering Configuration Management with Ansible

Section titled “Mastering Configuration Management with Ansible”

Ansible is an open-source automation tool that automates configuration management, application deployment, and IT orchestration. It uses a simple, declarative language (YAML) called “playbooks” to describe desired system states.

Ansible Architecture
+------------------------------------------------------------------+
| |
| Control Node |
| +-------------------------------------------------------------+ |
| | | |
| | +---------------+ +---------------+ | |
| | | Ansible | | Ansible | | |
| | | Engine | | Galaxy | | |
| | | (CLI/Config) | | (Roles) | | |
| | +---------------+ +---------------+ | |
| | | | | |
| | v v | |
| | +---------------------------------------------------+ | |
| | | Inventory & Variables | | |
| | +---------------------------------------------------+ | |
| | | |
| +-------------------------------------------------------------+ |
| | |
| | SSH/Connection |
| v |
| +-------------------------------------------------------------+ |
| | Managed Nodes | |
| | | |
| | +------------+ +------------+ +------------+ | |
| | | Server 1 | | Server 2 | | Server N | | |
| | | (Linux) | | (Linux) | | (Windows) | | |
| | +------------+ +------------+ +------------+ | |
| | | |
| +-------------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
Ansible Execution Flow
+------------------------------------------------------------------+
| |
| 1. User executes ansible-playbook |
| | |
| v |
| 2. Parse Inventory |
| +----------------------------------------------------------+ |
| | - Read hosts/groups from inventory file | |
| | - Load variable files | |
| +----------------------------------------------------------+ |
| | |
| v |
| 3. Parse Playbook |
| +----------------------------------------------------------+ |
| | - Read plays and tasks | |
| | - Resolve variables | |
| | - Load handlers | |
| +----------------------------------------------------------+ |
| | |
| v |
| 4. Build Execution Plan |
| +----------------------------------------------------------+ |
| | - Generate task list | |
| | - Apply filtering (limit, tags) | |
| | - Determine host order | |
| +----------------------------------------------------------+ |
| | |
| v |
| 5. Connect to Hosts |
| +----------------------------------------------------------+ |
| | - Establish SSH connection | |
| | - Gather facts (if enabled) | |
| +----------------------------------------------------------+ |
| | |
| v |
| 6. Execute Tasks |
| +----------------------------------------------------------+ |
| | - Run each task on each host | |
| | - Execute modules | |
| | - Collect results | |
| | - Execute handlers (if notified) | |
| +----------------------------------------------------------+ |
| | |
| v |
| 7. Report Results |
| +----------------------------------------------------------+ |
| | - Display output | |
| | - Generate reports | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

Terminal window
# /etc/ansible/hosts or custom inventory file
# Simple host list
server1.example.com
server2.example.com
192.168.1.100
# Groups
[webservers]
web1.example.com
web2.example.com
web3.example.com
[dbservers]
db1.example.com
db2.example.com
[loadbalancers]
lb1.example.com
# Group of groups
[production:children]
webservers
dbservers
loadbalancers
# Variables for groups
[webservers]
web1.example.com ansible_port=22
web2.example.com
[webservers:vars]
ansible_user=admin
ansible_python_interpreter=/usr/bin/python3
# Variables for hosts
[webservers]
web1.example.com nginx_port=80
web2.example.com nginx_port=8080
Terminal window
# All hosts
all
*
# Groups
webservers
production:staging
# Multiple groups
webservers:dbservers
# Exclude group
!webservers
# Intersection (in both)
webservers:&production
# Wildcards
*.example.com
server*.example.com
# Range
server[1:10].example.com
db[01:05].example.com

playbook.yml
---
- name: Configure Web Servers
hosts: webservers
become: yes # sudo
vars:
nginx_version: "1.24"
http_port: 80
tasks:
- name: Install nginx
package:
name: nginx
state: present
- name: Configure nginx
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart nginx
- name: Ensure nginx is running
service:
name: nginx
state: started
enabled: yes
handlers:
- name: Restart nginx
service:
name: nginx
state: restarted
Playbook Keywords
+------------------------------------------------------------------+
| |
| Play Level: |
| +----------------------------------------------------------+ |
| | name - Play description | |
| | hosts - Target hosts/groups | |
| | become - Enable privilege escalation | |
| | become_user - User to become | |
| | connection - Connection type (ssh/local/winrm) | |
| | gather_facts - Gather system facts | |
| | vars - Variables for play | |
| | vars_files - Variable files to include | |
| | roles - Roles to include | |
| | tasks - List of tasks | |
| | handlers - Handler definitions | |
| | pre_tasks - Tasks before roles | |
| | post_tasks - Tasks after roles | |
| +----------------------------------------------------------+ |
| |
| Task Level: |
| +----------------------------------------------------------+ |
| | name - Task description | |
| | action - Module to execute (deprecated) | |
| | module - Module to execute | |
| | args - Module arguments (explicit) | |
| | notify - Handler to notify | |
| | register - Register output to variable | |
| | until - Retry until condition | |
| | retries - Number of retries | |
| | delay - Delay between retries | |
| | when - Conditional execution | |
| | changed_when - Override changed status | |
| | failed_when - Override failed status | |
| | tags - Tags for selective execution | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

Essential Ansible Modules
+------------------------------------------------------------------+
| |
| Package Management: |
| +----------------------------------------------------------+ |
| | package - Generic package manager | |
| | yum/apt/dnf - Distribution-specific | |
| | pacman - Arch Linux | |
| +----------------------------------------------------------+ |
| |
| Service Management: |
| +----------------------------------------------------------+ |
| | service - Generic service manager | |
| | systemd - systemd-specific | |
| +----------------------------------------------------------+ |
| |
| File Management: |
| +----------------------------------------------------------+ |
| | copy - Copy files | |
| | template - Jinja2 templated files | |
| | file - File attributes | |
| | lineinfile - Edit lines in files | |
| | blockinfile - Edit blocks in files | |
| +----------------------------------------------------------+ |
| |
| System: |
| | user - User management | |
| | group - Group management | |
| | cron - Cron job management | |
| | mount - /etc/fstab entries | |
| | selinux - SELinux management | |
| +----------------------------------------------------------+ |
| |
| Commands: |
| | command - Execute commands | |
| | shell - Execute shell commands | |
| | script - Execute local script | |
| | expect - Execute with expect | |
| +----------------------------------------------------------+ |
| |
| Networking: |
| | get_url - Download files | |
| | uri - HTTP requests | |
| | nmcli - NetworkManager CLI | |
| +----------------------------------------------------------+ |
| |
| Cloud: |
| | ec2 - AWS EC2 | |
| | azure_rm - Azure | |
| | gce - Google Cloud | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
# Package
- name: Install nginx
package:
name: nginx
state: present
# Service
- name: Start nginx
service:
name: nginx
state: started
enabled: yes
# Copy
- name: Copy config
copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
# Template
- name: Render config
template:
src: templates/app.conf.j2
dest: /etc/app.conf
mode: '0600'
vars:
app_port: 8080
# File
- name: Create directory
file:
path: /var/log/app
state: directory
owner: app
group: app
mode: '0755'
# Line in file
- name: Add line to file
lineinfile:
path: /etc/sysctl.conf
line: 'net.ipv4.ip_forward = 1'
regexp: '^net.ipv4.ip_forward'
create: yes
# User
- name: Create deploy user
user:
name: deploy
comment: "Deploy User"
shell: /bin/bash
groups: [sudo, www-data]
append: yes
# Command
- name: Run custom command
command: /opt/app/init.sh
args:
chdir: /opt/app
creates: /var/run/app.pid
# Shell
- name: Execute shell script
shell: |
echo "Hello from $(hostname)"
register: shell_output
# Debug
- name: Show output
debug:
msg: "{{ shell_output.stdout }}"

Variable Precedence (Highest to Lowest)
+------------------------------------------------------------------+
| |
| 1. extra vars ( -e ) (highest) |
| |
| 2. task vars (register) |
| |
| 3. block vars (block:) |
| |
| 4. role vars (role/vars/main.yml) |
| |
| 5. handler vars (in handler) |
| |
| 6. include vars (include) |
| |
| 7. set_facts (inline) |
| |
| 8. registered vars |
| |
| 9. host vars (inventory) |
| |
| 10. group_vars (group_vars/) |
| |
| 11. playbook vars (vars:) |
| |
| 12. playbook vars_files (vars_files:) |
| |
| 13. role defaults (role/defaults/main.yml) (lowest) |
| |
+------------------------------------------------------------------+
group_vars/webservers.yml
---
nginx_version: "1.24"
nginx_workers: 4
http_port: 80
https_port: 443
# host_vars/web1.example.com.yml
---
nginx_port: 8080
- name: Use variables
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
vars:
worker_processes: "{{ nginx_workers }}"
listen_port: "{{ nginx_port }}"

Ansible Role Directory Structure
+------------------------------------------------------------------+
| |
| roles/ |
| └── rolename/ |
| ├── defaults/ # Default variables |
| │ └── main.yml |
| ├── vars/ # Role variables |
| │ └── main.yml │
| ├── tasks/ # Role tasks │
| │ └── main.yml │
| ├── handlers/ # Handlers │
| │ └── main.yml │
| ├── templates/ # Jinja2 templates │
| │ └── *.j2 │
| ├── files/ # Static files |
| │ └── * │
| ├── meta/ # Role dependencies │
| │ └── main.yml │
| └── README.md # Documentation |
| |
+------------------------------------------------------------------+
roles/nginx/tasks/main.yml
---
- name: Install nginx
package:
name: nginx
state: present
- name: Configure nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart nginx
- name: Ensure nginx is running
service:
name: nginx
state: started
enabled: yes
# roles/nginx/handlers/main.yml
---
- name: Restart nginx
service:
name: nginx
state: restarted
# roles/nginx/defaults/main.yml
---
nginx_port: 80
nginx_workers: 4
# roles/nginx/templates/nginx.conf.j2
worker_processes {{ nginx_workers }};
events {
worker_connections 1024;
}
http {
server {
listen {{ nginx_port }};
}
}

Terminal window
# Create encrypted file
ansible-vault create secrets.yml
# Edit encrypted file
ansible-vault edit secrets.yml
# View encrypted file
ansible-vault view secrets.yml
# Encrypt existing file
ansible-vault encrypt plain.yml
# Decrypt file
ansible-vault decrypt secrets.yml
# Change password
ansible-vault rekey secrets.yml
# Encrypt string (for inline secrets)
ansible-vault encrypt_string --stdin-name 'db_password'
playbook.yml
- name: Deploy app
hosts: all
vars_files:
- secrets.yml # encrypted
tasks:
- name: Set database password
set_fact:
db_pass: "{{ db_password }}"

- name: Install on Debian
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
- name: Install on RedHat
yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"
- name: Install nginx on supported OS
package:
name: nginx
state: present
when: ansible_distribution in ['Ubuntu', 'Debian', 'CentOS', 'RedHat']
# Loop over list
- name: Install packages
package:
name: "{{ item }}"
state: present
loop:
- nginx
- mysql
- postgresql
# Loop with index
- name: Create users
user:
name: "{{ item.name }}"
shell: "{{ item.shell }}"
loop:
- { name: 'alice', shell: '/bin/bash' }
- { name: 'bob', shell: '/bin/sh' }
# Loop over dictionary
- name: Set firewall rules
firewalld:
service: "{{ item.key }}"
permanent: yes
state: "{{ item.value }}"
loop:
{ 'http': 'yes', 'https': 'yes', 'ssh': 'no' }
# With lookup
- name: Read file lines
debug:
msg: "{{ item }}"
loop: "{{ query('file', '/path/to/file.txt') }}"

Recommended Project Structure
+------------------------------------------------------------------+
| |
| project/ |
| ├── inventory/ |
| │ ├── production/ │
| │ │ ├── hosts │
| │ │ └── group_vars/ │
| │ └── staging/ │
| │ ├── hosts │
| │ └── group_vars/ │
| ├── playbooks/ │
| │ ├── site.yml │
| │ ├── webservers.yml │
| │ └── dbservers.yml │
| ├── roles/ │
| │ ├── common/ │
| │ ├── nginx/ │
| │ └── postgresql/ │
| ├── vars/ │
│ │ └── common.yml │
| ├── files/ │
│ │ └── templates/ │
│ ├── library/ │
| ├── module_utils/ │
| ├── ansible.cfg │
| └── README.md |
| |
+------------------------------------------------------------------+
[defaults]
inventory = inventory/production/hosts
roles_path = roles
host_key_checking = False
retry_files_enabled = False
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
stdout_callback = yaml
bin_ansible_callbacks = True
[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
pipelining = True

Important

  1. Inventory: Use groups and patterns effectively
  2. Playbooks: YAML format, remember indentation
  3. Modules: Know common modules (package, service, copy, template)
  4. Variables: Understand precedence order
  5. Roles: Organize reusable playbooks
  6. Vault: Encrypt sensitive data
  7. Conditionals: Use when for conditional execution
  8. Loops: Use loop instead of with_items
  9. Handlers: Use notify to trigger
  10. Idempotency: Ansible should be idempotent

In this chapter, you learned:

  • ✅ Ansible architecture and how it works
  • ✅ Inventory management and patterns
  • ✅ Playbook structure and syntax
  • ✅ Common modules
  • ✅ Variables and precedence
  • ✅ Roles organization
  • ✅ Vault for secrets
  • ✅ Conditionals and loops
  • ✅ Best practices and project structure

Chapter 49: Configuration Management with Puppet/Chef


Last Updated: February 2026