โ๏ธ
Ansible
Ansible CLI commands and playbook patterns for configuration management and automation
Ad-hoc Commands
Run one-off tasks against hosts without writing a playbook
bashยทPing all hosts
ansible all -m ping
bashยทPing a specific group
ansible webservers -m ping
bashยทRun shell command on all hosts
ansible all -m shell -a 'uptime'
bashยทCopy file to hosts
ansible all -m copy -a 'src=./app.conf dest=/etc/app/app.conf owner=root mode=0644'
bashยทInstall package (apt)
ansible all -m apt -a 'name=nginx state=present' --become
bashยทRemove package
ansible all -m apt -a 'name=nginx state=absent' --become
bashยทRestart a service
ansible all -m service -a 'name=nginx state=restarted' --become
bashยทGather facts from hosts
ansible all -m setup
bashยทGather specific fact
ansible all -m setup -a 'filter=ansible_distribution*'
bashยทRun as a different user
ansible all -m shell -a 'whoami' --become --become-user=postgres
bashยทLimit to one host
ansible all -m ping --limit web01.example.com
Inventory
Define and inspect static and dynamic inventories
bashยทList all hosts in inventory
ansible all --list-hosts
bashยทList hosts in a group
ansible webservers --list-hosts
bashยทUse a custom inventory file
ansible all -i inventory/prod.ini --list-hosts
bashยทUse dynamic inventory script
ansible all -i inventory/aws_ec2.yml --list-hosts
bashยทGraph group hierarchy
ansible-inventory --graph
bashยทShow host vars as JSON
ansible-inventory --host <hostname>
bashยทDump full inventory as JSON
ansible-inventory --list
iniยทStatic inventory file (INI)
[webservers] web01.example.com ansible_user=ubuntu web02.example.com ansible_user=ubuntu [dbservers] db01.example.com ansible_user=postgres ansible_port=2222 [production:children] webservers dbservers [production:vars] ansible_ssh_private_key_file=~/.ssh/prod_key
yamlยทDynamic AWS EC2 inventory (YAML)
plugin: amazon.aws.aws_ec2
regions:
- us-east-1
filters:
tag:Environment: production
instance-state-name: running
keyed_groups:
- key: tags.Role
prefix: role
hostnames:
- private-ip-addressRunning Playbooks
Execute, test and control playbook runs
bashยทRun a playbook
ansible-playbook site.yml
bashยทRun with custom inventory
ansible-playbook -i inventory/prod.ini site.yml
bashยทDry run (check mode)
ansible-playbook site.yml --check
bashยทDry run with diff output
ansible-playbook site.yml --check --diff
bashยทLimit to specific hosts or groups
ansible-playbook site.yml --limit webservers
bashยทRun only specific tags
ansible-playbook site.yml --tags deploy
bashยทSkip specific tags
ansible-playbook site.yml --skip-tags restart
bashยทStart from a specific task
ansible-playbook site.yml --start-at-task='Configure nginx'
bashยทStep through tasks interactively
ansible-playbook site.yml --step
bashยทPass extra variables
ansible-playbook site.yml -e 'env=prod version=1.2.3'
bashยทPass extra variables from file
ansible-playbook site.yml -e @vars/prod.yml
bashยทIncrease verbosity (up to -vvvv)
ansible-playbook site.yml -vv
bashยทFork across 20 hosts in parallel
ansible-playbook site.yml --forks=20
Playbook Patterns
Common playbook structures and task idioms
yamlยทBasic playbook structure
---
- name: Configure web servers
hosts: webservers
become: true
vars:
app_port: 8080
pre_tasks:
- name: Update apt cache
apt:
update_cache: true
cache_valid_time: 3600
tasks:
- name: Install nginx
apt:
name: nginx
state: present
- name: Deploy config
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
mode: "0644"
notify: Restart nginx
handlers:
- name: Restart nginx
service:
name: nginx
state: restartedyamlยทLoop over a list
- name: Install required packages
apt:
name: "{{ item }}"
state: present
loop:
- git
- curl
- unzip
- build-essentialyamlยทConditionals with when
- name: Install on Debian-based systems only
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
- name: Install on RedHat-based systems only
yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"yamlยทRegister and use task output
- name: Check if app is running shell: pgrep -x myapp register: app_status ignore_errors: true - name: Start app if not running shell: /opt/myapp/start.sh when: app_status.rc != 0
yamlยทBlock with rescue and always
- block:
- name: Run risky task
shell: /opt/deploy.sh
- name: Run follow-up task
shell: /opt/verify.sh
rescue:
- name: Rollback on failure
shell: /opt/rollback.sh
always:
- name: Send notification
uri:
url: https://hooks.example.com/notify
method: POSTyamlยทSerial rolling deploy (one host at a time)
- name: Rolling deploy
hosts: webservers
serial: 1 # or "25%" for 25% at a time
max_fail_percentage: 0
tasks:
- name: Pull latest image
shell: docker pull myapp:latest
- name: Restart container
shell: docker-compose up -d --no-deps myappVariables & Jinja2 Templates
Variable precedence, filters and Jinja2 template patterns
yamlยทVariable precedence (low โ high)
# Low priority (define defaults here) # roles/myrole/defaults/main.yml app_port: 8080 app_workers: 4 # Medium priority (role-specific vars) # roles/myrole/vars/main.yml app_log_level: info # High priority (host/group specific) # inventory/group_vars/webservers.yml app_port: 443 # Highest priority (CLI override) # ansible-playbook site.yml -e 'app_port=9090'
yamlยทCommon Jinja2 filters
# String manipulation
"{{ app_name | upper }}" # MYAPP
"{{ app_name | replace('-', '_') }}" # my_app
"{{ app_name | default('myapp') }}" # fallback if undefined
# List operations
"{{ packages | join(', ') }}" # git, curl, unzip
"{{ users | length }}" # count items
"{{ items | select('match','web*') | list }}"
# Paths and types
"{{ '/etc/app' | basename }}" # app
"{{ value | int }}" # cast to integer
"{{ value | bool }}" # cast to boolean
"{{ data | to_json }}" # serialize to JSONyamlยทJinja2 template file (nginx.conf.j2)
upstream backend {
{% for host in groups['appservers'] %}
server {{ hostvars[host]['ansible_host'] }}:{{ app_port }};
{% endfor %}
}
server {
listen 80;
server_name {{ inventory_hostname }};
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
}
}yamlยทEncrypt a variable with Vault inline
# In vars file โ value was encrypted with: # ansible-vault encrypt_string 'mysecret' --name 'db_password' db_password: !vault | $ANSIBLE_VAULT;1.1;AES256 61383032303361343139616331373538...
Ansible Vault
Encrypt and manage secrets in playbooks and var files
bashยทEncrypt a file
ansible-vault encrypt vars/secrets.yml
bashยทDecrypt a file
ansible-vault decrypt vars/secrets.yml
bashยทView encrypted file without decrypting on disk
ansible-vault view vars/secrets.yml
bashยทEdit encrypted file in-place
ansible-vault edit vars/secrets.yml
bashยทRe-encrypt with a new password
ansible-vault rekey vars/secrets.yml
bashยทEncrypt a single string value
ansible-vault encrypt_string 'mysecretvalue' --name 'db_password'
bashยทRun playbook with vault password prompt
ansible-playbook site.yml --ask-vault-pass
bashยทRun playbook with vault password file
ansible-playbook site.yml --vault-password-file ~/.vault_pass
bashยทUse multiple vault IDs (multi-key)
ansible-playbook site.yml --vault-id dev@~/.vault_dev --vault-id prod@~/.vault_prod
Roles
Create, structure and reuse Ansible roles
bashยทCreate a new role scaffold
ansible-galaxy role init myrole
bashยทRole directory structure
roles/myrole/ โโโ defaults/main.yml # low-priority default vars โโโ vars/main.yml # high-priority role vars โโโ tasks/main.yml # task entry point โโโ handlers/main.yml # handlers โโโ templates/ # Jinja2 .j2 files โโโ files/ # static files to copy โโโ meta/main.yml # role dependencies โโโ README.md
yamlยทUse a role in a playbook
- name: Deploy app
hosts: webservers
roles:
- common
- role: nginx
vars:
nginx_port: 443
- role: myapp
tags: deploybashยทInstall role from Ansible Galaxy
ansible-galaxy role install geerlingguy.nginx
bashยทInstall roles from requirements file
ansible-galaxy install -r requirements.yml
bashยทList installed roles
ansible-galaxy role list
bashยทRemove a role
ansible-galaxy role remove geerlingguy.nginx
yamlยทrequirements.yml for roles and collections
---
roles:
- name: geerlingguy.nginx
version: "3.2.0"
- src: https://github.com/myorg/myrole.git
scm: git
version: main
collections:
- name: amazon.aws
version: ">=7.0.0"
- name: community.generalCollections & Galaxy
Install and manage Ansible collections
bashยทInstall a collection
ansible-galaxy collection install amazon.aws
bashยทInstall collection at specific version
ansible-galaxy collection install amazon.aws:==7.2.0
bashยทInstall collections from requirements.yml
ansible-galaxy collection install -r requirements.yml
bashยทList installed collections
ansible-galaxy collection list
bashยทUpgrade a collection
ansible-galaxy collection install amazon.aws --upgrade
bashยทBuild a collection tarball
ansible-galaxy collection build
bashยทPublish collection to Galaxy
ansible-galaxy collection publish myorg-mycollection-1.0.0.tar.gz --token <api-token>
Debugging & Testing
Lint, debug and test playbooks and roles
bashยทLint playbook with ansible-lint
ansible-lint site.yml
bashยทLint entire project
ansible-lint
bashยทSyntax check only (no connection)
ansible-playbook site.yml --syntax-check
bashยทList all tasks a playbook would run
ansible-playbook site.yml --list-tasks
bashยทList all hosts a playbook targets
ansible-playbook site.yml --list-hosts
bashยทList all tags in a playbook
ansible-playbook site.yml --list-tags
yamlยทDebug task โ print variable value
- name: Print variable
debug:
var: my_variable
- name: Print message with interpolation
debug:
msg: "App version is {{ app_version }}, port is {{ app_port }}"
- name: Dump all host facts
debug:
var: hostvars[inventory_hostname]yamlยทAssert task โ fail fast on bad state
- name: Ensure app version is set
assert:
that:
- app_version is defined
- app_version | length > 0
- app_port | int > 1024
fail_msg: "app_version must be defined and app_port > 1024"
success_msg: "Assertions passed"bashยทTest role with Molecule (init)
molecule init scenario --driver-name docker
bashยทRun Molecule tests
molecule test
bashยทMolecule converge only (no verify/destroy)
molecule converge