Skip to content

Ansible Best Practices

Project Structure

Directory Organization

ansible-project/
├── ansible.cfg                 # Ansible configuration
├── site.yml                   # Main playbook
├── requirements.yml           # Dependencies
├── inventories/              # Environment-specific inventories
│   ├── production/
│   │   ├── hosts            # Production hosts
│   │   ├── group_vars/
│   │   └── host_vars/
│   └── staging/
│       ├── hosts            # Staging hosts
│       ├── group_vars/
│       └── host_vars/
├── group_vars/               # Global group variables
│   └── all/
│       ├── vars.yml         # Non-sensitive variables
│       └── vault.yml        # Encrypted variables
├── roles/                    # Role definitions
│   ├── common/
│   ├── monitoring/
│   └── webserver/
└── playbooks/               # Task-specific playbooks
    ├── backup.yml
    ├── maintenance.yml
    └── security.yml

Playbook Organization

Main Playbook Structure

# site.yml
---
- name: Base configuration for all hosts
  hosts: all
  roles:
    - common
    - monitoring

- name: Configure web servers
  hosts: webservers
  roles:
    - nginx
    - php-fpm
    - deployment

- name: Configure databases
  hosts: dbservers
  roles:
    - postgresql
    - backup

Role Dependencies

# roles/webserver/meta/main.yml
---
dependencies:
  - role: common
    vars:
      priority: high
  - role: security
    vars:
      level: production

Variable Management

Variable Precedence

# Group variables (group_vars/all/vars.yml)
---
app_name: myapp
environment: production

# Role defaults (roles/webserver/defaults/main.yml)
---
http_port: 80
worker_processes: auto

# Host variables (host_vars/web1.example.com/vars.yml)
---
http_port: 8080
ssl_enabled: true

Environment-Specific Variables

# inventories/production/group_vars/all/vars.yml
---
environment: production
debug_enabled: false
log_level: ERROR
backup_retention: 30

# inventories/staging/group_vars/all/vars.yml
---
environment: staging
debug_enabled: true
log_level: DEBUG
backup_retention: 7

Task Design

Task Naming Conventions

# Good Examples
- name: Ensure nginx package is installed
  apt:
    name: nginx
    state: present

- name: Configure nginx virtual host
  template:
    src: vhost.conf.j2
    dest: /etc/nginx/sites-available/{{ app_name }}

# Bad Examples
- name: nginx install
- name: configure

Idempotency

# Good - Idempotent
- name: Ensure configuration directory exists
  file:
    path: /etc/myapp
    state: directory
    mode: '0755'

# Bad - Not Idempotent
- name: Create configuration directory
  command: mkdir /etc/myapp

Security Practices

Vault Usage

# Store sensitive data in vault
- name: Configure database connection
  template:
    src: database.conf.j2
    dest: /etc/myapp/database.conf
  vars_files:
    - vars/vault.yml

File Permissions

- name: Ensure secure file permissions
  file:
    path: "{{ item.path }}"
    state: file
    owner: "{{ item.owner }}"
    group: "{{ item.group }}"
    mode: "{{ item.mode }}"
  loop:
    - path: /etc/ssl/private/cert.key
      owner: root
      group: root
      mode: '0600'
    - path: /etc/myapp/config.yml
      owner: myapp
      group: myapp
      mode: '0640'

Performance Optimization

Async Tasks

- name: Update packages
  apt:
    update_cache: yes
    cache_valid_time: 3600
  async: 3600
  poll: 0
  register: pkg_update

- name: Long running task
  command: /usr/local/bin/long_operation
  async: 3600
  poll: 0

- name: Check async status
  async_status:
    jid: "{{ pkg_update.ansible_job_id }}"
  register: job_result
  until: job_result.finished
  retries: 30
  delay: 60

Fact Caching

# ansible.cfg
[defaults]
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /path/to/facts
fact_caching_timeout = 86400

Testing

Molecule Testing

# molecule/default/molecule.yml
---
dependency:
  name: galaxy
driver:
  name: docker
platforms:
  - name: instance
    image: ubuntu:20.04
    pre_build_image: true
provisioner:
  name: ansible
verifier:
  name: ansible

Integration Tests

# tests/integration/test_webserver.yml
---
- hosts: webservers
  tasks:
    - name: Verify nginx is running
      command: systemctl status nginx
      register: nginx_status
      failed_when: nginx_status.rc != 0

    - name: Verify web page is accessible
      uri:
        url: http://localhost
        return_content: yes
      register: webpage
      failed_when: webpage.status != 200

CI/CD Integration

Pipeline Configuration

# .gitlab-ci.yml
stages:
  - lint
  - test
  - deploy

lint:
  stage: lint
  script:
    - ansible-lint site.yml

molecule:
  stage: test
  script:
    - molecule test

deploy_staging:
  stage: deploy
  script:
    - ansible-playbook -i inventories/staging site.yml
  environment:
    name: staging

Documentation

Role Documentation

# roles/webserver/README.md
# Webserver Role

## Requirements
- Ubuntu 20.04 or later
- Python 3.8+

## Variables
| Variable | Default | Description |
|----------|---------|-------------|
| http_port | 80 | HTTP port |
| ssl_enabled | false | Enable SSL |

## Dependencies
- common
- security

## Example Usage
```yaml
- hosts: webservers
  roles:
    - role: webserver
      vars:
        http_port: 8080
        ssl_enabled: true

Error Handling

Block Usage

- name: Handle complex deployments
  block:
    - name: Deploy application
      include_role:
        name: deployment
  rescue:
    - name: Rollback deployment
      include_role:
        name: rollback
  always:
    - name: Cleanup temporary files
      file:
        path: /tmp/deployment
        state: absent

Monitoring and Logging

Task Logging

- name: Execute critical operation
  command: /usr/local/bin/critical_operation
  register: operation_result
  notify: log_operation

handlers:
  - name: log_operation
    copy:
      content: |
        Operation executed at {{ ansible_date_time.iso8601 }}
        Result: {{ operation_result.stdout }}
      dest: /var/log/ansible/operations.log

Maintenance and Updates

Role Updates

# requirements.yml
---
roles:
  - name: geerlingguy.nginx
    version: 3.1.0
  - src: https://github.com/company/ansible-security
    scm: git
    version: main
    name: security

Version Control

# .gitignore
*.retry
*.pyc
.vault_pass
inventory/*/group_vars/*/vault.yml