Ansible Interview Questions 2026: The Complete Guide
Ansible remains the dominant tool for configuration management and ad-hoc automation in 2026. Whether it's provisioning servers, deploying applications, or managing configuration drift, Ansible knowledge is tested heavily in senior DevOps interviews. Here are the 20 questions that matter most.
Section 1: Ansible Architecture & Fundamentals
1. Explain the Ansible architecture
Why they ask this: They want to confirm you understand the agentless model and its implications.
Ideal answer:
Ansible is agentless — no daemon runs on managed nodes. The control node (where Ansible runs) connects to managed nodes via SSH (Linux) or WinRM (Windows) and executes modules remotely.
Components:
- Control node: Where Ansible is installed and run. Not a daemon — just the Ansible CLI tools.
- Managed nodes (hosts): Target servers. Only need SSH + Python (2.7+ or 3.5+).
- Inventory: Defines what nodes exist and how to group them.
- Modules: Units of work (copy files, install packages, restart services). Each executes on the managed node and returns JSON.
- Playbooks: YAML files defining what plays to run against which hosts.
- Roles: Reusable, structured collections of tasks, variables, handlers, and templates.
Execution flow:
1. Ansible reads playbook and inventory
2. Connects to target hosts via SSH
3. Copies the module (Python script) to the target
4. Executes the module
5. Collects result (JSON), reports pass/fail/changed
6. Cleans up the temporary module file
2. What is idempotency in Ansible and why does it matter?
Why they ask this: Idempotency is the core design principle of Ansible. Not understanding it signals shallow experience.
Ideal answer:
An operation is idempotent if running it multiple times produces the same result as running it once — with no unintended side effects on subsequent runs.
In Ansible: Most built-in modules are designed to be idempotent. If the desired state already exists, the module does nothing and reports ok. If it needs to change something, it reports changed.
Example:
- name: Ensure nginx is installed
apt:
name: nginx
state: presentRunning this 10 times: First run installs nginx (changed). Subsequent runs detect nginx is already installed and do nothing (ok).
Why it matters:
- Safe to re-run playbooks after failures without causing double-installs or config corruption
- Enables declarative infrastructure management — describe the desired state, not the steps
- Makes playbooks safe to schedule and run periodically
Non-idempotent pitfall: Using the shell or command module without creates or removes guards, or using lineinfile incorrectly, can cause duplicate entries on re-runs.
3. What is the difference between a playbook, a play, and a task?
Ideal answer:
Playbook: The top-level YAML file. Contains one or more plays.
Play: Maps a group of hosts to a list of tasks. Each play targets specific hosts and defines variables, roles, and tasks for those hosts.
Task: A single unit of work that calls one Ansible module with specific parameters.
# playbook.yml
---
- name: Configure web servers # <-- PLAY
hosts: webservers
become: true
tasks:
- name: Install nginx # <-- TASK
apt:
name: nginx
state: present
- name: Start nginx # <-- TASK
service:
name: nginx
state: started
enabled: true
- name: Configure databases # <-- PLAY 2
hosts: dbservers
roles:
- role: postgresqlRole: A reusable collection of tasks, templates, files, variables, and handlers organized into a standard directory structure. Referenced in plays via the roles: key.
4. How does Ansible inventory work?
Ideal answer:
Inventory defines the managed hosts — what they're called, how to reach them, and how they're grouped.
Static inventory (INI format):
[webservers]
web1.example.com
web2.example.com ansible_user=ubuntu ansible_port=2222
[dbservers]
db1.example.com
db2.example.com
[production:children]
webservers
dbservers
[all:vars]
ansible_python_interpreter=/usr/bin/python3YAML format (preferred):
all:
children:
webservers:
hosts:
web1.example.com:
web2.example.com:
dbservers:
hosts:
db1.example.com:Dynamic inventory: A script or plugin that generates inventory on the fly from an external source (AWS EC2, GCP, Azure, Kubernetes). Ansible calls the script/plugin at runtime and receives JSON. Common plugins: amazon.aws.ec2, azure.azcollection.azure_rm.
Host variables: Defined inline (as above), in host_vars/, or in group_vars files.
5. Explain Ansible variable precedence
Why they ask this: Variable precedence bugs are common in large playbooks. Knowing the order separates senior from junior.
Ideal answer:
Ansible has 22 levels of variable precedence. The most important (lowest to highest):
1. Role defaults (defaults/main.yml) — lowest, easily overridable
2. Inventory vars
3. Group vars (group_vars/all, then specific groups)
4. Host vars
5. Play vars
6. Role vars (vars/main.yml)
7. Task vars (vars: in a task)
8. set_fact / register
9. --extra-vars (-e) — highest, always wins
Practical rule:
- Put defaults in
defaults/main.yml— these are meant to be overridden by operators - Put non-overridable role config in
vars/main.yml - Use
--extra-varsfor deployment-time values (version numbers, feature flags)
Common gotcha: group_vars/all has lower precedence than group_vars/webservers. So a more specific group's variables override the all group.
Section 2: Playbooks, Roles & Modules
6. What is an Ansible role and how do you structure one?
Ideal answer:
A role is a reusable, self-contained unit of automation with a standard directory structure:
roles/
└── nginx/
├── defaults/
│ └── main.yml # Default variables (low precedence, overridable)
├── vars/
│ └── main.yml # Role variables (high precedence)
├── tasks/
│ └── main.yml # Main task list
├── handlers/
│ └── main.yml # Handlers (triggered by notify)
├── templates/
│ └── nginx.conf.j2 # Jinja2 templates
├── files/
│ └── ssl.crt # Static files
├── meta/
│ └── main.yml # Role metadata and dependencies
└── README.mdUse a role when: The same set of tasks is needed across multiple playbooks or projects. Roles are shareable, testable units.
Galaxy: Ansible Galaxy is the public role repository. ansible-galaxy install geerlingguy.nginx downloads a community role. Collections are the modern packaging format (roles + modules + plugins).
7. What are Ansible handlers and when do you use them?
Ideal answer:
Handlers are tasks that run only when notified by another task — and only once at the end of the play, regardless of how many tasks notify them.
Use case: Restart a service when its configuration changes — but only once, even if multiple config files changed.
tasks:
- name: Update nginx config
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart nginx # notify the handler
- name: Update nginx ssl cert
copy:
src: ssl.crt
dest: /etc/nginx/ssl.crt
notify: Restart nginx # same handler, still runs only once
handlers:
- name: Restart nginx
service:
name: nginx
state: restartedKey behavior: Handlers only run if the notifying task reports changed. If nginx.conf didn't change (already correct), the handler won't run.
Force handler run: Use meta: flush_handlers to run pending handlers immediately rather than waiting for end of play.
8. When do you use the shell module vs command module?
Ideal answer:
command module: Runs a command without going through a shell. Safer — no shell expansion, no pipes, no redirects. Use for simple executable calls.
- command: /usr/bin/myapp --versionshell module: Runs command through /bin/sh. Supports pipes, redirects, shell variables, glob expansion. Needed for shell-specific operations.
- shell: ps aux | grep nginx | grep -v grep | wc -l
register: nginx_process_countWhen to use each:
- Prefer
command— safer, no injection risk - Use
shellonly when you need shell features - Consider purpose-built modules first:
apt,systemd,copy,templateare idempotent,shell/commandare not
Making shell/command idempotent: Use creates (skip if file exists) or removes (skip if file doesn't exist) arguments, or wrap in a when condition.
9. What is Ansible Vault and how do you use it?
Ideal answer:
Ansible Vault encrypts sensitive data (passwords, API keys, certificates) in YAML files using AES-256 encryption.
Encrypt a file:
ansible-vault encrypt secrets.yml
ansible-vault edit secrets.yml
ansible-vault view secrets.ymlEncrypt a string (embed in variable files):
ansible-vault encrypt_string 'mysecretpassword' --name 'db_password'Output embeds the encrypted value directly in your vars file.
Running playbooks with vault:
ansible-playbook site.yml --vault-password-file ~/.vault_pass
# or interactively:
ansible-playbook site.yml --ask-vault-passMultiple vault IDs: Ansible supports multiple vault passwords — useful when different teams own different secret files.
CI/CD integration: Store the vault password in your CI secrets, pass via --vault-password-file or ANSIBLE_VAULT_PASSWORD_FILE env variable.
Alternative for 2026: Consider HashiCorp Vault or cloud secret managers (AWS Secrets Manager, Azure Key Vault) with the community.hashi_vault collection for more sophisticated secret rotation and auditing.
10. How do you handle errors and failures in Ansible playbooks?
Ideal answer:
ignore_errors: true: Task failure doesn't stop the play. Use sparingly — can hide real failures.
failed_when: Define custom failure conditions.
- command: myapp --check
register: result
failed_when: result.rc != 0 and "already configured" not in result.stdoutblock / rescue / always: Ansible's try-catch equivalent.
- block:
- name: Risky task
command: /usr/bin/risky
rescue:
- name: Handle failure
debug:
msg: "Risky task failed, running recovery"
always:
- name: Always runs
debug:
msg: "Cleanup"any_errors_fatal: true: Stop all hosts immediately if any host fails — useful when partial deployments are worse than no deployment.
max_fail_percentage: Allow a percentage of hosts to fail before aborting the play. Useful for rolling deployments.
Section 3: Advanced Ansible
11. How do you write a dynamic inventory for AWS EC2?
Ideal answer:
The amazon.aws.ec2 inventory plugin connects to AWS and dynamically builds inventory from EC2 instances.
Install collection: ansible-galaxy collection install amazon.aws
Inventory config file (aws_ec2.yml):
plugin: amazon.aws.ec2
regions:
- us-east-1
- us-west-2
filters:
instance-state-name: running
tag:Environment: production
keyed_groups:
- key: tags.Role
prefix: role
- key: placement.availability_zone
hostnames:
- private-ip-addressUsage:
ansible-inventory -i aws_ec2.yml --list
ansible-playbook -i aws_ec2.yml site.ymlResult: Instances with tag Role=webserver are automatically grouped under role_webserver. No manual inventory maintenance needed.
12. How do you use Ansible with containers and Kubernetes?
Ideal answer:
Ansible can manage both Docker containers and Kubernetes resources.
Docker (community.docker collection):
- name: Run application container
community.docker.docker_container:
name: myapp
image: myapp:1.2.3
state: started
ports:
- "8080:8080"
env:
DATABASE_URL: "{{ db_url }}"Kubernetes (kubernetes.core collection):
- name: Apply Kubernetes deployment
kubernetes.core.k8s:
state: present
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: productionWhen Ansible vs Helm for K8s: Ansible is useful for orchestrating multi-step workflows that combine Kubernetes operations with external systems (DNS, load balancer config, database provisioning). For pure Kubernetes application deployment, Helm or Kustomize is more appropriate.
13. What is AWX / Ansible Automation Platform?
Ideal answer:
AWX is the open-source upstream project for Ansible Automation Platform (Red Hat's commercial offering). It provides a web UI, REST API, and execution management layer for Ansible.
What it adds over raw Ansible:
- Web UI: Run playbooks, manage inventory, view job history without CLI
- Role-based access control: Team-level permissions for running specific playbooks against specific inventories
- Credential management: Centralized, encrypted credential storage (SSH keys, cloud credentials, Vault passwords)
- Job scheduling: Run playbooks on a schedule (like cron, but with history and notifications)
- Notifications: Slack/email alerts on job success/failure
- REST API: Trigger playbook runs from CI/CD pipelines or external systems
- Workflows: Chain multiple playbooks into complex workflows with conditional branching
When to use AWX: When multiple teams need to run Ansible automation, when you need audit trails, or when you need to give non-engineers a safe interface to trigger specific automation.
14. How do you use `delegate_to` and `run_once` in Ansible?
Ideal answer:
delegate_to: Run a task on a different host than the current play host. Useful for tasks that need to run on a specific machine (database host, load balancer) during a playbook targeting other hosts.
- name: Remove host from load balancer
command: /usr/bin/haproxy-remove {{ inventory_hostname }}
delegate_to: loadbalancer.example.com
- name: Update application
apt:
name: myapp
state: latest
- name: Add host back to load balancer
command: /usr/bin/haproxy-add {{ inventory_hostname }}
delegate_to: loadbalancer.example.comrun_once: true: Run a task only once, on the first host in the group, even though the play targets multiple hosts. Use for tasks that should happen once per cluster (e.g., database schema migration during a rolling deploy).
- name: Run database migration (once per deployment)
command: rails db:migrate
run_once: true
delegate_to: "{{ groups['appservers'][0] }}"15. How do you test Ansible roles with Molecule?
Ideal answer:
Molecule is the standard testing framework for Ansible roles. It provisions ephemeral instances, runs the role, verifies the result, and tears down.
Initialize a role with Molecule:
molecule init role my-role --driver-name dockerMolecule directory structure:
molecule/
└── default/
├── molecule.yml # Driver config (Docker, Vagrant, EC2...)
├── converge.yml # Playbook that applies the role
├── verify.yml # Verification playbook (or use Testinfra/Goss)
└── prepare.yml # Optional pre-role setupTest lifecycle:
molecule create # Spin up test instances
molecule converge # Apply the role
molecule verify # Run verifications
molecule destroy # Tear down
molecule test # All steps in sequence (CI-friendly)Verification options: Use Ansible tasks in verify.yml (simple), or testinfra (Python-based, more expressive for integration testing).
16. Ansible vs Terraform vs Chef/Puppet: when do you use each?
Ideal answer:
Terraform: Infrastructure provisioning. Creates/destroys cloud resources (VMs, networks, databases, DNS). Declarative, stateful (tracks what it created). Not designed for configuration management inside servers.
Ansible: Configuration management and application deployment. Connects to existing servers and configures them. Agentless, procedural (runs tasks in order), stateless (no central state file). Also good for cloud resource management but less powerful than Terraform for complex IaC.
Chef/Puppet: Agent-based configuration management. Agents run on managed nodes on a schedule, pull config from a central server, enforce desired state continuously. Better for large-scale drift correction but higher operational overhead.
How they complement each other:
- Terraform provisions the server → Ansible configures it (most common)
- Terraform manages infrastructure → Kubernetes + Helm manages applications
- Chef/Puppet for large fleets with strict compliance requirements
2026 reality: Terraform + Ansible is the dominant pairing for most DevOps teams. Chef/Puppet usage has declined significantly except in large enterprise environments.
17. How do you optimize Ansible playbook performance?
Ideal answer:
forks: By default, Ansible runs against 5 hosts in parallel. Increase with -f 20 or forks = 20 in ansible.cfg. Set based on control node capacity.
pipelining: Reduces SSH connections by sending multiple module operations over a single connection.
# ansible.cfg
[connection]
pipelining = TrueRequires requiretty disabled in sudoers on managed nodes.
gather_facts: false: Fact gathering (the setup module) adds ~1-2 seconds per host. Disable when facts aren't needed.
--limit: Target only specific hosts or groups rather than running against all.
Strategy plugins:
linear(default): All hosts run task N before any host runs task N+1free: Each host runs through the playbook as fast as possible, independentlymitogen: Drop-in strategy plugin that dramatically speeds up Ansible (3-7x) by replacing the SSH transport with a Python-based connection framework
Caching: Enable fact caching (Redis or JSON file) so facts don't need to be gathered every run.
18. How do you use Ansible tags?
Ideal answer:
Tags let you selectively run or skip parts of a playbook without maintaining multiple playbooks.
Applying tags:
- name: Install packages
apt:
name: "{{ item }}"
loop: "{{ packages }}"
tags: [install, packages]
- name: Configure application
template:
src: app.conf.j2
dest: /etc/app/app.conf
tags: [configure, app]Running with tags:
# Run only tasks tagged with 'configure'
ansible-playbook site.yml --tags configure
# Skip tasks tagged with 'install'
ansible-playbook site.yml --skip-tags install
# Run everything
ansible-playbook site.ymlSpecial tags: always (always runs even when other tags are specified), never (only runs when explicitly requested).
CI/CD use: Tag deployment tasks separately from installation tasks. During routine deploys, skip install to only run configure and deploy tasks — much faster.
19. How do you integrate Ansible into a CI/CD pipeline?
Ideal answer:
GitHub Actions example:
- name: Deploy with Ansible
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Ansible
run: pip install ansible boto3
- name: Configure SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
- name: Run playbook
run: |
ansible-playbook -i aws_ec2.yml site.yml --extra-vars "version=${{ github.sha }}" --vault-password-file <(echo "${{ secrets.VAULT_PASS }}")AWX REST API trigger (from any CI):
curl -X POST https://awx.example.com/api/v2/job_templates/42/launch/ -H "Authorization: Bearer $AWX_TOKEN" -d '{"extra_vars": {"version": "'"$GIT_SHA"'"}}'Best practices:
- Store vault password in CI secrets, never in the repository
- Use dynamic inventory — never hardcode IPs
- Run
ansible-lintin CI before execution - Use
--check(dry-run) +--diffon PR review to show what would change
20. Walk me through debugging a failing Ansible playbook
Why they ask this: Real-world troubleshooting skill. They want systematic thinking, not guesswork.
Step-by-step:
Step 1: Increase verbosity
ansible-playbook site.yml -v # basic output
ansible-playbook site.yml -vvvv # max verbosity (SSH debug, raw output)Step 2: Check the error message carefully
FAILED! => {"msg": "..."} output tells you the module, the host, and the error. Read it fully before guessing.
Step 3: Test connectivity
ansible all -i inventory -m ping
ansible webservers -m setup # gather facts to test connectivity + PythonStep 4: Run on a single host
ansible-playbook site.yml --limit web1.example.comStep 5: Use --check + --diff
Dry run showing what would change — often reveals the issue without making changes.
Step 6: Debug with debug module
- debug:
var: my_variable
- debug:
msg: "{{ some_complex_expression }}"Step 7: Check ansible-lint
ansible-lint site.ymlCatches common issues: deprecated modules, unsafe practices, YAML errors.
Common root causes: SSH key not trusted, Python not found on managed node, privilege escalation config, missing variable, module not available (collection not installed).
