# Introduction to Ansible Ansible is an open-source **IT automation tool** that automates: - **Configuration management** - setting up servers - **Application deployment** - deploying software - **Task automation** - repetitive operations ## Key Features - **Agentless** - no software needed on remote servers - **YAML-based** - human-readable playbooks - **Idempotent** - safe to run multiple times - **SSH-based** - uses existing SSH infrastructure ## Core Concepts ### Inventory File listing managed hosts (servers): ```ini [webservers] web1.example.com web2.example.com [databases] db1.example.com ``` ### Playbooks YAML files describing desired state: ```yaml - name: Install nginx hosts: webservers tasks: - name: Install nginx apt: name: nginx state: present ``` ### Modules Reusable units of work (apt, yum, copy, service, etc.) ### Roles Organized collections of tasks, handlers, and files ## Quick Start ### Ansible Navigator [Ansible Navigator](https://ansible-navigator.readthedocs.io/en/stable/) is a CLI tool for exploring and interacting with Ansible content. It provides: - Playbook visualization - Task execution tracking - Inventory exploration - Interactive shell for testing playbooks - Integration with Ansible Core features Use `ansible-navigator` to: 1. Explore playbooks and roles 2. Run ad-hoc commands 3. Debug playbook execution 4. Manage inventory files 5. Test YAML syntax ```bash ansible-navigator run playbook.yml ansible-navigator explore ansible-navigator shell ``` 1. Install: `pip install ansible` 2. Create inventory file 3. Write playbook 4. Run: `ansible-playbook playbook.yml` ## Ad-Hoc Commands ```bash ansible all -m ping ansible all -m command -a "uptime" ansible webserver -m apt -a "name=vim state=present" ``` Ansible is ideal for orchestrating infrastructure as code across cloud, on-premise, and hybrid environments. --- ## Handlers Handlers are tasks that only run when notified by other tasks (typically after a change): ```yaml - name: Install nginx hosts: webservers tasks: - name: Install nginx apt: name: nginx state: present notify: Restart nginx handlers: - name: Restart nginx service: name: nginx state: restarted ``` ## Variables Define and use variables for flexibility: ```yaml - name: Deploy application hosts: all vars: app_version: "2.1.0" app_port: 8080 tasks: - name: Deploy app get_url: url: "https://example.com/app-{{ app_version }}.tar.gz" dest: "/opt/app" ``` ### Facts Ansible gathers system facts automatically: ```yaml - name: Display system info hosts: all tasks: - name: Show hostname debug: msg: "Host {{ ansible_facts.hostname }} has {{ ansible_facts.memtotal_mb }}MB RAM" ``` ## Conditionals Run tasks based on conditions: ```yaml tasks: - name: Install on Debian apt: name: apache2 state: present when: ansible_facts.os_family == "Debian" - name: Install on RedHat yum: name: httpd state: present when: ansible_facts.os_family == "RedHat" ``` ## Loops Repeat tasks with different values: ```yaml tasks: - name: Create users user: name: "{{ item }}" state: present loop: - alice - bob - charlie - name: Create multiple directories file: path: "{{ item.path }}" state: directory mode: "{{ item.mode }}" loop: - { path: "/opt/app", mode: "0755" } - { path: "/var/log/app", mode: "0700" } ``` ## Templates (Jinja2) Generate configuration files dynamically: ```jinja2 # templates/nginx.conf.j2 server { listen {{ nginx_port }}; server_name {{ domain_name }}; root {{ document_root }}; location / { {% if enable_caching %} expires {{ cache_duration }}; {% endif %} } } ``` ```yaml - name: Deploy nginx config template: src: nginx.conf.j2 dest: /etc/nginx/sites-available/default ``` ## Ansible Vault Encrypt sensitive data (passwords, keys, etc.): ```bash # Create encrypted file ansible-vault create secrets.yml # Edit encrypted file ansible-vault edit secrets.yml # Encrypt existing file ansible-vault encrypt_string "my_password" --name "db_password" # Run playbook with vault ansible-playbook site.yml --ask-vault-pass ansible-playbook site.yml --vault-password-file ~/.vault_pass ``` ## Roles Organize playbooks into reusable structures: ``` roles/ common/ tasks/ main.yml handlers/ main.yml templates/ files/ vars/ main.yml defaults/ main.yml ``` ```yaml # site.yml - name: Deploy infrastructure hosts: webservers roles: - common - nginx - webapp ``` ## Tags Control which tasks run: ```yaml tasks: - name: Install dependencies apt: name: "{{ item }}" loop: - python3 - git tags: [install, setup] - name: Configure app template: src: app.conf.j2 dest: /etc/app.conf tags: [configure] - name: Start service service: name: app state: started tags: [deploy] ``` ```bash ansible-playbook site.yml --tags "install,configure" ansible-playbook site.yml --skip-tags "deploy" ``` ## Delegation Run tasks on specific hosts: ```yaml - name: Load balancer config hosts: webservers tasks: - name: Update load balancer haproxy: state: enabled delegate_to: lb01.example.com - name: Get facts from database server setup: delegate_to: db01.example.com ``` ## Async and Parallel Tasks Run long-running tasks without blocking: ```yaml tasks: - name: Long backup task command: /usr/local/bin/backup.sh async: 3600 poll: 0 register: backup_job - name: Check backup status async_status: jid: "{{ backup_job.ansible_job_id }}" register: backup_result until: backup_result.finished retries: 30 ``` ## Check Mode (Dry Run) Preview changes without applying them: ```bash ansible-playbook site.yml --check ansible-playbook site.yml -C # shorthand ``` ## Task Error Handling Control task failure behavior: ```yaml tasks: - name: Ignore errors command: /opt/risky-script.sh ignore_errors: yes - name: Custom failure command: /opt/check-service.sh register: result failed_when: result.rc != 0 and "ERROR" in result.stdout - name: Block with rescue block: - name: Deploy application include_tasks: deploy.yml rescue: - name: Rollback include_tasks: rollback.yml always: - name: Cleanup file: path: /tmp/deploy-temp state: absent ``` ## Ansible Galaxy Download and use community roles: ```bash # Search for roles ansible-galaxy search nginx # Install a role ansible-galaxy install nginx.docker # Create role skeleton ansible-galaxy init myrole # Install from requirements file ansible-galaxy install -r requirements.yml ``` ## Dynamic Inventory Use dynamic sources for cloud environments: ```bash # AWS EC2 ansible-playbook -i ec2.py site.yml # Kubernetes ansible-playbook -i k8s.yml site.yml ``` ```ini # inventory.ini with groups and variables [webservers] web1.example.com ansible_host=192.168.1.10 web2.example.com ansible_host=192.168.1.11 [webservers:vars] ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_rsa [databases] db1.example.com ``` ## Useful Modules Reference | Module | Purpose | |--------|---------| | `apt` / `yum` / `dnf` | Package management | | `copy` | Copy files to remote | | `template` | Generate files with Jinja2 | | `file` | Create files/directories/symlinks | | `service` | Manage services | | `user` | User account management | | `cron` | Schedule tasks | | `uri` | Interact with HTTP APIs | | `get_url` | Download files | | `git` / `subversion` | Version control | | `docker_container` | Container management | | `k8s` | Kubernetes operations | | `aws_ec2` | AWS resource management | | `shell` / `command` | Execute commands | | `debug` | Print variables | | `assert` | Validate conditions | ## Best Practices 1. **Use roles** - Organize tasks into reusable roles 2. **Minimize `shell/command`** - Prefer modules for idempotency 3. **Use `check_mode`** - Test changes before applying 4. **Encrypt secrets** - Always use Ansible Vault for sensitive data 5. **Use tags** - Enable selective execution 6. **Define handlers** - Trigger actions only on changes 7. **Validate syntax** - Run `ansible-playbook --syntax-check` before execution