Ansible Deep Dive — Roles, Collections, Vault, AAP & OCP
1. Roles
What is a Role?
A Role is a structured, reusable unit of automation — it organizes tasks, variables, files, templates, and handlers into a standardized directory layout.
Role Directory Structure
roles/└── my-webserver/ ├── tasks/ │ └── main.yml # Entry point — all tasks ├── handlers/ │ └── main.yml # Handlers (restart, reload) ├── templates/ │ └── nginx.conf.j2 # Jinja2 templates ├── files/ │ └── index.html # Static files to copy ├── vars/ │ └── main.yml # High-priority variables ├── defaults/ │ └── main.yml # Low-priority defaults (overridable) ├── meta/ │ └── main.yml # Role metadata, dependencies └── README.md
tasks/main.yml
---- name: Install nginx ansible.builtin.yum: name: nginx state: present- name: Deploy config from template ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: Restart nginx- name: Ensure nginx is started ansible.builtin.service: name: nginx state: started enabled: true
defaults/main.yml
---nginx_port: 80nginx_worker_processes: autonginx_max_connections: 1024
templates/nginx.conf.j2 (Jinja2)
worker_processes {{ nginx_worker_processes }};events { worker_connections {{ nginx_max_connections }};}server { listen {{ nginx_port }}; server_name {{ ansible_hostname }};}
meta/main.yml — Role Dependencies
---dependencies: - role: common - role: firewall vars: open_ports: - 80 - 443
Using a Role in a Playbook
- name: Configure web servers hosts: webservers become: true roles: - common - my-webserver # Simple include # OR with parameters: roles: - role: my-webserver vars: nginx_port: 8080
Role Execution Order in a Play
pre_tasks → role dependencies → roles → tasks → post_tasks → handlers
2. Collections
What is a Collection?
A Collection is a distribution format for Ansible content — it packages roles, modules, plugins, playbooks, and docs together under a namespace.
namespace.collection_name └── ansible.builtin # Core Ansible modules └── redhat.openshift # OCP-specific modules └── community.kubernetes # K8s modules └── amazon.aws # AWS modules
Collection Directory Structure
my_namespace/my_collection/├── galaxy.yml # Collection metadata├── README.md├── roles/│ └── my_role/├── plugins/│ ├── modules/ # Custom modules│ ├── inventory/ # Dynamic inventory plugins│ └── filter/ # Custom Jinja2 filters├── playbooks/└── docs/
Installing Collections
# From Ansible Galaxyansible-galaxy collection install redhat.openshift# From requirements file (preferred)ansible-galaxy collection install -r requirements.yml# From Automation Hub (AAP)ansible-galaxy collection install redhat.openshift \ --server https://cloud.redhat.com/api/automation-hub/# Offline / from tarballansible-galaxy collection install my_namespace-my_collection-1.0.0.tar.gz
requirements.yml
---collections: - name: redhat.openshift version: ">=2.0.0" - name: community.kubernetes version: "2.0.0" - name: amazon.aws version: ">=5.0.0"roles: - name: geerlingguy.nginx version: "3.0.0"
Key Collections for OCP/K8s
| Collection | Use |
|---|---|
redhat.openshift | OCP-specific — routes, builds, operators |
kubernetes.core | Core K8s module (k8s, helm, kubectl) |
community.kubernetes | Community K8s modules |
redhat.rhel_system_roles | RHEL OS config |
ansible.posix | POSIX system modules |
amazon.aws | AWS provisioning |
Using Collection Modules
- name: Deploy OCP application hosts: localhost collections: - redhat.openshift - kubernetes.core tasks: - name: Create namespace kubernetes.core.k8s: state: present definition: apiVersion: v1 kind: Namespace metadata: name: my-app - name: Deploy from template kubernetes.core.k8s: state: present src: deployment.yaml - name: Create OCP Route redhat.openshift.openshift_route: namespace: my-app service: my-service state: present
3. Ansible Vault
What is Vault?
Ansible Vault encrypts sensitive data — passwords, API keys, certificates — at rest in YAML files using AES-256 encryption.
Encrypting Files
# Encrypt an entire fileansible-vault encrypt secrets.yml# Decrypt a fileansible-vault decrypt secrets.yml# View without decrypting to diskansible-vault view secrets.yml# Edit encrypted fileansible-vault edit secrets.yml# Re-key (change password)ansible-vault rekey secrets.yml# Encrypt a single string valueansible-vault encrypt_string 'mysecretpassword' \ --name 'db_password'
Encrypted String Output
# Output of encrypt_string — paste directly into vars filedb_password: !vault | $ANSIBLE_VAULT;1.1;AES256 61386634653335343832333938343039303664653764323035 64356635333562303937363135626565353537306261363539 ...
Vault in Variable Files
# group_vars/all/vault.yml ← encrypted filevault_db_password: supersecret123vault_api_key: abc123xyz# group_vars/all/vars.yml ← plaintext, references vault varsdb_password: "{{ vault_db_password }}"api_key: "{{ vault_api_key }}"
Running Playbooks with Vault
# Prompt for passwordansible-playbook site.yml --ask-vault-pass# Use password fileansible-playbook site.yml --vault-password-file ~/.vault_pass# Use environment variableexport ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_passansible-playbook site.yml# Multiple vault IDs (different passwords for different files)ansible-playbook site.yml \ --vault-id dev@~/.vault_pass_dev \ --vault-id prod@prompt
Multiple Vault IDs
# Encrypt with a specific vault ID labelansible-vault encrypt_string 'prodpassword' \ --name 'db_password' \ --vault-id prod@~/.vault_pass_prod# Result:db_password: !vault | $ANSIBLE_VAULT;1.2;AES256;prod ← vault ID label ...
Best Practices
- Never commit plaintext secrets to git
- Store vault password file outside the repo
- Use separate vault IDs per environment (dev/staging/prod)
- Encrypt the vars file, not the whole playbook
- Use
ansible-vault encrypt_stringfor individual values in otherwise plaintext files
4. Ansible Automation Platform (AAP)
What is AAP?
AAP (formerly Ansible Tower) is the enterprise version of Ansible — adds a Web UI, REST API, RBAC, job scheduling, audit logging, credential management, and execution environments.
AAP Architecture
┌──────────────────────────────────────────────────┐│ Ansible Automation Platform ││ ││ ┌────────────┐ ┌──────────────────────────┐ ││ │ Automation │ │ Automation Controller │ ││ │ Hub │ │ (formerly Tower) │ ││ │(Collections│ │ - Job Templates │ ││ │ & roles) │ │ - Workflows │ ││ └────────────┘ │ - Schedules │ ││ │ - RBAC │ ││ ┌────────────┐ │ - Credentials │ ││ │ Event │ └──────────────────────────┘ ││ │ Driven │ ││ │ Ansible │ ┌──────────────────────────┐ ││ │ (EDA) │ │ Execution Environments │ ││ └────────────┘ │ (containerized runtime) │ ││ └──────────────────────────┘ │└──────────────────────────────────────────────────┘
Key AAP Concepts
| Concept | Description |
|---|---|
| Inventory | Static or dynamic host groups |
| Credential | Stored secrets (SSH, cloud, vault) — never exposed |
| Project | SCM-linked (Git) source for playbooks |
| Job Template | Reusable job definition — playbook + inventory + credential |
| Workflow | Chain multiple job templates with conditions |
| Execution Environment (EE) | Container image with Ansible + dependencies |
| Organization | Multi-tenancy unit — groups users, teams, resources |
| RBAC | Role-based access — Admin, Execute, Read per resource |
| Notification | Alerts on job success/failure (Slack, email, webhook) |
| Survey | Runtime input form for job templates |
Execution Environments (EE)
# execution-environment.ymlversion: 1build_arg_defaults: EE_BASE_IMAGE: registry.redhat.io/ansible-automation-platform/ee-minimal-rhel8dependencies: galaxy: requirements.yml python: requirements.txt system: bindep.txtadditional_build_steps: prepend: - RUN pip3 install boto3
# Build EE with ansible-builderpip install ansible-builderansible-builder build -t my-ee:1.0 -f execution-environment.yml# Push to registrypodman push my-ee:1.0 registry.example.com/my-ee:1.0
Event-Driven Ansible (EDA)
EDA triggers automation based on events from external sources.
# rulebook.yml- name: Respond to alerts hosts: all sources: - ansible.eda.webhook: # Listen on webhook host: 0.0.0.0 port: 5000 - ansible.eda.kafka: # Or Kafka topic host: kafka.example.com topic: alerts rules: - name: Restart service on alert condition: event.payload.alertname == "ServiceDown" action: run_job_template: name: Restart Service organization: Default - name: Scale up on high CPU condition: event.payload.metric > 80 action: run_playbook: name: scale-up.yml
5. Ansible for OpenShift — Practical Examples
Install OCP Cluster (IPI)
- name: Install OpenShift cluster hosts: localhost collections: - redhat.openshift_installer tasks: - name: Generate install-config template: src: install-config.yaml.j2 dest: "{{ install_dir }}/install-config.yaml" - name: Run openshift-install command: > openshift-install create cluster --dir {{ install_dir }} --log-level info
Day-2 OCP Operations
- name: OCP Day-2 Configuration hosts: localhost collections: - redhat.openshift - kubernetes.core tasks: - name: Create htpasswd identity provider kubernetes.core.k8s: state: present definition: "{{ lookup('template', 'oauth.yaml.j2') }}" - name: Apply resource quotas kubernetes.core.k8s: state: present definition: apiVersion: v1 kind: ResourceQuota metadata: name: team-quota namespace: "{{ item }}" spec: hard: pods: "20" requests.cpu: "4" requests.memory: 8Gi loop: "{{ namespaces }}" - name: Deploy OADP operator kubernetes.core.k8s: state: present src: oadp-subscription.yaml - name: Wait for operator to be ready kubernetes.core.k8s_info: kind: ClusterServiceVersion namespace: openshift-adp register: csv until: > csv.resources | selectattr('status.phase','equalto','Succeeded') | list | length > 0 retries: 20 delay: 30
Interview Quick-Fire
- Difference between
varsanddefaultsin a role?defaultslowest priority — easily overridden.varshigher priority — harder to override. - What is
ansible_facts? Auto-gathered system info (OS, IP, memory) available as variables. - How do you run only specific tasks? Use
--tagsor--skip-tags. - What is
delegate_to? Run a task on a different host than the current one. - Difference between
include_tasksandimport_tasks?importis static (parsed at startup);includeis dynamic (evaluated at runtime — supports loops/conditions). - What is an inventory plugin? Dynamically generates inventory from external sources (AWS, Azure, OCP).
- How do you test Ansible roles? Using Molecule — spins up containers/VMs, runs the role, verifies with testinfra or ansible assertions.