在DevOps实践中,环境部署的重复性和一致性一直是困扰技术团队的痛点。想象一下,当你需要在十台服务器上部署相同的Frappe-Bench环境时,手动执行每个安装步骤不仅耗时费力,还容易因人为疏忽导致环境差异。这正是Ansible这类基础设施即代码(IaC)工具大显身手的场景。
本文将带你从零开始构建一个完整的Ansible Playbook,实现从裸机到Frappe-Bench环境的全自动部署。不同于传统的手动命令行教程,我们将采用声明式配置方法,确保每次部署都像运行一个命令那么简单。无论你是需要频繁重建环境的开发者,还是管理多台服务器的运维工程师,这套自动化方案都能显著提升你的工作效率。
在开始编写Playbook之前,我们需要明确目标环境的架构需求。Frappe-Bench作为应用框架,对底层软件栈有特定要求:
提示:虽然可以手动安装这些组件,但通过Ansible的幂等性特性,我们可以确保无论执行多少次,最终环境状态都保持一致。
首先准备Ansible控制节点(可以是你的本地开发机或专用管理服务器):
bash复制# 在Ubuntu/Debian上安装Ansible
sudo apt update
sudo apt install -y ansible git
# 验证安装
ansible --version
创建项目目录结构:
code复制frappe-ansible/
├── inventories/
│ └── production
├── group_vars/
│ └── all.yml
├── roles/
│ ├── common/
│ ├── mariadb/
│ ├── nodejs/
│ └── frappe/
└── playbook.yml
我们的主playbook将协调各个角色的执行顺序。创建playbook.yml:
yaml复制---
- name: Deploy Frappe-Bench on Ubuntu 22.04
hosts: all
become: true
gather_facts: true
vars_files:
- group_vars/all.yml
roles:
- role: common
tags: common
- role: mariadb
tags: database
- role: nodejs
tags: nodejs
- role: frappe
tags: frappe
在group_vars/all.yml中定义全局变量:
yaml复制# 系统配置
system_timezone: Asia/Shanghai
system_locale: en_US.UTF-8
# 软件版本
nodejs_version: "18.x"
python_version: "3.10"
mariadb_version: "10.6"
# Frappe配置
frappe_user: "frappe"
frappe_bench_name: "frappe-bench"
frappe_version: "version-15"
创建roles/common/tasks/main.yml处理系统级配置:
yaml复制---
- name: Update apt cache and upgrade packages
apt:
update_cache: yes
upgrade: dist
autoremove: yes
- name: Install essential packages
apt:
name:
- curl
- wget
- git
- vim
- openssh-server
- software-properties-common
state: present
- name: Set timezone
timezone:
name: "{{ system_timezone }}"
- name: Generate locale
locale_gen:
name: "{{ system_locale }}"
state: present
- name: Create frappe user
user:
name: "{{ frappe_user }}"
groups: sudo
append: yes
shell: /bin/bash
password: "{{ 'password' | password_hash('sha512') }}"
MariaDB角色(roles/mariadb/tasks/main.yml)需要处理数据库安装和配置:
yaml复制---
- name: Add MariaDB repository
apt_repository:
repo: "deb [arch=amd64,arm64,ppc64el] http://mirrors.tencentyun.com/mariadb/repo/{{ mariadb_version }}/ubuntu jammy main"
state: present
filename: mariadb
update_cache: yes
- name: Install MariaDB server
apt:
name:
- mariadb-server
- libmysqlclient-dev
state: present
- name: Configure MariaDB character set
template:
src: templates/my.cnf.j2
dest: /etc/mysql/my.cnf
owner: root
group: root
mode: 0644
notify: restart mariadb
- name: Secure MariaDB installation
mysql_secure_installation:
login_password: ""
change_root_password: yes
new_root_password: "{{ mysql_root_password }}"
remove_anonymous_users: yes
disallow_root_login_remotely: no
remove_test_database: no
对应的模板文件roles/mariadb/templates/my.cnf.j2:
ini复制[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
innodb-file-format=barracuda
innodb-file-per-table=1
innodb-large-prefix=1
[mysql]
default-character-set = utf8mb4
Node.js角色(roles/nodejs/tasks/main.yml)负责JavaScript运行时的安装:
yaml复制---
- name: Add NodeSource repository
shell: |
curl -fsSL https://deb.nodesource.com/setup_{{ nodejs_version }} | bash -
args:
warn: false
- name: Install Node.js and npm
apt:
name:
- nodejs
state: present
- name: Install Yarn globally
npm:
name: yarn
global: yes
核心的Frappe安装角色(roles/frappe/tasks/main.yml)需要处理Python环境和Frappe本身的安装:
yaml复制---
- name: Install Python dependencies
apt:
name:
- python{{ python_version }}-dev
- python{{ python_version }}-venv
- python3-pip
- python3-setuptools
- virtualenv
- redis-server
- wkhtmltopdf
- xvfb
- libfontconfig
- nginx
- cron
state: present
- name: Configure pip with mirror
pip_conf:
global:
index-url: https://pypi.tuna.tsinghua.edu.cn/simple
trusted-host: pypi.tuna.tsinghua.edu.cn
- name: Install frappe-bench CLI
pip:
name: frappe-bench
state: present
- name: Initialize frappe-bench
command: >
bench init {{ frappe_bench_name }}
--frappe-branch {{ frappe_version }}
--frappe-path=https://gitee.com/mirrors/frappe
--verbose
args:
chdir: "/home/{{ frappe_user }}"
environment:
PATH: "/home/{{ frappe_user }}/.local/bin:{{ ansible_env.PATH }}"
become_user: "{{ frappe_user }}"
become: yes
为了让部署更加健壮,我们需要添加错误处理和验证步骤。在roles/frappe/tasks/main.yml追加:
yaml复制- name: Verify installations
block:
- name: Check Node.js version
command: node --version
register: node_version
changed_when: false
- name: Check Python version
command: python3 --version
register: python_version
changed_when: false
- name: Check bench CLI
command: bench --version
register: bench_version
changed_when: false
environment:
PATH: "/home/{{ frappe_user }}/.local/bin:{{ ansible_env.PATH }}"
become_user: "{{ frappe_user }}"
become: yes
rescue:
- name: Notify admin about installation failure
debug:
msg: "Frappe-Bench installation failed. Please check the logs."
对于生产环境,我们还需要配置Nginx作为反向代理。创建roles/frappe/templates/nginx.conf.j2:
nginx复制server {
listen 80;
server_name {{ inventory_hostname }};
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /assets {
root /home/{{ frappe_user }}/{{ frappe_bench_name }}/sites;
}
}
对应的部署任务:
yaml复制- name: Configure Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/frappe
owner: root
group: root
mode: 0644
notify: restart nginx
- name: Enable Nginx site
file:
src: /etc/nginx/sites-available/frappe
dest: /etc/nginx/sites-enabled/frappe
state: link
notify: restart nginx
完成所有角色编写后,可以通过以下命令执行部署:
bash复制# 在inventories/production中定义目标主机
[all]
frappe-server ansible_host=192.168.1.100 ansible_user=root
# 执行Playbook
ansible-playbook -i inventories/production playbook.yml
部署完成后,验证服务状态:
bash复制# 检查服务状态
systemctl status mariadb nginx redis
# 进入frappe-bench目录
su - frappe
cd frappe-bench
# 启动开发服务器
bench start
对于需要频繁重建环境的场景,可以将整个Playbook与Vagrant或Terraform结合,实现从虚拟机创建到应用部署的完整自动化流程。