A Comprehensive Guide to Ansible for Batch Server Management

In modern IT operations environments, configuration management automation has become a key technology for improving efficiency, ensuring consistency, and reducing human errors. Ansible, as an open-source configuration management tool, has become one of the preferred tools for operations engineers due to its ease of use and agentless architecture. This article will provide a comprehensive introduction to various aspects of Ansible configuration automation, from basic concepts to advanced applications, helping operations engineers master this powerful automation tool.

2. Basic Concepts of Ansible

2.1 What is Ansible

Ansible is an open-source automation platform used for configuration management, application deployment, task automation, and IT orchestration. It adopts an agentless architecture, executing tasks remotely via SSH protocol, and uses YAML language to write playbooks, characterized by low learning costs and simple deployment.

2.2 Core Components

Control Node

  • • The machine where Ansible is installed
  • • Executes playbooks and ad-hoc commands
  • • Manages inventory files

Managed Node

  • • The target machines managed by Ansible
  • • SSH service needs to be enabled
  • • Usually requires a Python environment

Inventory

  • • Defines the list of managed nodes
  • • Supports static and dynamic inventory
  • • Can set host variables and group variables

Playbook

  • • Configuration files written in YAML
  • • Describes the execution process of automation tasks
  • • Contains one or more plays

Module

  • • The execution unit of Ansible
  • • Completes specific task operations
  • • Built-in thousands of modules

Plugin

  • • Components that extend Ansible’s functionality
  • • Includes connection plugins, filter plugins, etc.

3. Installation and Configuration

3.1 Installing Ansible

CentOS/RHEL Systems

# Using EPEL repository
yum install epel-release -y
yum install ansible -y

# Or install using pip
pip install ansible

Ubuntu/Debian Systems

# Add PPA repository
sudo apt-add-repository ppa:ansible/ansible
sudo apt update
sudo apt install ansible -y

# Or install using pip
pip install ansible

Verify Installation

ansible --version

3.2 Configuration File Structure

The search order for Ansible configuration files is as follows:

  1. 1. The file specified by the $ANSIBLE_CONFIG environment variable
  2. 2. The ansible.cfg file in the current directory
  3. 3. The .ansible.cfg file in the user’s home directory
  4. 4. The system configuration file /etc/ansible/ansible.cfg

Main Configuration Items

[defaults]
# Default inventory file path
inventory = /etc/ansible/hosts
# Remote user
remote_user = root
# SSH private key file path
private_key_file = ~/.ssh/id_rsa
# Host key checking
host_key_checking = False
# Number of forks
forks = 20
# Timeout
timeout = 30
# Log file
log_path = /var/log/ansible.log

[ssh_connection]
# SSH parameters
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
# Enable pipelining
pipelining = True

4. Inventory Management

4.1 Static Inventory

Basic Format

# Single host
web1.example.com

# Host groups
[webservers]
web1.example.com
web2.example.com
web3.example.com

[databases]
db1.example.com
db2.example.com

# Host variables
[webservers]
web1.example.com http_port=80 maxRequestsPerChild=808
web2.example.com http_port=8080 maxRequestsPerChild=909

# Group variables
[webservers:vars]
ntp_server=ntp.example.com
proxy=proxy.example.com

Host Ranges

# Numeric range
[webservers]
web[01:50].example.com

# Alphabetic range
[databases]
db[a:f].example.com

# Multiple ranges
[servers]
server[01:20].example[1:3].com

4.2 Dynamic Inventory

AWS EC2 Dynamic Inventory

#!/usr/bin/env python3
import boto3
import json

def get_ec2_instances():
    ec2 = boto3.client('ec2')
    response = ec2.describe_instances()
    
    inventory = {
        '_meta': {'hostvars': {}},
        'all': {'hosts': []},
        'webservers': {'hosts': []},
        'databases': {'hosts': []}
    }
    
    for reservation in response['Reservations']:
        for instance in reservation['Instances']:
            if instance['State']['Name'] == 'running':
                public_ip = instance.get('PublicIpAddress')
                if public_ip:
                    inventory['all']['hosts'].append(public_ip)
                    
                    # Grouping by tags
                    for tag in instance.get('Tags', []):
                        if tag['Key'] == 'Role':
                            role = tag['Value']
                            if role not in inventory:
                                inventory[role] = {'hosts': []}
                            inventory[role]['hosts'].append(public_ip)
    
    return inventory

if __name__ == '__main__':
    print(json.dumps(get_ec2_instances(), indent=2))

4.3 Host Variables and Group Variables

Directory Structure

inventory/
├── hosts
├── group_vars/
│   ├── all.yml
│   ├── webservers.yml
│   └── databases.yml
└── host_vars/
    ├── web1.example.com.yml
    └── db1.example.com.yml

group_vars/all.yml

---
# Global variables
timezone: Asia/Shanghai
dns_servers:
  - 8.8.8.8
  - 8.8.4.4

group_vars/webservers.yml

---
# Web server group variables
http_port: 80
max_clients: 200
document_root: /var/www/html

5. Ad-hoc Commands

5.1 Basic Syntax

ansible <pattern> -m <module> -a <arguments>

5.2 Common Ad-hoc Commands

Execute Shell Commands

# Execute command on all hosts
ansible all -m shell -a "uptime"

# Execute command on specific group
ansible webservers -m shell -a "systemctl status nginx"

# Use sudo privileges
ansible all -m shell -a "systemctl restart nginx" --become

File Operations

# Copy files
ansible all -m copy -a "src=/tmp/test.txt dest=/tmp/test.txt"

# Create directory
ansible all -m file -a "path=/tmp/testdir state=directory"

# Change file permissions
ansible all -m file -a "path=/tmp/test.txt mode=0644"

Package Management

# Install package
ansible all -m yum -a "name=nginx state=present"

# Uninstall package
ansible all -m yum -a "name=nginx state=absent"

# Update all packages
ansible all -m yum -a "name=* state=latest"

Service Management

# Start service
ansible all -m service -a "name=nginx state=started"

# Stop service
ansible all -m service -a "name=nginx state=stopped"

# Restart service
ansible all -m service -a "name=nginx state=restarted"

6. Writing Playbooks

6.1 Basic Structure

---
- name: Configure Web Server
  hosts: webservers
  become: yes
  vars:
      http_port: 80
      max_clients: 200

  tasks:
      - name: Install Nginx
        yum:
          name: nginx
          state: present
      
      - name: Start Nginx Service
        service:
          name: nginx
          state: started
          enabled: yes

6.2 Variable Usage

Defining Variables

---
- name: Variable Example
  hosts: all
  vars:
      packages:
        - nginx
        - mysql
        - php
      
      user_info:
        name: webapp
        group: webapp
        shell: /bin/bash

  tasks:
      - name: Install Packages
        yum:
          name: "{{ packages }}"
          state: present
      
      - name: Create User
        user:
          name: "{{ user_info.name }}"
          group: "{{ user_info.group }}"
          shell: "{{ user_info.shell }}"

Variable Files

# vars/main.yml
---
database_name: myapp
database_user: myapp_user
database_password: "{{ vault_database_password }}"

Referencing in Playbook

---
- name: Database Configuration
  hosts: databases
  vars_files:
      - vars/main.yml

  tasks:
      - name: Create Database
        mysql_db:
          name: "{{ database_name }}"
          state: present

6.3 Conditional Statements

---
- name: Conditional Example
  hosts: all

  tasks:
      - name: Install Apache (RedHat)
        yum:
          name: httpd
          state: present
        when: ansible_os_family == "RedHat"
      
      - name: Install Apache (Debian)
        apt:
          name: apache2
          state: present
        when: ansible_os_family == "Debian"
      
      - name: Check Disk Space
        shell: df -h /
        register: disk_usage
      
      - name: Warn if Disk Space is Low
        debug:
          msg: "Disk space is low, please clean up"
        when: "'90%' in disk_usage.stdout"

6.4 Loops

---
- name: Loop Example
  hosts: all

  tasks:
      - name: Install Multiple Packages
        yum:
          name: "{{ item }}"
          state: present
        loop:
          - nginx
          - mysql
          - php
          - redis
      
      - name: Create Multiple Users
        user:
          name: "{{ item.name }}"
          group: "{{ item.group }}"
          state: present
        loop:
          - { name: 'user1', group: 'web' }
          - { name: 'user2', group: 'db' }
          - { name: 'user3', group: 'app' }
      
      - name: Process Dictionary Loop
        debug:
          msg: "{{ item.key }}: {{ item.value }}"
        loop: "{{ lookup('dict', {'a': 1, 'b': 2, 'c': 3}) }}"

6.5 Error Handling

---
- name: Error Handling Example
  hosts: all

  tasks:
      - name: Attempt to Start Service
        service:
          name: nginx
          state: started
        ignore_errors: yes
      
      - name: Capture Error Information
        shell: /bin/false
        register: result
        failed_when: result.rc != 0
        ignore_errors: yes
      
      - name: Execute Different Actions Based on Result
        debug:
          msg: "Command execution failed"
        when: result.failed
      
      - name: Rescue Operation
        block:
          - name: Potentially Failing Task
            shell: /bin/false
        rescue:
          - name: Rescue Task
            debug:
              msg: "Executing rescue operation"
        always:
          - name: Always Executed Task
            debug:
              msg: "Executed regardless of success or failure"

7. Module Details

7.1 System Modules

User Module

- name: Create User
  user:
    name: webapp
    group: webapp
    shell: /bin/bash
    home: /home/webapp
    create_home: yes
    password: "{{ 'password' | password_hash('sha512') }}"

Group Module

- name: Create Group
  group:
    name: webapp
    gid: 1001
    state: present

Cron Module

- name: Add Cron Job
  cron:
    name: "backup database"
    minute: "0"
    hour: "2"
    job: "/usr/local/bin/backup.sh"
    user: root

7.2 File Modules

File Module

- name: Create Directory
  file:
    path: /var/www/html
    state: directory
    owner: nginx
    group: nginx
    mode: '0755'

- name: Create Symbolic Link
  file:
    src: /var/www/html
    dest: /var/www/site
    state: link

Copy Module

- name: Copy File
  copy:
    src: /tmp/source.txt
    dest: /tmp/dest.txt
    owner: root
    group: root
    mode: '0644'
    backup: yes

Template Module

- name: Generate Configuration File
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
  notify: restartnginx

7.3 Package Modules

Yum Module

- name: Install Packages
  yum:
    name:
      - nginx
      - mysql-server
      - php
    state: present
    update_cache: yes

- name: Install Specific Version
  yum:
    name: nginx-1.18.0
    state: present

Apt Module

- name: Update Package Cache
  apt:
    update_cache: yes
    cache_valid_time: 3600

- name: Install Packages
  apt:
    name: "{{ packages }}"
    state: present
  vars:
    packages:
      - nginx
      - mysql-server
      - php

7.4 Service Modules

Service Module

- name: Start and Enable Service
  service:
    name: nginx
    state: started
    enabled: yes

- name: Restart Service
  service:
    name: nginx
    state: restarted

Systemd Module

- name: Reload Systemd
  systemd:
    daemon_reload: yes

- name: Start Service
  systemd:
    name: nginx
    state: started
    enabled: yes

8. Templates and Filters

8.1 Jinja2 Templates

Basic Syntax

# nginx.conf.j2
user {{ nginx_user }};
worker_processes {{ ansible_processor_cores }};
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;

events {
    worker_connections {{ nginx_worker_connections }};
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    {% for upstream in nginx_upstreams %}
    upstream {{ upstream.name }} {
        {% for server in upstream.servers %}
        server {{ server }};
        {% endfor %}
    }
    {% endfor %}
    
    server {
        listen {{ http_port }};
        server_name {{ server_name }};
        
        location / {
            root {{ document_root }};
            index index.html index.htm;
        }
    }
}

8.2 Common Filters

---
- name: Filter Example
  hosts: all
  vars:
      items: [1, 2, 3, 4, 5]
      text: "Hello World"
      
tasks:
      - name: Number Filter
        debug:
          msg: "{{ items | max }}" # Maximum value
      
      - name: String Filter
        debug:
          msg: "{{ text | lower }}" # Convert to lowercase
      
      - name: Default Value Filter
        debug:
          msg: "{{ undefined_var | default('default_value') }}"
      
      - name: Password Hash
        debug:
          msg: "{{ 'password' | password_hash('sha512') }}"
      
      - name: Time Filter
        debug:
          msg: "{{ ansible_date_time.iso8601 | to_datetime }}"

9. Handlers and Notifications

9.1 Basic Usage of Handlers

---
- name: Web Server Configuration
  hosts: webservers

  tasks:
      - name: Install Nginx
        yum:
          name: nginx
          state: present
      
      - name: Configure Nginx
        template:
          src: nginx.conf.j2
          dest: /etc/nginx/nginx.conf
        notify:
          - restartnginx
          - reloadnginx
      
      - name: Ensure Nginx is Running
        service:
          name: nginx
          state: started
          enabled: yes

handlers:
    - name: restartnginx
      service:
        name: nginx
        state: restarted
    
    - name: reloadnginx
      service:
        name: nginx
        state: reloaded

9.2 Conditional Handlers

---
- name: Conditional Handler Example
  hosts: all

  tasks:
      - name: Check Configuration File
        stat:
          path: /etc/nginx/nginx.conf
        register: nginx_config
    
      - name: Update Configuration
        template:
          src: nginx.conf.j2
          dest: /etc/nginx/nginx.conf
        when: nginx_config.stat.exists
        notify: restartnginx

handlers:
    - name: restartnginx
      service:
        name: nginx
        state: restarted
      when: nginx_config.stat.exists

10. Roles

10.1 Role Structure

roles/
└── nginx/
    ├── tasks/
    │   └── main.yml
    ├── handlers/
    │   └── main.yml
    ├── templates/
    │   └── nginx.conf.j2
    ├── files/
    │   └── index.html
    ├── vars/
    │   └── main.yml
    ├── defaults/
    │   └── main.yml
    ├── meta/
    │   └── main.yml
    └── README.md

10.2 Creating a Role

tasks/main.yml

---
- name: Install Nginx
  yum:
      name: nginx
      state: present

- name: Create Configuration File
  template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
  notify: restartnginx

- name: Start Nginx Service
  service:
      name: nginx
      state: started
      enabled: yes

handlers/main.yml

---
- name: restartnginx
  service:
    name: nginx
    state: restarted

defaults/main.yml

---
nginx_user: nginx
nginx_worker_connections: 1024
http_port: 80
document_root: /usr/share/nginx/html

meta/main.yml

---
galaxy_info:
  author: your-name
  description: Nginx web server role
  company: your-company
  license: MIT
  min_ansible_version: 2.9

platforms:
    - name: EL
      versions:
        - 7
        - 8
    - name: Ubuntu
      versions:
        - 18.04
        - 20.04

dependencies: []

10.3 Using Roles

---
- name: Deploy Web Server
  hosts: webservers
  roles:
      - nginx
      - mysql
      - php

# Passing variables to Role
- name: Deploy Web Server
  hosts: webservers
  roles:
      - role: nginx
        nginx_user: www-data
        http_port: 8080

11. Vault Encryption

11.1 Creating Encrypted Files

# Create encrypted file
ansible-vault create secret.yml

# Edit encrypted file
ansible-vault edit secret.yml

# View encrypted file
ansible-vault view secret.yml

# Encrypt existing file
ansible-vault encrypt existing_file.yml

# Decrypt file
ansible-vault decrypt secret.yml

11.2 Using Encrypted Variables

Encrypted Variable File

# vault.yml
---
vault_database_password: secretpassword123
vault_api_key: abc123def456

Using in Playbook

---
- name: Using Encrypted Variables
  hosts: databases
  vars_files:
      - vault.yml

  tasks:
      - name: Create Database User
        mysql_user:
          name: myapp
          password: "{{ vault_database_password }}"
          priv: "myapp.*:ALL"
          state: present

Running Playbook

ansible-playbook -i inventory site.yml --ask-vault-pass
# Or use password file
ansible-playbook -i inventory site.yml --vault-password-file ~/.vault_pass

12. Advanced Features

12.1 Strategy Control

---
- name: Strategy Control Example
  hosts: all
  strategy: free # Free strategy, each host executes independently

  tasks:
      - name: Long Running Task
        shell: sleep 30
      
      - name: Quick Task
        debug:
          msg: "This task will complete quickly"

12.2 Delegation and Proxy

---
- name: Delegation Example
  hosts: webservers

  tasks:
      - name: Check Service Status on Monitoring Server
        uri:
          url: "http://{{ inventory_hostname }}/health"
          method: GET
        delegate_to: monitor.example.com
      
      - name: Execute Command Locally
        shell: echo "Executed on control node"
        delegate_to: localhost
        run_once: true

12.3 Rolling Updates

---
- name: Rolling Update Example
  hosts: webservers
  serial: 2 # Process 2 servers at a time

  tasks:
      - name: Remove from Load Balancer
        uri:
          url: "http://lb.example.com/remove/{{ inventory_hostname }}"
          method: POST
        delegate_to: localhost
      
      - name: Update Application
        yum:
          name: myapp
          state: latest
        notify: restartmyapp
      
      - name: Wait for Service to Start
        wait_for:
          port: 8080
          delay: 10
      
      - name: Add to Load Balancer
        uri:
          url: "http://lb.example.com/add/{{ inventory_hostname }}"
          method: POST
        delegate_to: localhost

handlers:
    - name: restartmyapp
      service:
        name: myapp
        state: restarted

12.4 Asynchronous Tasks

---
- name: Asynchronous Task Example
  hosts: all

  tasks:
      - name: Long Running Task
        shell: /opt/long_running_script.sh
        async: 3600 # Maximum run time (seconds)
        poll: 0      # Do not wait for result
        register: long_task
      
      - name: Execute Other Tasks
        debug:
          msg: "Continue executing other tasks"
      
      - name: Check Asynchronous Task Status
        async_status:
          jid: "{{ long_task.ansible_job_id }}"
        register: job_result
        until: job_result.finished
        retries: 30
        delay: 10

13. Best Practices

13.1 Directory Structure

ansible-project/
├── inventories/
│   ├── production/
│   │   ├── hosts
│   │   └── group_vars/
│   └── staging/
│       ├── hosts
│       └── group_vars/
├── roles/
│   ├── common/
│   ├── nginx/
│   └── mysql/
├── playbooks/
│   ├── site.yml
│   ├── webservers.yml
│   └── databases.yml
├── group_vars/
│   └── all.yml
├── host_vars/
├── vault/
│   └── secrets.yml
├── files/
├── templates/
├── library/
├── filter_plugins/
└── ansible.cfg

13.2 Naming Conventions

---
# Use descriptive names
- name: Install and Configure Nginx Web Server
  hosts: webservers

  tasks:
      - name: Install Nginx Package
        yum:
          name: nginx
          state: present
      
      - name: Create Nginx Configuration File
        template:
          src: nginx.conf.j2
          dest: /etc/nginx/nginx.conf
        notify: Restart Nginx Service
      
      - name: Start and Enable Nginx Service
        service:
          name: nginx
          state: started
          enabled: yes

handlers:
    - name: Restart Nginx Service
      service:
        name: nginx
        state: restarted

13.3 Variable Management

# Use clear variable hierarchy
nginx_config:
  user: nginx
  worker_processes: auto
  worker_connections: 1024
  keepalive_timeout: 65

server:
    listen: 80
    server_name: example.com
    root: /var/www/html
    index: index.html
    
upstream:
    name: backend
    servers:
      - 192.168.1.10:8080
      - 192.168.1.11:8080

13.4 Error Handling

---
- name: Robust Error Handling
  hosts: all

  tasks:
      - name: Check System Requirements
        assert:
          that:
            - ansible_distribution_major_version | int >= 7
            - ansible_memtotal_mb >= 1024
          fail_msg: "System does not meet minimum requirements"
      
      - name: Backup Configuration File
        copy:
          src: /etc/nginx/nginx.conf
          dest: /etc/nginx/nginx.conf.bak
          remote_src: yes
        ignore_errors: yes
      
      - name: Update Configuration
        template:
          src: nginx.conf.j2
          dest: /etc/nginx/nginx.conf
          validate: nginx -t -c %s
        notify: restartnginx

14. Monitoring and Logging

14.1 Log Configuration

# ansible.cfg
[defaults]
log_path = /var/log/ansible.log
display_skipped_hosts = False
display_ok_hosts = False

14.2 Callback Plugins

# callback_plugins/timer.py
from ansible.plugins.callback import CallbackBase
from datetime import datetime

class CallbackModule(CallbackBase):
    def __init__(self):
        super(CallbackModule, self).__init__()
        self.start_time = datetime.now()
    
    def v2_playbook_on_task_start(self, task, is_conditional):
        self.task_start_time = datetime.now()
    
    def v2_runner_on_ok(self, result):
        duration = datetime.now() - self.task_start_time
        self._display.display(f"Task completed in {duration.total_seconds():.2f}s")

14.3 Performance Monitoring

---
- name: Performance Monitoring Example
  hosts: all

  tasks:
      - name: Collect System Information
        setup:
          gather_subset:
            - hardware
            - network
            - virtual
      
      - name: Record Performance Metrics
        debug:
          msg: |
            CPU Cores: {{ ansible_processor_cores }}
            Memory Size: {{ ansible_memtotal_mb }}MB
            Disk Usage: {{ ansible_mounts | selectattr('mount', 'equalto', '/') | map(attribute='size_available') | first }}

15. CI/CD Integration

15.1 GitLab CI Integration

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

ansible-lint:
  stage: test
  script:
    - ansible-lint playbooks/site.yml
  only:
    - merge_requests

deploy-staging:
  stage: deploy
  script:
    - ansible-playbook -i inventories/staging/hosts playbooks/site.yml --vault-password-file $VAULT_PASSWORD_FILE
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - develop

deploy-production:
  stage: deploy
  script:
    - ansible-playbook -i inventories/production/hosts playbooks/site.yml --vault-password-file $VAULT_PASSWORD_FILE
  environment:
    name: production
    url: https://production.example.com
  when: manual
  only:
    - master

15.2 Jenkins Integration

// Jenkinsfile
pipeline {
    agent any
    
    environment {
        ANSIBLE_HOST_KEY_CHECKING = 'False'
        VAULT_PASSWORD_FILE = credentials('ansible-vault-password')
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        stage('Syntax Check') {
            steps {
                sh 'ansible-playbook --syntax-check playbooks/site.yml'
            }
        }
        
        stage('Lint') {
            steps {
                sh 'ansible-lint playbooks/site.yml'
            }
        }
        
        stage('Deploy to Staging') {
            steps {
                sh '''
                    ansible-playbook -i inventories/staging/hosts \
                    playbooks/site.yml \
                    --vault-password-file $VAULT_PASSWORD_FILE
                '''
            }
        }
        
        stage('Deploy to Production') {
            when {
                branch 'master'
            }
            steps {
                input message: 'Deploy to Production?'
                sh '''
                    ansible-playbook -i inventories/production/hosts \
                    playbooks/site.yml \
                    --vault-password-file $VAULT_PASSWORD_FILE
                '''
            }
        }
    }
    
    post {
        always {
            archiveArtifacts artifacts: 'logs/*.log', allowEmptyArchive: true
        }
        failure {
            emailext (
                subject: "Ansible Deployment Failed: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
                body: "Build failed. Check console output at ${env.BUILD_URL}",
                to: "${env.CHANGE_AUTHOR_EMAIL}"
            )
        }
    }
}

15.3 GitHub Actions Integration

# .github/workflows/deploy.yml
name: Deploy with Ansible

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v2
      
      - name: Setup Python
        uses: actions/setup-python@v2
        with:
          python-version: 3.8
      
      - name: Install dependencies
        run: |
          pip install ansible ansible-lint
      
      - name: Run ansible-lint
        run: ansible-lint playbooks/site.yml
      
      - name: Syntax check
        run: ansible-playbook --syntax-check playbooks/site.yml

  deploy-staging:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/develop'
    
    steps:
      - uses: actions/checkout@v2
      
      - name: Deploy to staging
        env:
          ANSIBLE_HOST_KEY_CHECKING: False
          VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }}
        run: |
          echo "$VAULT_PASSWORD" > .vault_pass
          ansible-playbook -i inventories/staging/hosts playbooks/site.yml --vault-password-file .vault_pass
          rm .vault_pass

  deploy-production:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production
    
    steps:
      - uses: actions/checkout@v2
      
      - name: Deploy to production
        env:
          ANSIBLE_HOST_KEY_CHECKING: False
          VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }}
        run: |
          echo "$VAULT_PASSWORD" > .vault_pass
          ansible-playbook -i inventories/production/hosts playbooks/site.yml --vault-password-file .vault_pass
          rm .vault_pass

16. Troubleshooting

16.1 Common Issues and Solutions

SSH Connection Issues

# Check SSH connection
ansible all -m ping

# Use verbose output
ansible all -m ping -vvv

# Skip host key checking
export ANSIBLE_HOST_KEY_CHECKING=False

Permission Issues

# Use sudo privileges
ansible all -m shell -a "systemctl status nginx" --become

# Specify sudo user
ansible all -m shell -a "systemctl status nginx" --become-user=root

Module Not Found

# Check module path
ansible-doc -l | grep module_name

# Install missing Python modules
pip install required_module

16.2 Debugging Tips

---
- name: Debug Example
  hosts: all

  tasks:
      - name: Collect Facts
        setup:
        register: facts
    
      - name: Display Variable Content
        debug:
          var: facts
          verbosity: 2
    
      - name: Conditional Debug
        debug:
          msg: "Disk space is low"
        when:
          - ansible_mounts | selectattr('mount', 'equalto', '/') | map(attribute='size_available') | first < 1000000000
    
      - name: Pause Execution
        pause:
          prompt: "Please check system status and press enter to continue"
        when: debug_mode | default(false)

16.3 Performance Optimization

# ansible.cfg optimization configuration
[defaults]
# Increase number of forks
forks = 50
# Enable fact caching
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts_cache
fact_caching_timeout = 3600

[ssh_connection]
# Enable SSH pipelining
pipelining = True
# Control connection reuse
ssh_args = -o ControlMaster=auto -o ControlPersist=300s
# Reduce SSH connection time
control_path = /tmp/ansible-ssh-%%h-%%p-%%r

17. Security Considerations

17.1 Permission Control

---
- name: Security Configuration Example
  hosts: all
  become: yes
  become_method: sudo

  tasks:
      - name: Create Dedicated User
        user:
          name: ansible
          groups: wheel
          shell: /bin/bash
          create_home: yes
      
      - name: Configure Sudo Permissions
        lineinfile:
          path: /etc/sudoers.d/ansible
          line: 'ansible ALL=(ALL) NOPASSWD: ALL'
          create: yes
          validate: 'visudo -cf %s'
      
      - name: Configure SSH Key
        authorized_key:
          user: ansible
          key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
          state: present

17.2 Sensitive Information Protection

---
- name: Sensitive Data Handling
  hosts: all
  vars:
      sensitive_data: "{{ vault_sensitive_data }}"

  tasks:
      - name: Use Sensitive Data
        shell: echo "{{ sensitive_data }}"
        no_log: true # Prevent sensitive information from being logged
      
      - name: Handle Password
        user:
          name: dbuser
          password: "{{ vault_db_password | password_hash('sha512') }}"
        no_log: true

17.3 Network Security

---
- name: Network Security Configuration
  hosts: all

  tasks:
      - name: Configure Firewall
        firewalld:
          service: "{{ item }}"
          permanent: yes
          state: enabled
          immediate: yes
        loop:
          - ssh
          - http
          - https
      
      - name: Restrict SSH Access
        lineinfile:
          path: /etc/ssh/sshd_config
          regexp: "^#?PasswordAuthentication"
          line: "PasswordAuthentication no"
        notify: restartsshd
      
      - name: Configure SELinux
        selinux:
          policy: targeted
          state: enforcing

handlers:
    - name: restartsshd
      service:
        name: sshd
        state: restarted

18. Enterprise Deployment Cases

18.1 Automated Deployment of LAMP Architecture

---
- name: Deploy LAMP Architecture
  hosts: webservers
  become: yes
  vars:
      mysql_root_password: "{{ vault_mysql_root_password }}"
      app_user: webapp
      app_group: webapp

  roles:
      - common
      - apache
      - mysql
      - php
      - application

  post_tasks:
      - name: Validate Deployment
        uri:
          url: "http://{{ inventory_hostname }}/health"
          method: GET
          status_code: 200
        delegate_to: localhost

18.2 Docker Containerization Deployment

---
- name: Docker Containerization Deployment
  hosts: docker_hosts
  become: yes

  tasks:
      - name: Install Docker
        yum:
          name: docker
          state: present
      
      - name: Start Docker Service
        service:
          name: docker
          state: started
          enabled: yes
      
      - name: Pull Application Image
        docker_image:
          name: "{{ app_image }}"
          tag: "{{ app_version }}"
          source: pull
      
      - name: Deploy Application Container
        docker_container:
          name: "{{ app_name }}"
          image: "{{ app_image }}:{{ app_version }}"
          state: started
          restart_policy: always
          ports:
            - "80:8080"
          env:
            DB_HOST: "{{ db_host }}"
            DB_PASSWORD: "{{ vault_db_password }}"
      
      - name: Wait for Application to Start
        wait_for:
          port: 80
          delay: 10
          timeout: 60

18.3 Kubernetes Cluster Deployment

---
- name: Kubernetes Cluster Deployment
  hosts: k8s_masters
  become: yes

  tasks:
      - name: Initialize Cluster
        shell: |
          kubeadm init --pod-network-cidr=10.244.0.0/16
        register: kubeadm_init
        run_once: true
      
      - name: Save Join Command
        set_fact:
          join_command: "{{ kubeadm_init.stdout_lines | select('match', 'kubeadm join.*') | first }}"
        run_once: true
      
      - name: Configure kubectl
        shell: |
          mkdir -p $HOME/.kube
          cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
          chown $(id -u):$(id -g) $HOME/.kube/config
        run_once: true
      
      - name: Deploy Network Plugin
        shell: kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
        run_once: true

- name: Join Worker Nodes
  hosts: k8s_workers
  become: yes

  tasks:
      - name: Join Cluster
        shell: "{{ hostvars[groups['k8s_masters'][0]]['join_command'] }}"

19. Conclusion

Ansible, as an important tool for modern IT infrastructure automation, provides operations engineers with powerful and flexible configuration management capabilities.

Everyone should start using it now!

A Comprehensive Guide to Ansible for Batch Server Management

Recommended Articles

  • Is our CMDB model wrong?

  • Keepalived, the dual-machine hot backup tool, achieves zero downtime!

  • Linux Shell Tricks: sed

  • Cloud Automation Tool: Terraform

  • How to deal with mining viruses on online Linux servers?

  • Jenkins setup, permission management, parameterization, pipeline, etc., very detailed!

  • How to prevent over 10,000 brute force attacks on online Linux servers every day?

  • Enterprise-level MySQL high availability cluster setup and monitoring, very detailed!

  • Jenkins Pipeline detailed explanation, recommended for collection!

  • Finally understood Nginx reverse proxy!

  • How to troubleshoot network packet loss in Linux? Finally understood!

  • How to implement canary/gray releases in K8s?

  • Analysis of over 20 Linux commands for log analysis, very comprehensive!

  • Deploying a MySQL cluster in K8s, stable!

  • 40 common Nginx interview questions (with answers)

  • Jenkins production environment notes, very detailed!

  • 19 common issues in K8s clusters, recommended for collection

  • Nginx working principles and optimization summary (super detailed)

  • Six high-frequency Linux operation and maintenance troubleshooting notes!

  • 17 commonly used operation and maintenance metrics, 90% of people don’t know!

  • Why does performance drop so much after containerizing applications?

  • Detailed explanation of Nginx rate limiting, dealing with traffic spikes and malicious attacks

  • How to troubleshoot when the Linux disk is full?

  • What to do when the CPU spikes to 900%?

  • Nginx performance optimization is covered in this article!

  • K8s Pod “OOM Killer”, found the reason

  • K8s Pod troubleshooting, an unknown trick!

  • Summary of high concurrency performance optimization notes for Nginx from large companies

  • Building a CI/CD system based on Jenkins

  • Seven application scenarios of Nginx (with configuration)

  • The most comprehensive Jenkins Pipeline detailed explanation

  • Mainstream monitoring system Prometheus learning guide

  • 40 common Nginx interview questions

  • Common Linux operation and maintenance interview questions, a must-read for job seekers!

  • 25 common MySQL interview questions and answers

Leave a Comment