โš™๏ธ

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-address

Running 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: restarted
yamlยทLoop over a list
- name: Install required packages
  apt:
    name: "{{ item }}"
    state: present
  loop:
    - git
    - curl
    - unzip
    - build-essential
yamlยท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: POST
yamlยท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 myapp

Variables & 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 JSON
yamlยท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: deploy
bashยท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.general

Collections & 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