In the modern era of DevOps and cloud computing, managing Linux systems manually has become increasingly unsustainable. Tasks like configuring servers, deploying software, managing users, and ensuring consistency across environments are time-consuming, error-prone, and难以扩展 at scale. This is where Ansible—an open-source automation tool—shines. Ansible simplifies Linux system automation with its agentless architecture, human-readable YAML playbooks, and extensive module library. Whether you’re managing a handful of servers or a large enterprise infrastructure, Ansible enables you to automate repetitive tasks, enforce configurations, and maintain system state consistently. This blog will guide you through the fundamentals of Ansible, from core concepts to practical implementation, common use cases, and best practices. By the end, you’ll have the knowledge to start automating Linux systems efficiently with Ansible.
Table of Contents
- What is Ansible?
- Core Concepts
- Getting Started with Ansible
- Writing Playbooks: The Heart of Ansible
- Common Use Cases
- Best Practices
- Troubleshooting Tips
- Conclusion
- References
What is Ansible?
Ansible is an open-source automation platform developed by Red Hat. It is designed to automate provisioning, configuration management, application deployment, and orchestration of IT infrastructure. Unlike tools like Puppet or Chef, Ansible is agentless—it uses SSH (or WinRM for Windows) to communicate with managed nodes, eliminating the need to install software agents on target systems. This makes Ansible lightweight, easy to set up, and low-maintenance.
Key features of Ansible include:
- Human-readable playbooks: Written in YAML, making them easy to write, read, and version-control.
- Extensive module library: Thousands of built-in modules for tasks like package management, file operations, and cloud provisioning.
- Idempotent operations: Ensures running the same playbook multiple times produces the same result (no unintended side effects).
- Scalability: Automate hundreds or thousands of nodes from a single control node.
Core Concepts
To use Ansible effectively, you need to understand its core components:
Control Node
The machine where Ansible is installed and from which automation is executed. It can be any Linux or macOS system with Python 3.8+ and an SSH client. Windows is not supported as a control node.
Managed Nodes
The target systems (Linux servers, network devices, etc.) that Ansible automates. Managed nodes require:
- Python 2.7 or 3.5+ (for most modules).
- SSH server (enabled and accessible from the control node).
- Proper network connectivity and authentication (SSH keys recommended).
Inventory
A file (or directory) that lists managed nodes, organized into groups for easier targeting. Inventory files can be in INI or YAML format and may include variables specific to nodes/groups.
Playbooks
YAML files that define a set of “plays” and “tasks” to execute on managed nodes. Playbooks are the primary way to automate workflows in Ansible.
Tasks
The smallest unit of work in Ansible. A task calls a module with specific arguments to perform an action (e.g., install a package, create a user).
Modules
Reusable, standalone scripts that Ansible executes on managed nodes to perform tasks. Ansible provides over 4,500 built-in modules (e.g., apt, user, copy, service), and you can write custom modules in Python.
Roles
A way to organize playbooks, variables, tasks, handlers, and templates into a reusable directory structure. Roles simplify sharing and reusing automation logic across projects.
Getting Started with Ansible
Let’s walk through setting up Ansible and running your first automation tasks.
Installation
Install Ansible on the control node using one of these methods:
On Ubuntu/Debian:
sudo apt update && sudo apt install ansible -y
On CentOS/RHEL:
sudo dnf install ansible -y # For RHEL 8+/CentOS 8+
# Or for older versions: sudo yum install ansible -y
Using pip (Python package manager):
pip3 install ansible
Verify installation:
ansible --version
Setting Up Inventory
The inventory file tells Ansible which nodes to manage. By default, Ansible uses /etc/ansible/hosts, but you can specify a custom inventory with the -i flag.
Example Inventory (INI format):
Create a file named inventory.ini:
# inventory.ini
[webservers]
server1.example.com # IP or hostname
server2.example.com ansible_user=ubuntu # Override SSH user
[databases]
db1.example.com ansible_port=2222 # Override SSH port
[all:vars]
ansible_user=centos # Default SSH user for all nodes
YAML Format (Alternative):
inventory.yml:
all:
vars:
ansible_user: centos
children:
webservers:
hosts:
server1.example.com:
server2.example.com:
ansible_user: ubuntu
databases:
hosts:
db1.example.com:
ansible_port: 2222
Test inventory connectivity with the ping module (checks if nodes are reachable):
ansible all -i inventory.ini -m ping
Output should look like:
server1.example.com | SUCCESS => {
"changed": false,
"ping": "pong"
}
Ad-Hoc Commands
For one-off tasks, use ad-hoc commands instead of playbooks. Syntax:
ansible <target> -i <inventory> -m <module> -a <module_arguments> [--become]
Examples:
- Check disk space on all nodes:
ansible all -i inventory.ini -m command -a "df -h" - Install
nginxon web servers (withsudo):
ansible webservers -i inventory.ini -m apt -a "name=nginx state=present" --become
(Useyuminstead ofaptfor RHEL/CentOS.) - Restart
nginxon web servers:
ansible webservers -i inventory.ini -m service -a "name=nginx state=restarted" --become
--become (or -b) elevates privileges (equivalent to sudo).
Writing Playbooks: The Heart of Ansible
Playbooks are Ansible’s configuration, deployment, and orchestration language. They define a series of tasks to run on target nodes and are written in YAML.
Basic Playbook Structure
A playbook consists of one or more “plays,” each targeting a group of hosts and defining tasks to execute. Here’s a simple playbook to install and start nginx:
# install_nginx.yml
---
- name: Install and start Nginx on web servers
hosts: webservers # Target group from inventory
become: yes # Run tasks with sudo
tasks:
- name: Install Nginx package
apt: # Module for Debian/Ubuntu
name: nginx
state: present # Ensure package is installed
- name: Start and enable Nginx service
service:
name: nginx
state: started
enabled: yes # Start on boot
Run the playbook with:
ansible-playbook -i inventory.ini install_nginx.yml
Variables
Variables make playbooks reusable by allowing dynamic values. Define variables in:
- Playbooks (using
varskeyword). - Inventory files (per node/group).
- Separate
vars_files(e.g.,vars/webservers.yml). - Command line (with
-e "var=value").
Example with Variables:
# install_nginx_with_vars.yml
---
- name: Install Nginx with variables
hosts: webservers
become: yes
vars:
web_package: nginx # Variable defined in playbook
service_state: started
tasks:
- name: Install {{ web_package }}
apt:
name: "{{ web_package }}"
state: present
- name: Ensure {{ web_package }} is {{ service_state }}
service:
name: "{{ web_package }}"
state: "{{ service_state }}"
enabled: yes
Conditionals
Use when clauses to run tasks only if a condition is met (e.g., based on OS, node hostname, or variable values).
Example: Install nginx only on Debian/Ubuntu:
tasks:
- name: Install Nginx on Debian/Ubuntu
apt:
name: nginx
state: present
when: ansible_os_family == "Debian" # Built-in fact: ansible_os_family
- name: Install Nginx on RHEL/CentOS
yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"
Ansible gathers “facts” (system info) by default, including ansible_os_family, ansible_distribution, and ansible_hostname. View all facts with:
ansible <node> -m setup
Loops
Use loops to repeat tasks (e.g., install multiple packages). Ansible supports loop (recommended) and with_items (legacy).
Example: Install Multiple Packages:
tasks:
- name: Install web server dependencies
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- git
- curl
when: ansible_os_family == "Debian"
Handlers
Handlers are tasks that run only when triggered (e.g., restart a service after a config file changes). Use notify in a task to trigger a handler.
Example: Update Nginx Config and Restart:
tasks:
- name: Copy Nginx config file
copy:
src: ./nginx.conf # Local file on control node
dest: /etc/nginx/nginx.conf
mode: '0644'
notify: Restart Nginx # Trigger handler if file changes
handlers: # Define handlers at the play level
- name: Restart Nginx
service:
name: nginx
state: restarted
Common Use Cases
Ansible excels at automating routine Linux system administration tasks. Below are common scenarios with playbook examples.
Package Management
Install, remove, or update packages across systems.
Example: Install/Remove Packages:
# package_management.yml
---
- name: Manage packages on web and db servers
hosts: webservers:databases
become: yes
tasks:
- name: Install required packages
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- mysql-client
when: ansible_os_family == "Debian"
- name: Remove unwanted package
yum:
name: httpd
state: absent # Uninstall package
when: ansible_os_family == "RedHat"
User Management
Create users, set passwords, and manage groups.
Example: Create a System User:
# create_user.yml
---
- name: Create devops user with SSH access
hosts: all
become: yes
tasks:
- name: Create devops group
group:
name: devops
state: present
gid: 1001
- name: Create devops user
user:
name: devops
uid: 1001
group: devops
groups: sudo # Add to sudo group
shell: /bin/bash
home: /home/devops
create_home: yes
state: present
- name: Add SSH public key for devops user
authorized_key:
user: devops
key: "{{ lookup('file', '/home/control-node-user/.ssh/id_rsa.pub') }}" # Local pub key
state: present
File Configuration
Copy files, templates, or set permissions. Use template (Jinja2) for dynamic configs.
Example: Deploy a Custom Nginx Config with Template:
# deploy_nginx_config.yml
---
- name: Deploy Nginx config from template
hosts: webservers
become: yes
vars:
nginx_port: 8080 # Variable used in template
tasks:
- name: Copy Nginx template
template:
src: templates/nginx.conf.j2 # Jinja2 template on control node
dest: /etc/nginx/nginx.conf
mode: '0644'
notify: Restart Nginx
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
Template File (templates/nginx.conf.j2):
server {
listen {{ nginx_port }}; # Dynamic port from variable
server_name {{ ansible_fqdn }}; # Ansible fact for hostname
root /var/www/html;
index index.html;
}
Service Management
Start, stop, restart, or enable services.
Example: Manage Docker Service:
# manage_docker.yml
---
- name: Ensure Docker is running and enabled
hosts: webservers
become: yes
tasks:
- name: Start Docker service
service:
name: docker
state: started
enabled: yes
System Updates
Update system packages (use cautiously in production!).
Example: Update Debian/Ubuntu Packages:
# update_packages.yml
---
- name: Update apt packages
hosts: all
become: yes
when: ansible_os_family == "Debian"
tasks:
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600 # Cache valid for 1 hour
- name: Upgrade all packages
apt:
upgrade: dist # Safe upgrade (avoid kernel updates)
state: present
Best Practices
To write maintainable, efficient Ansible automation, follow these best practices:
Idempotency
Ensure playbooks are idempotent—running them multiple times has the same effect as running once. Most Ansible modules are idempotent by design (e.g., apt with state: present won’t reinstall if already installed). Avoid command/shell modules for idempotent tasks (use specialized modules instead).
Use Roles for Organization
Roles organize playbooks, variables, tasks, and templates into a standard directory structure, making them reusable and shareable. Use ansible-galaxy init to create a role skeleton:
ansible-galaxy init roles/nginx # Creates roles/nginx/...
Role directory structure:
roles/nginx/
├── tasks/ # Main tasks (main.yml)
├── handlers/ # Handlers (main.yml)
├── vars/ # Variables (main.yml)
├── defaults/ # Default variables (low precedence)
├── templates/ # Jinja2 templates
├── files/ # Static files to copy
└── meta/ # Role metadata (dependencies, etc.)
Example: Use a Role in a Playbook:
# site.yml
---
- name: Deploy web servers
hosts: webservers
become: yes
roles:
- role: nginx # Path to role directory
Variables Management
- Store sensitive variables (passwords, API keys) in
ansible-vault(encrypted files).
Example:ansible-vault create vars/secrets.yml, then reference withvars_files: [vars/secrets.yml]. - Use
group_varsandhost_varsdirectories for inventory-specific variables:
inventory/group_vars/webservers.yml(vars for webservers group). - Avoid hardcoding variables in playbooks.
Security
- Use SSH keys instead of passwords for authentication.
- Restrict
becomeprivileges (e.g., limit sudo access for Ansible tasks). - Encrypt sensitive data with `ans