从零开始搭建高可用性 WordPress 网站(2026 版)!第三部分:Ansible

在本系列教程中,我们将从零开始搭建一个高可用性的 WordPress 网站。

第一部分 – 引言、考虑因素和架构
第二部分 – 订购虚拟专用服务器
第三部分 – Ansible(本文)
第四部分——群聚
第五部分 – WordPress 安装
第六部分 – MariaDB 多主数据库
第七部分 – 轮询 DNS、Let's Encrypt 和结论

2021年,我只是在两个节点上执行了所有设置命令。现在我们有三个节点,是时候采取更便捷的方法了。

我们将使用Ansible ,这是一个非常棒的系统和应用程序管理系统工具。你可以把它安装在 node1 上,然后用它来控制所有三个节点,但我用的是一个现成的 Ansible 主节点。其实这都无所谓。

安装 Ansible:

 apt install ansible

在我的 Ansible 主服务器上,我挂载了一个位于 /ansible 的文件系统,其中包含了我需要的所有文件。但是,如果您使用 apt 安装 Ansible,它会在 /etc/ansible 中配置各种内容,所以我们将使用 /etc/ansible。

这是我的 /etc/ansible/hosts 文件:

 [节点]
node1.lowend.party
node2.lowend.party
node3.lowend.party

这样做会创建一个名为“nodes”的组,其中包含我们的三个节点。请确保这些节点已添加到 DNS 中,或者您可以创建类似如下的 /etc/hosts 条目:

 5.78.68.150 node1.lowend.party node1
5.78.91.194 节点2.lowend.party 节点2
5.78.74.126 node3.lowend.party node3

在 /etc/ansible/ansible.cfg 文件中,您无需进行任何更改。

现在到了重点,也就是 playbook 本身。在 Ansible 中,playbook 是一系列待执行的任务(以及其他内容,但这里我们只关注任务)。我们将 playbook 命名为 wp_nodes.yml。.yml 表示该文件采用 YAML 格式。

以下是操作指南:

 ---
  - 名称:设置高可用性 WordPress 节点
    主机:节点
    任务:
      - 名称:主机名
        主机名:name={{ ansible_host }}
      - 名称: /etc/hostname
        lineinfile:
          path=/etc/hostname line="{{ ansible_host }}" create=yes
      - 名称:区域设置生成
        locale_gen: name=en_US.UTF-8 state=present
      - 名称:apt-get update
        apt: update_cache=yes
      - 名称:升级
        apt: upgrade=dist
      - 名称:apt 软件包
        apt: name=nginx,mariadb-server,php-fpm,php-mysql,python3-pymysql,python3-pexpect,glusterfs-server,rsyslog,parted,certbot,python3-certbot-nginx
      - name: 设置时区为美国/太平洋
        community.general.timezone:
          名称:美国/太平洋
      - 名称: /etc/profile mods
        blockinfile:
          路径:/etc/profile
          块:|
            别名 ll='ls -al'
            设置 -o vi
      - name: 运行 mysql_secure_installation
        预计:
          命令:mysql_secure_installation
          回复:
            请输入root用户的当前密码:''
            '切换到 unix_socket 身份验证' : 'Y'
            '更改root密码':'是'
            设置root密码:'Y'
            “新密码”: “强密码”
            请重新输入新密码:'StrongPassword'
            '移除匿名用户':'是'
            '禁止远程root用户登录': 'Y'
            '删除测试数据库': '是'
            “立即重新加载权限表”:'是'
          超时:1
      - 名称:创建 WordPress 数据库
        mysql_db: login_user=root login_password="StrongPassword" name=wp state=present collat​​ion=utf8_general_ci
      - 名称:创建数据库用户
        mysql_user: login_user=root login_password="StrongPassword" name=wp password=ComplePassword priv=wp.*:ALL host=localhost 
      - 名称:nginx 日志轮转
        复制:src=/ansible/src/nodes/nginx_web_dirs dest=/etc/logrotate.d owner=root group=root mode=0644 force=yes 
      - 名称:nginx www.lowend.party
        复制:src=/ansible/src/nodes/www.lowend.party dest=/etc/nginx/sites-available owner=root group=root mode=0644 force=yes 
      - 名称:创建启用站点的符号链接
        文件:src=/etc/nginx/sites-available/www.lowend.party dest=/etc/nginx/sites-enabled/www.lowend.party state=link
      - 名称:nginx 日志目录
        文件:路径=/var/log/nginx/www.lowend.party 状态=目录 所有者=www-data 组=adm 模式=0775 
      - 名称:nginx 访问日志
        文件:路径=/var/log/nginx/www.lowend.party/access.log 状态=touch 所有者=www-data 组=adm 模式=0664 状态=touch
      - 名称:nginx 错误日志
        文件:路径=/var/log/nginx/www.lowend.party/error.log 状态=touch 所有者=www-data 组=adm 模式=0664 状态=touch
      - 名称:nginx /web
        文件:路径=/web 状态=目录 所有者=www-data 组=adm 模式=0775 
      - name: nginx /web/www.lowend.party
        文件:路径=/web/www.lowend.party 状态=目录 所有者=www-data 组=adm 模式=0775 
      - name: 重启 nginx
        服务:名称=nginx 已启用=是 状态=已重启
      - 名称:Gluster 挂载点
        文件:路径=/gluster 状态=目录 所有者=root 组=root 模式=0777

让我们一步一步来分析。

  
---
  - 名称:设置高可用性 WordPress 节点
    主机:节点

name 参数只是 playbook 的描述符。hosts 参数告诉我们 playbook 将针对 /etc/ansible/hosts 文件中的哪个组运行。

任务:
      - 名称:主机名
        主机名:name={{ ansible_host }}
      - 名称: /etc/hostname
        lineinfile:
          path=/etc/hostname line="{{ ansible_host }}" create=yes

每个 Ansible 命令都利用了 Ansible 的一个模块。你无需编写自己的 Bash 或其他代码,只需将参数传递给 Ansible 模块,所有工作都由模块完成。这使你无需担心语法、逻辑、引用等问题。

这里我们使用 hostname 模块,并为其指定 Ansible 变量“ansible_host”。该变量的值将为 node1.lowend.party 等,该模块将据此设置系统主机名。

接下来,我们使用“lineinfile”模块来确保主机名被放入 /etc/hostname 中(我认为这是 Debian 的一个特性),这样系统在启动时就能始终获取到正确的主机名。

 - 名称:区域设置生成
        locale_gen: name=en_US.UTF-8 state=present

接下来,我们为环境生成合适的区域设置,确保选择 en_US.UTF-8。当然,您可以根据自身需求进行调整。

 - 名称:apt-get update
        apt: update_cache=yes
      - 名称:升级
        apt: upgrade=dist
      - 名称:apt 软件包
        apt: name=nginx,mariadb-server,php-fpm,php-mysql,python3-pymysql,python3-pexpect,glusterfs-server,rsyslog,parted,certbot,python3-certbot-nginx

这里我们使用 Ansible apt 模块来做三件事:

  • apt-get update
  • apt-get upgrade
  • 安装一些我们需要的apt软件包。是否运行rsyslog取决于你。我个人更喜欢使用传统的文本日志,而不是所有日志都用journalctl记录,但这完全取决于你。
 - name: 设置时区为美国/太平洋
        community.general.timezone:
          名称:美国/太平洋

在这里设置时区。口味可根据个人喜好调整。

 - 名称: /etc/profile mods
        blockinfile:
          路径:/etc/profile
          块:|
            别名 ll='ls -al'
            设置 -o vi

我只是把它作为示例保留下来,但这完全是可选的。我喜欢在我的 `/etc/profile` 文件中添加这两行,因为无论我以哪个用户身份工作,我都希望设置该别名和选项。`blockinfile` 模块的作用是确保指定的文件(在本例中为 `/etc/profile`)中包含该代码块(此处列出的两个命令)。

 - 名称:运行 mysql_secure_installation
        预计:
          命令:mysql_secure_installation
          回复:
            请输入root用户的当前密码:''
            '切换到 unix_socket 身份验证' : 'Y'
            '更改root密码':'是'
            设置root密码:'Y'
            “新密码”: “强密码”
            请重新输入新密码:'StrongPassword'
            '移除匿名用户':'是'
            '禁止远程root用户登录': 'Y'
            '删除测试数据库': '是'
            “立即重新加载权限表”:'是'
          超时:1

安装 MySQL(实际上是 MariaDB)时,建议运行 `mysql_secure_installation` 命令。但我们不会手动运行该命令,而是使用 Ansible 的 expect 模块。您只需告诉它要运行的命令,以及预期输出和要提供的答案。本节将逐步讲解 `mysql_secure_installation` 命令的问题并提供相应的答案。当然,您应该将 `StrongPassword` 替换为一个真正强大的密码!

 - 名称:创建 WordPress 数据库
        mysql_db: login_user=root login_password="StrongPassword" name=wp state=present collat​​ion=utf8_general_ci
      - 名称:创建数据库用户
        mysql_user: login_user=root login_password="StrongPassword" name=wp password=ComplexPassword priv=wp.*:ALL host=localhost 

这里我们为 WordPress 创建一个 MariaDB 数据库,为该数据库创建一个用户,并授予其相应的权限。请注意,即使您多次运行此 playbook,Ansible 也足够智能,会首先检查数据库是否存在,而不会因为尝试重新创建数据库而报错。

 - 名称:nginx 日志轮转
        复制:src=/ansible/src/nodes/nginx_web_dirs dest=/etc/logrotate.d owner=root group=root mode=0644 force=yes 
      - 名称:nginx www.lowend.party
        复制:src=/ansible/src/nodes/www.lowend.party dest=/etc/nginx/sites-available owner=root group=root mode=0644 force=yes 

这里我们将两个本地文件从 Ansible 主服务器分发到每个节点。我将它们存储在 /ansible/src 目录下,但您可以将它们存储在任何位置。

以下是这些文件的内容。

 - 名称:创建启用站点的符号链接
        文件:src=/etc/nginx/sites-available/www.lowend.party dest=/etc/nginx/sites-enabled/www.lowend.party state=link

我们将 /etc/nginx/sites-enabled/www.lowend.party 链接到 /etc/nginx/sites-available/www.lowend.party,这是 Debian 上的标准 Nginx 设置。

 - 名称:nginx 日志目录
        文件:路径=/var/log/nginx/www.lowend.party 状态=目录 所有者=www-data 组=adm 模式=0775 
      - 名称:nginx 访问日志
        文件:路径=/var/log/nginx/www.lowend.party/access.log 状态=touch 所有者=www-data 组=adm 模式=0664 状态=touch
      - 名称:nginx 错误日志
        文件:路径=/var/log/nginx/www.lowend.party/error.log 状态=touch 所有者=www-data 组=adm 模式=0664 状态=touch

我们为 Nginx 创建了目录以及 access.log 和 error.log 文件。我更倾向于将每个站点放在各自的目录中。

 - 名称:nginx /web
        文件:路径=/web 状态=目录 所有者=www-data 组=adm 模式=0775 
      - name: nginx /web/www.lowend.party
        文件:路径=/web/www.lowend.party 状态=目录 所有者=www-data 组=adm 模式=0775 

我将我的网站根目录组织在 /web 目录下(是的,就在根目录下——为什么不呢?)。

 - name: 重启 nginx
        服务:名称=nginx 已启用=是 状态=已重启
      - 名称:Gluster 挂载点
        文件:路径=/gluster 状态=目录 所有者=root 组=root 模式=0777

最后,我们重启 nginx 服务,并创建 gluster 需要的另一个目录。

我们从 /ansible/src/nginx_web_dirs 分发到所有节点的 /etc/logrotate.d/nginx_web_dirs 文件内容如下:

 /var/log/nginx/*/*.log {
	日常的
	失踪
	旋转14
	压缩
	延迟压缩
	通知为空
	创建 0640 www-data adm
	共享脚本
	预旋转
		如果 [ -d /etc/logrotate.d/httpd-prerotate ]; 则 \
			run-parts /etc/logrotate.d/httpd-prerotate; \
		fi \
	结束脚本
	旋转后
		invoke-rc.d nginx rotate >/dev/null 2>&1
	结束脚本
}

只有在使用 rsyslog 时才需要这样做。

放置在 /etc/nginx/sites-available/www.lowend.party 目录下的 Nginx 文件内容如下:

服务器 {
  服务器名称 www.lowend.party;
  access_log /var/log/nginx/www.lowend.party/access.log;
  错误日志 /var/log/nginx/www.lowend.party/error.log;

  location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(.*)$;
    包含 /etc/nginx/fastcgi_params;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /web/www.lowend.party$fastcgi_script_name;
  }

  地点 / {
    根目录 /web/www.lowend.party;
    index index.php index.html;
    try_files $uri $uri/ /index.php;
    如果 (!-e $request_filename) {
      重写 . /index.php 最后;
    }
  }
}

这是一个非常标准的 Nginx 配置。如您所见,我们使用的是 PHP-FPM,这是我们之前安装的软件包。

哇,我们用 Ansible 完成了好多工作:

  • 设置主机名、语言环境和时区
  • 使用 apt 安装软件包
  • 建立数据库并保护其安全
  • 安装 rsyslog 并配置其轮换 Nginx
  • 安装 Nginx、配置 Nginx、配置网站并设置网站日志

下次我们就能让 GlusterFS 运行起来!