Operations 14 min read

Master Ansible Playbooks: From Basics to Large‑Scale Cluster Automation

This comprehensive guide walks you through Ansible fundamentals, production‑grade playbook design, large‑scale cluster deployment, performance tuning, security hardening, CI/CD integration, and monitoring, enabling you to automate infrastructure efficiently and reliably.

Ops Community
Ops Community
Ops Community
Master Ansible Playbooks: From Basics to Large‑Scale Cluster Automation

Ansible Playbook Practical Guide: From Basics to Large-Scale Cluster Automation

Why Choose Ansible?

In the cloud‑native era, manual operations become the biggest bottleneck. Ansible enables agent‑less, SSH‑based automation, allowing massive parallel deployments without installing software on target machines.

Chapter 1: Quick Overview of Core Concepts

1.1 Architecture: Control Node + Managed Nodes

# Typical Ansible architecture
ControlNode
├── ansible.cfg      # Global config
├── inventory/       # Host inventory
│   ├── hosts.ini
│   └── group_vars/
├── playbooks/       # Playbook directory
└── roles/           # Role directory

Key Advantages:

Agent‑less operation

SSH‑based, secure connection

Declarative syntax, easy to read

Idempotent execution

1.2 Deep Dive into Core Components

Inventory (host list)

[webservers]
web01 ansible_host=192.168.1.10
web02 ansible_host=192.168.1.11

[databases]
db01 ansible_host=192.168.1.20
db02 ansible_host=192.168.1.21

[all:vars]
ansible_user=deploy
ansible_ssh_private_key_file=~/.ssh/id_rsa

Playbook

---
- name: Deploy Web Application
  hosts: webservers
  become: yes
  vars:
    app_name: "myapp"
    app_version: "v1.2.0"
  tasks:
    - name: Install Nginx
      yum:
        name: nginx
        state: present
    - name: Start and enable Nginx
      systemd:
        name: nginx
        state: started
        enabled: yes

Chapter 2: Advanced Production-Level Playbook Design

2.1 Variable Management Best Practices

# group_vars/webservers.yml
nginx_version: "1.20.2"
app_port: 8080
ssl_enabled: true

# host_vars/web01.yml
server_id: 1
local_storage_path: "/data/web01"

# Use in playbook
- name: Configure application port
  lineinfile:
    path: /etc/nginx/nginx.conf
    regexp: '^listen'
    line: "listen {{ app_port }};"

2.2 Role Architecture

roles/
├── common/          # Base environment
│   ├── tasks/main.yml
│   ├── handlers/main.yml
│   └── vars/main.yml
├── nginx/           # Nginx role
└── mysql/           # MySQL role

common/tasks/main.yml example

---
- name: Update system packages
  yum:
    name: "*"
    state: latest
  when: ansible_os_family == "RedHat"

- name: Install basic tools
  package:
    name: "{{ item }}"
    state: present
  loop:
    - htop
    - vim
    - curl
    - wget

- name: Set timezone
  timezone:
    name: Asia/Shanghai

2.3 Error Handling and Rollback

- name: Application deployment main flow
  block:
    - name: Backup current version
      archive:
        path: /opt/app
        dest: "/backup/app_{{ ansible_date_time.epoch }}.tar.gz"

    - name: Deploy new version
      git:
        repo: "{{ app_repo_url }}"
        dest: /opt/app
        version: "{{ app_version }}"

    - name: Restart service
      systemd:
        name: "{{ app_service_name }}"
        state: restarted
  rescue:
    - name: Roll back to backup
      unarchive:
        src: "/backup/app_{{ ansible_date_time.epoch }}.tar.gz"
        dest: /opt/
        remote_src: yes

    - name: Restore service
      systemd:
        name: "{{ app_service_name }}"
        state: restarted

Chapter 3: Large-Scale Cluster Deployment Case

3.1 Scenario: Deploying a 100+ Node Microservice Cluster

Challenges:

Batch server initialization

Multi-environment configuration

Rolling updates

Service health checks

Solution Architecture (site.yml)

---
- import_playbook: playbooks/01-system-init.yml
- import_playbook: playbooks/02-docker-deploy.yml
- import_playbook: playbooks/03-app-deploy.yml
- import_playbook: playbooks/04-monitoring.yml

3.2 System Initialization Playbook

---
- name: Large-scale cluster system init
  hosts: all
  serial: 20
  gather_facts: yes
  become: yes
  pre_tasks:
    - name: Check OS compatibility
      fail:
        msg: "Unsupported OS version"
      when:
        - ansible_distribution != "CentOS"
        - ansible_distribution_major_version|int < 7
  roles:
    - common
    - security
    - monitoring-agent
  post_tasks:
    - name: Verify basic services
      service_facts:
    - name: Ensure critical services are running
      assert:
        that:
          - ansible_facts.services["sshd.service"].state == "running"
          - ansible_facts.services["chronyd.service"].state == "running"

3.3 Docker Container Deployment

---
- name: Docker environment deployment
  hosts: app_servers
  serial: "30%"
  become: yes
  vars:
    docker_version: "20.10.17"
    docker_compose_version: "2.6.0"
  tasks:
    - name: Install Docker CE
      yum:
        name:
          - docker-ce-{{ docker_version }}
          - docker-ce-cli-{{ docker_version }}
          - containerd.io
        state: present
    - name: Configure Docker daemon
      template:
        src: docker-daemon.json.j2
        dest: /etc/docker/daemon.json
      notify: restart docker
    - name: Start Docker service
      systemd:
        name: docker
        state: started
        enabled: yes
  handlers:
    - name: restart docker
      systemd:
        name: docker
        state: restarted

3.4 Rolling Deployment Strategy

---
- name: Microservice batch deployment
  hosts: app_servers
  serial: 5
  max_fail_percentage: 10
  vars:
    deployment_strategy: "rolling"
    health_check_retries: 3
    health_check_delay: 10
  tasks:
    - name: Remove node from load balancer
      uri:
        url: "http://{{ load_balancer_host }}/api/remove/{{ inventory_hostname }}"
        method: POST
      delegate_to: localhost

    - name: Wait for connections to drain
      wait_for:
        timeout: 30

    - name: Stop old version
      docker_compose:
        project_src: /opt/app
        state: absent

    - name: Deploy new version
      docker_compose:
        project_src: /opt/app
        files:
          - docker-compose.yml
          - docker-compose.prod.yml
        state: present
        pull: yes

    - name: Health check
      uri:
        url: "http://{{ inventory_hostname }}:8080/health"
        status_code: 200
        retries: "{{ health_check_retries }}"
        delay: "{{ health_check_delay }}"

    - name: Add node back to load balancer
      uri:
        url: "http://{{ load_balancer_host }}/api/add/{{ inventory_hostname }}"
        method: POST
      delegate_to: localhost

Chapter 4: Performance Tuning and Troubleshooting

4.1 Ansible Performance Tips

# ansible.cfg
[defaults]
host_key_checking = False
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts_cache
fact_caching_timeout = 3600
forks = 50
callback_whitelist = timer, profile_tasks

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
pipelining = True
control_path_dir = /tmp/.ansible-cp

Facts collection optimization

- name: Optimized task execution
  hosts: all
  gather_facts: no
  tasks:
    - name: Collect only required facts
      setup:
        gather_subset:
          - "!all"
          - "!min"
          - network
          - virtual

4.2 Common Issue Diagnosis

Connection timeout

- name: Diagnose network connection
  wait_for:
    host: "{{ inventory_hostname }}"
    port: 22
    timeout: 5
  delegate_to: localhost
  ignore_errors: yes
  register: connection_test

- name: Report connection status
  debug:
    msg: "{{ inventory_hostname }} connection status: {{ 'SUCCESS' if not connection_test.failed else 'FAILED' }}"

Chapter 5: Enterprise Practices and Security Hardening

5.1 Sensitive Data Management – Ansible Vault

# Create encrypted file
ansible-vault create secrets.yml

# Encrypt existing file
ansible-vault encrypt vars/database.yml

# Run playbook with vault
ansible-playbook -i inventory site.yml --ask-vault-pass

secrets.yml example

database_password: !vault |
    $ANSIBLE_VAULT;1.1;AES256
    66386439653138363739653730636365396464333661643138656234323837653462613431613938
    3730623234643863666466303435346138666330363834660a653864373765623965383535633166

5.2 RBAC and Permission Control

---
- name: System security hardening
  hosts: all
  become: yes
  tasks:
    - name: Create ops group
      group:
        name: ops
        state: present
    - name: Configure sudo for ops
      lineinfile:
        path: /etc/sudoers.d/ops
        line: "%ops ALL=(ALL) NOPASSWD: /usr/bin/systemctl, /usr/bin/docker"
        create: yes
        mode: '0440'
    - name: Disable root SSH login
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^PermitRootLogin'
        line: 'PermitRootLogin no'
      notify: restart sshd
  handlers:
    - name: restart sshd
      service:
        name: sshd
        state: restarted

5.3 CI/CD Integration Example (GitLab CI)

# .gitlab-ci.yml
deploy:
  stage: deploy
  script:
    - ansible-playbook -i inventory/prod site.yml --vault-password-file .vault_pass
  only:
    - main
  when: manual
  environment:
    name: production

Chapter 6: Monitoring and Logging Integration

6.1 Deploy Monitoring Stack (Prometheus + Grafana)

- name: Deploy Prometheus + Grafana monitoring
  hosts: monitoring
  become: yes
  tasks:
    - name: Create monitoring directory
      file:
        path: /opt/monitoring
        state: directory
    - name: Deploy monitoring services
      docker_compose:
        project_src: /opt/monitoring
        definition:
          version: '3.8'
          services:
            prometheus:
              image: prom/prometheus:latest
              ports:
                - "9090:9090"
              volumes:
                - ./prometheus.yml:/etc/prometheus/prometheus.yml
            grafana:
              image: grafana/grafana:latest
              ports:
                - "3000:3000"
              environment:
                - GF_SECURITY_ADMIN_PASSWORD=admin123

6.2 Automated Deployment Report

- name: Generate deployment report
  hosts: localhost
  gather_facts: no
  tasks:
    - name: Collect deployment statistics
      set_fact:
        deployment_stats:
          total_hosts: "{{ groups['all'] | length }}"
          successful_hosts: "{{ groups['all'] | length - (ansible_failed_hosts | default([]) | length) }}"
          failed_hosts: "{{ ansible_failed_hosts | default([]) | length }}"
          deployment_time: "{{ ansible_date_time.iso8601 }}"
    - name: Send deployment notification
      uri:
        url: "{{ slack_webhook_url }}"
        method: POST
        body_format: json
        body:
          text: |
            🚀 Deployment Report
            ✅ Success: {{ deployment_stats.successful_hosts }}/{{ deployment_stats.total_hosts }}
            ❌ Failure: {{ deployment_stats.failed_hosts }}
            🕐 Time: {{ deployment_stats.deployment_time }}

Conclusion: Core Value of Ansible Automation

Through this end-to-end tutorial we covered Ansible fundamentals, production-grade playbook design, large-scale cluster rollout, performance tuning, security hardening, CI/CD integration, and monitoring. Readers gain a solid grasp of infrastructure-as-code, declarative management, idempotency, layered variable strategies, and the tangible business benefits of faster deployments, reduced human error, and near‑perfect environment consistency.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Configuration ManagementDevOpsInfrastructure as CodeAnsiblePlaybook
Ops Community
Written by

Ops Community

A leading IT operations community where professionals share and grow together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.