使用Ansible自动化部署WordPress

本文详解如何使用Ansible自动化部署WordPress,包括Playbook编写、角色管理和多环境配置。

为什么使用Ansible

方式 问题 Ansible优势
手动部署 易出错、不可复现 幂等性、可重复执行
Shell脚本 无状态管理、难回滚 状态感知、支持回滚
Docker 学习曲线陡 贴近原生、易调试

环境准备

安装Ansible

# Ubuntu/Debian
sudo apt update
sudo apt install -y ansible

# CentOS/RHEL
sudo yum install -y epel-release
sudo yum install -y ansible

# 验证安装
ansible --version

配置Inventory

# hosts.ini
[webservers]
192.168.1.10 ansible_user=deployer
192.168.1.11 ansible_user=deployer

[dbservers]
192.168.1.20 ansible_user=deployer

[staging]
staging.example.com ansible_user=deployer

[production]
prod1.example.com ansible_user=deployer
prod2.example.com ansible_user=deployer

[all:vars]
ansible_python_interpreter=/usr/bin/python3

基础Playbook结构

目录结构

wordpress-ansible/
├── ansible.cfg
├── hosts.ini
├── site.yml
├── group_vars/
   ├── all.yml
   ├── staging.yml
   └── production.yml
├── host_vars/
   └── prod1.example.com.yml
└── roles/
    ├── common/
    ├── nginx/
    ├── php/
    ├── mysql/
    └── wordpress/

ansible.cfg配置

[defaults]
inventory = hosts.ini
remote_user = deployer
host_key_checking = False
retry_files_enabled = False
stdout_callback = yaml

[privilege_escalation]
become = True
become_method = sudo
become_user = root

编写Roles

Common角色(基础环境)

# roles/common/tasks/main.yml
---
- name: Update apt cache
  apt:
    update_cache: yes
    cache_valid_time: 3600
  when: ansible_os_family == "Debian"

- name: Install basic packages
  package:
    name:
      - vim
      - curl
      - git
      - unzip
      - python3
      - python3-pip
    state: present

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

- name: Configure NTP
  service:
    name: ntp
    state: started
    enabled: yes

Nginx角色

# roles/nginx/tasks/main.yml
---
- name: Add Nginx repository (CentOS)
  yum_repository:
    name: nginx
    description: Nginx repo
    baseurl: http://nginx.org/packages/centos/$releasever/$basearch/
    gpgcheck: no
  when: ansible_os_family == "RedHat"

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

- name: Configure Nginx
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  notify: Restart Nginx

- name: Remove default site
  file:
    path: /etc/nginx/sites-enabled/default
    state: absent
  when: ansible_os_family == "Debian"

- name: Start and enable Nginx
  service:
    name: nginx
    state: started
    enabled: yes
{# roles/nginx/templates/nginx.conf.j2 #}
user {{ nginx_user }};
worker_processes {{ ansible_processor_vcpus }};

events {
    worker_connections 1024;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    {# 这里留空由具体的站点配置填充 #}
    server {
        listen 80 default_server;
        server_name _;
        return 444;
    }
}

PHP角色

# roles/php/tasks/main.yml
---
- name: Add PHP PPA (Ubuntu)
  apt_repository:
    repo: ppa:ondrej/php
  when: ansible_distribution == "Ubuntu"

- name: Install PHP and extensions
  package:
    name:
      - php{{ php_version }}
      - php{{ php_version }}-fpm
      - php{{ php_version }}-mysql
      - php{{ php_version }}-curl
      - php{{ php_version }}-gd
      - php{{ php_version }}-mbstring
      - php{{ php_version }}-xml
      - php{{ php_version }}-zip
      - php{{ php_version }}-opcache
    state: present

- name: Configure PHP-FPM pool
  template:
    src: www.conf.j2
    dest: "/etc/php/{{ php_version }}/fpm/pool.d/www.conf"
  notify: Restart PHP-FPM

- name: Start and enable PHP-FPM
  service:
    name: "php{{ php_version }}-fpm"
    state: started
    enabled: yes

MySQL角色

# roles/mysql/tasks/main.yml
---
- name: Install MySQL
  package:
    name:
      - mysql-server
      - python3-pymysql
    state: present

- name: Start MySQL
  service:
    name: mysql
    state: started
    enabled: yes

- name: Create WordPress database
  mysql_db:
    name: "{{ wp_db_name }}"
    state: present
    login_unix_socket: /var/run/mysqld/mysqld.sock

- name: Create WordPress user
  mysql_user:
    name: "{{ wp_db_user }}"
    password: "{{ wp_db_password }}"
    priv: "{{ wp_db_name }}.*:ALL"
    host: localhost
    state: present
    login_unix_socket: /var/run/mysqld/mysqld.sock

WordPress角色

# roles/wordpress/tasks/main.yml
---
- name: Download WordPress
  get_url:
    url: https://wordpress.org/latest.tar.gz
    dest: /tmp/wordpress.tar.gz
    mode: 0644

- name: Extract WordPress
  unarchive:
    src: /tmp/wordpress.tar.gz
    dest: /tmp/
    remote_src: yes

- name: Create web root
  file:
    path: "{{ wp_root }}"
    state: directory
    owner: "{{ nginx_user }}"
    group: "{{ nginx_user }}"
    mode: 0755

- name: Copy WordPress files
  copy:
    src: /tmp/wordpress/
    dest: "{{ wp_root }}"
    owner: "{{ nginx_user }}"
    group: "{{ nginx_user }}"
    remote_src: yes

- name: Configure wp-config.php
  template:
    src: wp-config.php.j2
    dest: "{{ wp_root }}/wp-config.php"
    owner: "{{ nginx_user }}"
    group: "{{ nginx_user }}"
    mode: 0640

- name: Configure Nginx site for WordPress
  template:
    src: wordpress-site.conf.j2
    dest: "/etc/nginx/sites-available/{{ wp_site_name }}.conf"
  notify: Restart Nginx

- name: Enable Nginx site
  file:
    src: "/etc/nginx/sites-available/{{ wp_site_name }}.conf"
    dest: "/etc/nginx/sites-enabled/{{ wp_site_name }}.conf"
    state: link
  notify: Restart Nginx

主Playbook

# site.yml
---
- name: Deploy WordPress to web servers
  hosts: webservers
  become: yes

  roles:
    - common
    - nginx
    - php
    - wordpress

- name: Configure database
  hosts: dbservers
  become: yes

  roles:
    - common
    - mysql

变量管理

group_vars/all.yml

---
nginx_user: www-data
php_version: "8.2"
wp_root: /var/www/html
wp_site_name: wordpress

group_vars/production.yml

---
wp_db_name: wp_production
wp_db_user: wp_user
wp_db_password: "{{ vault_wp_db_password }}"  # 存在Ansible Vault里
wp_site_url: https://www.example.com

执行部署

测试连通性

ansible all -m ping

执行部署(Staging)

ansible-playbook site.yml -l staging -e env=staging --check  # 干跑测试
ansible-playbook site.yml -l staging -e env=staging         # 实际执行

执行部署(Production)

ansible-playbook site.yml -l production -e env=production

使用Ansible Vault加密敏感数据

# 创建加密文件
ansible-vault create group_vars/production.yml

# 编辑加密文件
ansible-vault edit group_vars/production.yml

# 执行时指定vault密码文件
ansible-playbook site.yml --vault-password-file ~/.vault_pass.txt

回滚方案

# roles/wordpress/tasks/rollback.yml
---
- name: List available backups
  find:
    paths: "{{ wp_root }}/../backups"
    patterns: "wp-backup-*.tar.gz"
    file_type: file
  register: backups

- name: Restore from latest backup
  unarchive:
    src: "{{ (backups.files | sort(attribute='mtime') | last).path }}"
    dest: "{{ wp_root }}/../"
    remote_src: yes
  when: backups.matched > 0
  notify: Restart Nginx

常用调试命令

# 测试特定task
ansible-playbook site.yml --start-at-task="Install Nginx"

# 限制执行主机
ansible-playbook site.yml -l "192.168.1.10"

# 使用详细输出
ansible-playbook site.yml -vvv

# 检查语法
ansible-playbook site.yml --syntax-check

最佳实践

  1. 使用Roles组织代码:便于复用和分享
  2. 敏感数据用Vault加密:密码、API Key不能明文
  3. 多环境配置分离:staging/production用不同的group_vars
  4. 先--check再执行:干跑测试避免意外
  5. 版本控制Playbook:用Git管理,配合CI/CD

目录结构最终版

wordpress-ansible/
├── ansible.cfg
├── hosts.ini
├── site.yml
├── requirements.yml   # Galaxy依赖
├── group_vars/
   ├── all.yml
   ├── staging.yml
   └── production.yml
├── host_vars/
   └── prod1.example.com.yml
├── roles/
   ├── common/
   ├── nginx/
   ├── php/
   ├── mysql/
   └── wordpress/
└── vault.yml.gpg      # GPG加密的vault文件

通过Ansible自动化部署,可以将部署时间从2小时缩短到10分钟,同时大幅降低人为错误。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。