Installation
|
Install Ansible via pip pip install ansible |
|
|
Install Ansible via apt (Ubuntu/Debian) sudo apt update sudo apt install ansible |
|
|
Install Ansible via yum (RHEL/CentOS) sudo yum install ansible |
|
|
Verify installation ansible --version |
Basic Commands
|
Run ad-hoc command on all hosts ansible all -m ping |
|
|
Run ad-hoc command on specific group ansible webservers -m ping |
|
|
Run shell command on hosts ansible all -m shell -a 'uptime' |
|
|
Run playbook ansible-playbook playbook.yml |
|
|
Run playbook with inventory file ansible-playbook -i inventory.ini playbook.yml |
|
|
Run playbook with specific tags ansible-playbook playbook.yml --tags "configuration,packages" |
|
|
Skip specific tags ansible-playbook playbook.yml --skip-tags "testing" |
|
|
Check playbook syntax ansible-playbook playbook.yml --syntax-check |
|
|
Run playbook in dry-run mode ansible-playbook playbook.yml --check |
|
|
Run playbook with verbose output ansible-playbook playbook.yml -v ansible-playbook playbook.yml -vv ansible-playbook playbook.yml -vvv ansible-playbook playbook.yml -vvvv |
|
|
Limit execution to specific hosts ansible-playbook playbook.yml --limit "host1,host2" |
|
|
Step through playbook interactively ansible-playbook playbook.yml --step |
|
|
Start at specific task ansible-playbook playbook.yml --start-at-task="task name" |
Configuration
|
ansible.cfg locations (in order of precedence)
|
|
|
Basic ansible.cfg structure [defaults] inventory = ./inventory remote_user = ansible host_key_checking = False retry_files_enabled = False [privilege_escalation] become = True become_method = sudo become_user = root become_ask_pass = False |
|
|
Set custom config location export ANSIBLE_CONFIG=/path/to/ansible.cfg |
|
|
View current configuration ansible-config dump |
|
|
List all config options ansible-config list |
Inventory
|
INI format inventory # inventory.ini [webservers] web1.example.com web2.example.com [databases] db1.example.com db2.example.com [production:children] webservers databases [webservers:vars] http_port=80 |
|
|
YAML format inventory # inventory.yml all: children: webservers: hosts: web1.example.com: web2.example.com: vars: http_port: 80 databases: hosts: db1.example.com: db2.example.com: |
|
|
List all hosts in inventory ansible all --list-hosts |
|
|
List hosts in specific group ansible webservers --list-hosts |
|
|
Get host variables ansible-inventory --host hostname |
|
|
View inventory graph ansible-inventory --graph |
|
|
Use dynamic inventory script ansible-playbook -i ec2.py playbook.yml |
Playbook Structure
|
Basic playbook structure --- - name: Configure web servers hosts: webservers become: yes vars: http_port: 80 tasks: - name: Install Apache apt: name: apache2 state: present - name: Start Apache service service: name: apache2 state: started enabled: yes |
|
|
Multiple plays in one playbook --- - name: Configure web servers hosts: webservers tasks: - name: Task 1 ... - name: Configure database servers hosts: databases tasks: - name: Task 2 ... |
|
|
Include tasks from file tasks: - name: Include common tasks include_tasks: common-tasks.yml |
|
|
Import tasks from file tasks: - name: Import common tasks import_tasks: common-tasks.yml |
|
|
Include variables from file - name: Include variables include_vars: vars.yml |
Common Modules
|
apt - Manage packages (Debian/Ubuntu) - name: Install package apt: name: nginx state: present update_cache: yes - name: Remove package apt: name: nginx state: absent - name: Install multiple packages apt: name: - nginx - git - vim state: present |
|
|
yum - Manage packages (RHEL/CentOS) - name: Install package yum: name: httpd state: present - name: Install specific version yum: name: httpd-2.4.6 state: present |
|
|
package - Generic package manager - name: Install package (OS agnostic) package: name: htop state: present |
|
|
service - Manage services - name: Start and enable service service: name: nginx state: started enabled: yes - name: Restart service service: name: nginx state: restarted - name: Stop service service: name: nginx state: stopped |
|
|
copy - Copy files to remote hosts - name: Copy file copy: src: /local/path/file.txt dest: /remote/path/file.txt owner: root group: root mode: '0644' - name: Copy with inline content copy: content: "Hello World" dest: /tmp/hello.txt |
|
|
file - Manage files and directories - name: Create directory file: path: /opt/myapp state: directory mode: '0755' - name: Create symlink file: src: /path/to/source dest: /path/to/link state: link - name: Delete file file: path: /tmp/file.txt state: absent - name: Touch file file: path: /tmp/file.txt state: touch |
|
|
template - Template files using Jinja2 - name: Template a configuration file template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf owner: root group: root mode: '0644' notify: restart nginx |
|
|
lineinfile - Manage lines in files - name: Add line to file lineinfile: path: /etc/hosts line: '192.168.1.100 myserver.example.com' - name: Replace or add line lineinfile: path: /etc/ssh/sshd_config regexp: '^PermitRootLogin' line: 'PermitRootLogin no' |
|
|
user - Manage user accounts - name: Create user user: name: johndoe state: present shell: /bin/bash groups: sudo append: yes - name: Remove user user: name: johndoe state: absent remove: yes |
|
|
group - Manage groups - name: Create group group: name: developers state: present |
|
|
git - Manage git repositories - name: Clone repository git: repo: https://github.com/user/repo.git dest: /opt/myapp version: main - name: Pull latest changes git: repo: https://github.com/user/repo.git dest: /opt/myapp update: yes |
|
|
shell - Execute shell commands - name: Run shell command shell: echo "Hello" > /tmp/hello.txt args: creates: /tmp/hello.txt |
|
|
command - Execute commands - name: Run command command: ls -la /tmp args: chdir: /home/user Note: |
|
|
debug - Print debug messages - name: Print variable debug: var: ansible_hostname - name: Print message debug: msg: "The hostname is {{ ansible_hostname }}" |
|
|
assert - Assertions - name: Assert condition assert: that: - ansible_os_family == "Debian" - ansible_distribution_version >= "20.04" fail_msg: "This playbook requires Ubuntu 20.04 or later" |
|
|
uri - Interact with HTTP/HTTPS - name: Make HTTP request uri: url: https://api.example.com/health method: GET status_code: 200 |
|
|
wait_for - Wait for a condition - name: Wait for port to be available wait_for: port: 80 delay: 10 timeout: 300 |
Variables and Facts
|
Define variables in playbook vars: http_port: 80 app_name: myapp |
|
|
Use variables in tasks - name: Install {{ app_name }} apt: name: "{{ app_name }}" state: present |
|
|
Gather facts from hosts - name: Gather facts hosts: all gather_facts: yes Common facts:
- |
|
|
Disable fact gathering - name: Play without facts hosts: all gather_facts: no |
|
|
Set fact dynamically - name: Set fact set_fact: my_var: "{{ ansible_hostname }}_backup" |
|
|
Register task output as variable - name: Get disk usage shell: df -h / register: disk_usage - name: Print disk usage debug: var: disk_usage.stdout |
|
|
Variable precedence (low to high)
|
|
|
Pass extra variables via command line ansible-playbook playbook.yml -e "http_port=8080" ansible-playbook playbook.yml -e "@vars.yml" |
Conditionals and Loops
|
Conditional execution with when - name: Install Apache on Debian apt: name: apache2 state: present when: ansible_os_family == "Debian" - name: Install Apache on RedHat yum: name: httpd state: present when: ansible_os_family == "RedHat" |
|
|
Multiple conditions - name: Task with AND conditions debug: msg: "Condition met" when: - ansible_os_family == "Debian" - ansible_distribution_version >= "20.04" - name: Task with OR conditions debug: msg: "Condition met" when: ansible_os_family == "Debian" or ansible_os_family == "RedHat" |
|
|
Loop over list - name: Install packages apt: name: "{{ item }}" state: present loop: - nginx - git - vim |
|
|
Loop over dictionary - name: Create users user: name: "{{ item.key }}" state: present groups: "{{ item.value.groups }}" loop: "{{ users | dict2items }}" vars: users: alice: groups: sudo bob: groups: developers |
|
|
Loop with index - name: Print items with index debug: msg: "Item {{ item.0 }}: {{ item.1 }}" loop: "{{ packages | zip(range(packages | length)) | list }}" |
|
|
Loop until condition is met - name: Retry until success shell: /usr/bin/check-service.sh register: result until: result.rc == 0 retries: 5 delay: 10 |
Handlers
|
Define and use handlers tasks: - name: Update nginx config template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: restart nginx handlers: - name: restart nginx service: name: nginx state: restarted |
|
|
Multiple handlers tasks: - name: Update config template: src: config.j2 dest: /etc/app/config notify: - restart app - clear cache handlers: - name: restart app service: name: myapp state: restarted - name: clear cache file: path: /var/cache/myapp state: absent |
|
|
Force handler execution - name: Force handlers to run now meta: flush_handlers |
Roles
|
Role directory structure roles/
common/
tasks/
main.yml
handlers/
main.yml
templates/
config.j2
files/
script.sh
vars/
main.yml
defaults/
main.yml
meta/
main.yml |
|
|
Use role in playbook - name: Configure web servers hosts: webservers roles: - common - nginx - php |
|
|
Use role with parameters - name: Configure web servers hosts: webservers roles: - role: nginx vars: http_port: 8080 server_name: example.com |
|
|
Install role from Ansible Galaxy ansible-galaxy install geerlingguy.nginx |
|
|
List installed roles ansible-galaxy list |
|
|
Create new role structure ansible-galaxy init myrole |
|
|
Install roles from requirements file # requirements.yml - src: geerlingguy.nginx - src: geerlingguy.php # Install ansible-galaxy install -r requirements.yml |
Ansible Vault
|
Create encrypted file ansible-vault create secrets.yml |
|
|
Encrypt existing file ansible-vault encrypt vars.yml |
|
|
Edit encrypted file ansible-vault edit secrets.yml |
|
|
Decrypt file ansible-vault decrypt secrets.yml |
|
|
View encrypted file ansible-vault view secrets.yml |
|
|
Rekey encrypted file ansible-vault rekey secrets.yml |
|
|
Run playbook with vault password ansible-playbook playbook.yml --ask-vault-pass |
|
|
Use vault password file ansible-playbook playbook.yml --vault-password-file ~/.vault_pass |
|
|
Encrypt string inline ansible-vault encrypt_string 'secretpassword' --name 'db_password' Output can be used directly in playbooks:
|
Tags
|
Define tags on tasks - name: Install packages apt: name: nginx state: present tags: - packages - nginx - name: Configure nginx template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf tags: - configuration - nginx |
|
|
Tag entire play or role - name: Configure web servers hosts: webservers tags: webserver roles: - role: nginx tags: nginx |
|
|
Run only tagged tasks ansible-playbook playbook.yml --tags "configuration" ansible-playbook playbook.yml --tags "nginx,php" |
|
|
Skip tagged tasks ansible-playbook playbook.yml --skip-tags "testing" |
|
|
List all tags in playbook ansible-playbook playbook.yml --list-tags |
|
|
Special tags
- name: Always run this debug: msg: "This always runs" tags: always |
Best Practices
|
Use descriptive names # Good - name: Install and configure nginx web server ... # Bad - name: Install stuff ... |
|
|
Make tasks idempotent Tasks should be safe to run multiple times without changing the result beyond the initial run. # Idempotent - name: Ensure nginx is installed apt: name: nginx state: present # Not idempotent - name: Append to file shell: echo "line" >> /etc/config |
|
|
Use version control
|
|
|
Organize with roles
|
|
|
Test before production # Syntax check ansible-playbook playbook.yml --syntax-check # Dry run ansible-playbook playbook.yml --check # Run on test hosts first ansible-playbook playbook.yml --limit "test-servers" |
|
|
Use become appropriately # On entire play - name: System configuration hosts: all become: yes tasks: ... # On specific task - name: Install package apt: name: nginx become: yes |
|
|
Document your playbooks
|
Troubleshooting
|
Check connectivity ansible all -m ping |
|
|
Increase verbosity ansible-playbook playbook.yml -v # Level 1 ansible-playbook playbook.yml -vv # Level 2 ansible-playbook playbook.yml -vvv # Level 3 ansible-playbook playbook.yml -vvvv # Level 4 (connection debug) |
|
|
Debug variable values - name: Show all variables debug: var: hostvars[inventory_hostname] - name: Show specific variable debug: var: ansible_os_family |
|
|
List all facts ansible hostname -m setup |
|
|
Test with single host ansible-playbook playbook.yml --limit "hostname" |
|
|
Enable callback plugins for better output # ansible.cfg [defaults] stdout_callback = yaml # or stdout_callback = debug |
Notes
- Based on official Ansible documentation
- Ansible documentation: https://docs.ansible.com/
