news 2026/9/24 20:41:27

Deployer Databases Recipe 实战指南:一条命令完成 MySQL / MariaDB / PostgreSQL 数据库供给

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Deployer Databases Recipe 实战指南:一条命令完成 MySQL / MariaDB / PostgreSQL 数据库供给

Deployer Databases Recipe 实战指南:一条命令完成 MySQL / MariaDB / PostgreSQL 数据库供给

【免费下载链接】deployerThe PHP deployment tool with support for popular frameworks out of the box项目地址: https://gitcode.com/gh_mirrors/de/deployer

导读

recipe/provision/databases.php是 Deployer 提供服务器供给(provision)能力的核心配方之一,它负责在全新的 Ubuntu 服务器上自动安装数据库服务、创建数据库账号、授权并建库。阅读本文后,你将掌握如何通过provision:databases任务一键部署 MySQL、MariaDB 或 PostgreSQL,理解db_typedb_namedb_userdb_password四个配置项的取值与底层交互逻辑,并能在自己的部署脚本中安全、正确地组合使用这套数据库供给任务。

一、Databases Recipe 是什么

Databases Recipe 是 Deployer 供给体系(Provision)中的数据库子模块,对应仓库文件 recipe/provision/databases.php。它不是一个独立可部署的应用配方,而是被上层 recipe/provision.php 通过require __DIR__ . '/provision/databases.php';引入,作为provision大任务链条中的一环(见 recipe/provision.php)。

它的职责非常聚焦:在目标服务器上完成数据库层面的初始化,包括:

  • 安装数据库服务端软件(MySQL / MariaDB / PostgreSQL 三选一);
  • 创建可远程登录的数据库用户并授权;
  • 按指定字符集与排序规则创建应用数据库。

整套数据库任务都依赖 Deployer 的 SSH 执行能力,属于“服务器供给”而非“应用部署”范畴,通常只在服务器首次初始化时运行一次。

二、引入方式

与 Deployer 中所有配方一致,Databases Recipe 通过require引入。在部署脚本(deploy.php)顶部添加:

require 'recipe/provision/databases.php';

如果引入了完整供给配方,则无需单独引入:

require 'recipe/provision.php';

因为 recipe/provision.php 已经替你引入了databases.php,同时还会引入nodejs.phpphp.phpuser.phpwebsite.php等兄弟模块。

注意:仓库中对应的说明文档 docs/recipe/provision/databases.md 为自动生成产物,头部明确标注DO NOT EDIT THIS FILE!,源码唯一权威入口是 recipe/provision/databases.php,文档由bin/docgen生成。

三、配置项详解(Configuration)

Databases Recipe 定义了 4 个配置项,全部采用**惰性求值(闭包)**方式定义,即只有在任务执行中真正访问它们时才会触发交互式提问。这与 Deployer 中set()+get()的配置体系完全一致(参见 src/functions.php 中set/get的实现:set将值与闭包存入配置容器,get在访问时才求值闭包)。

3.1db_type—— 选择数据库类型(自动生成)

set('db_type', function () { $supportedDbTypes = [ 'none', 'mysql', 'mariadb', 'postgresql', ]; return askChoice(' What DB to install? ', $supportedDbTypes, 0); });
  • 取值nonemysqlmariadbpostgresql,对应源码 recipe/provision/databases.php。
  • 交互方式:通过askChoice()弹出选择列表,默认选中索引0,即none(不安装数据库)。
  • 特别说明:该配置项是“autogenerated on access”,意味着它不会预先写入配置,只有在访问时才触发提问。选择none时,provision:databases任务会直接跳过数据库安装(见下文任务实现)。
  • 推荐做法:在部署脚本中通过set('db_type', 'mysql')预先固定,避免每次执行都进入交互式选择,也便于 CI 环境使用--option或配置注入。

3.2db_name—— 数据库名称

return ask(' DB name: ', 'prod');
  • 默认值prod
  • 交互方式ask()普通文本提问,可输入任意数据库名。
  • 用途:该名称会用于CREATE DATABASE IF NOT EXISTS(MySQL/MariaDB)或CREATE DATABASE(PostgreSQL)建库操作。

3.3db_user—— 数据库用户

return ask(' DB user: ', 'deployer');
  • 默认值deployer
  • 用途:用于创建数据库账号并授予权限。Deployer 默认使用与部署用户一致的命名,便于后续应用连接。

3.4db_password—— 数据库密码(隐藏输入)

return askHiddenResponse(' DB password: ');
  • 交互方式askHiddenResponse()以隐藏输入方式提问,不显示回显,且关闭了隐藏回退(setHiddenFallback(false)),确保密码不会出现在终端上(见 src/functions.php)。
  • 安全机制:该密码在任务内部通过secrets机制(%db_password%占位符)传递,在run()输出中会被脱敏,不会泄露到终端日志。

这三个配置项同样支持在部署脚本中预先set()固定,例如:

host('prod') ->set('db_type', 'mysql') ->set('db_name', 'myapp') ->set('db_user', 'myapp_user') ->set('db_password', 'S3cret!Pass');

固定后,provision任务链中的provision:configure会检测到这些参数已显式配置(通过hasOwn判断),从而跳过交互式收集,并直接打印已生成的配置代码块(见 recipe/provision.php)。

四、任务详解(Tasks)

Databases Recipe 共定义 4 个任务,其中 1 个调度任务 + 3 个具体数据库供给任务。

4.1provision:databases—— 供给调度任务

desc('Provision databases'); task('provision:databases', function () { set('remote_user', get('provision_user')); $dbType = get('db_type'); if ($dbType === 'none') { return; } invoke('provision:' . $dbType); }) ->limit(1);
  • 核心逻辑:先设置remote_userprovision_user(默认root,见 recipe/provision.php),随后读取db_type:若为none直接返回;否则通过invoke('provision:' . $dbType)动态调用对应子任务(见 recipe/provision/databases.php)。
  • invoke()机制invoke是 Deployer 提供的内置函数,用于在任务内部调用另一个任务(见 src/functions.php),它会启动/结束日志记录并执行目标任务。这里通过字符串拼接实现“任务分发”,是典型的策略模式用法。
  • ->limit(1):限定该任务在多主机并行场景下只在一台主机上执行,避免在集群环境中重复安装数据库。

4.2provision:mysql—— 安装并初始化 MySQL

desc('Provision MySQL'); task('provision:mysql', function () { run('apt-get install -y mysql-server', env: ['DEBIAN_FRONTEND' => 'noninteractive'], timeout: 900); run("mysql --user=\"root\" -e \"CREATE USER IF NOT EXISTS '{{db_user}}'@'0.0.0.0' IDENTIFIED BY '%db_password%';\"", secrets: ['db_password' => get('db_password')]); run("mysql --user=\"root\" -e \"CREATE USER IF NOT EXISTS '{{db_user}}'@'%' IDENTIFIED BY '%db_password%';\"", secrets: ['db_password' => get('db_password')]); run("mysql --user=\"root\" -e \"GRANT ALL PRIVILEGES ON *.* TO '{{db_user}}'@'0.0.0.0' WITH GRANT OPTION;\""); run("mysql --user=\"root\" -e \"GRANT ALL PRIVILEGES ON *.* TO '{{db_user}}'@'%' WITH GRANT OPTION;\""); run("mysql --user=\"root\" -e \"FLUSH PRIVILEGES;\""); run("mysql --user=\"root\" -e \"CREATE DATABASE IF NOT EXISTS {{db_name}} character set UTF8mb4 collate utf8mb4_bin;\""); });

执行步骤如下(见 recipe/provision/databases.php):

  1. 安装apt-get install -y mysql-server,通过env: ['DEBIAN_FRONTEND' => 'noninteractive']禁止 apt 交互式提问,timeout: 900将命令超时放宽到 900 秒(默认超时为default_timeout,即 300 秒,见 src/functions.php),确保大体积安装包能在慢速网络上完成。
  2. 创建用户:同时创建'{{db_user}}'@'0.0.0.0''{{db_user}}'@'%'两个主机匹配项,分别覆盖通过 IPv4 任意地址和任意主机名连接的场景。
  3. 授予权限GRANT ALL PRIVILEGES ON *.* ... WITH GRANT OPTION赋予全部库表的全权限并允许继续授权。
  4. 刷新权限FLUSH PRIVILEGES
  5. 建库CREATE DATABASE IF NOT EXISTS {{db_name}} character set UTF8mb4 collate utf8mb4_bin,字符集使用UTF8mb4、排序规则使用utf8mb4_bin,兼容 Emoji 与二进制排序语义。

安全细节:密码通过secrets: ['db_password' => get('db_password')]传入,命令中的%db_password%占位符在run()执行时被脱敏替换(run()secrets参数签名见 src/functions.php),确保密码不会明文出现在进程参数与日志中。

4.3provision:mariadb—— 安装并初始化 MariaDB

desc('Provision MariaDB'); task('provision:mariadb', function () { run('apt-get install -y mariadb-server', env: ['DEBIAN_FRONTEND' => 'noninteractive'], timeout: 900); // ...与 MySQL 相同的建用户、授权、建库 SQL });

逻辑与provision:mysql完全一致(见 recipe/provision/databases.php),唯一区别是安装包改为mariadb-server,其余CREATE USERGRANTFLUSH PRIVILEGESCREATE DATABASE语句与 MySQL 分支相同——因为 MariaDB 使用mysql命令行客户端,SQL 方言兼容。

4.4provision:postgresql—— 安装并初始化 PostgreSQL

desc('Provision PostgreSQL'); task('provision:postgresql', function () { run('apt-get install -y postgresql postgresql-contrib', env: ['DEBIAN_FRONTEND' => 'noninteractive'], timeout: 900); run("sudo -u postgres psql <<< $'CREATE DATABASE {{db_name}};'"); run("sudo -u postgres psql <<< $'CREATE USER {{db_user}} WITH ENCRYPTED PASSWORD \'%db_password%\';'", secrets: ['db_password' => get('db_password')]); run("sudo -u postgres psql <<< $'GRANT ALL PRIVILEGES ON DATABASE {{db_name}} TO {{db_user}};'"); });

PostgreSQL 分支实现差异明显(见 recipe/provision/databases.php):

  1. 安装:安装postgresqlpostgresql-contrib(后者提供常用扩展与工具),同样使用noninteractive环境变量与 900 秒超时。
  2. 建库:通过sudo -u postgres psql切换到 postgres 超级用户执行CREATE DATABASE {{db_name}}。注意 PostgreSQL 没有IF NOT EXISTS语法(此处为直接创建),重复执行会报错。
  3. 建用户CREATE USER {{db_user}} WITH ENCRYPTED PASSWORD '...',使用加密密码存储,密码经secrets机制脱敏传递。
  4. 授权GRANT ALL PRIVILEGES ON DATABASE {{db_name}} TO {{db_user}},将目标库的全部权限授予应用用户。

与 MySQL/MariaDB 的差异:PostgreSQL 使用psql工具、以postgres系统用户身份执行 SQL、权限作用域是单个数据库而非*.*。同时其run()调用以sudo开头,会触发 src/functions.php 中内置的 sudo 密码处理逻辑:若当前用户无免密 sudo,Deployer 会通过sudo_askpass机制交互式收集 sudo 密码。

五、与 Provision 主任务链的集成

Databases Recipe 是整个provision供给流程的组成部分。在 recipe/provision.php 中,provision是一个包含 15 个子任务的组任务:

task('provision', [ 'provision:check', 'provision:configure', 'provision:update', 'provision:upgrade', 'provision:install', 'provision:ssh', 'provision:firewall', 'provision:user', 'provision:php', 'provision:node', 'provision:databases', // ← 数据库供给在此位置 'provision:composer', 'provision:server', 'provision:website', 'provision:verify', ]);

provision:databases被编排在 PHP、Node 供给之后、Composer 与 Web 站点配置之前,这符合依赖顺序:先有数据库,才能为站点与应用提供数据存储。你可以单独运行:

dep provision:databases

也可以随完整供给流程运行:

dep provision

运行dep provision时,provision:configure(见 recipe/provision.php)会提前收集db_type,并仅在db_type !== 'none'继续收集db_userdb_namedb_password,随后把收集到的参数以host(...)->set(...)代码块的形式打印出来,方便固化到部署脚本中。

运行示例

以默认交互方式单独执行数据库供给:

dep provision:databases

终端将依次出现如下交互(默认值用括号标注):

What DB to install? [0] none: [1] mysql [2] mariadb [3] postgresql > 1 DB name: (prod) myapp DB user: (deployer) myapp_user DB password: ********

全部回答后,Deployer 通过 SSH 以rootprovision_user)身份在服务器上完成安装、建用户、授权与建库。注意:由于数据库密码默认来自交互输入,在 CI/CD 等非交互环境中务必提前通过set('db_password', ...)固定,或在host()定义中注入。

六、源码级要点总结

要点实现位置说明
配置项惰性求值recipe/provision/databases.phpset()+ 闭包,访问时才触发askChoice/ask/askHiddenResponse
交互式选择src/functions.phpaskChoice基于 SymfonyChoiceQuestionnone为默认索引 0
隐藏密码输入src/functions.phpaskHiddenResponse设置setHidden(true)且禁止回退明文
密码脱敏src/functions.phprun()secrets参数,%db_password%占位符不落入日志
任务分发src/functions.phpinvoke('provision:' . $dbType)动态调用子任务
单机限制recipe/provision/databases.php->limit(1)避免多主机重复建库
安装超时src/functions.phptimeout: 900覆盖默认 300 秒
Ubuntu 支持recipe/provision.phpprovision:check仅校验 Ubuntu 20+,其余系统会告警

七、实践建议与注意事项

  1. 首次供给务必交互式运行db_password默认无默认值,非交互环境(-q)下askHiddenResponse会返回空字符串,导致创建出空密码用户,务必显式配置。
  2. db_type固定为none可跳过:若服务器已有数据库(如云厂商托管 RDS),将db_type设为noneprovision:databases会立即返回,不干扰既有环境。
  3. MySQL/MariaDB 是幂等的CREATE USER IF NOT EXISTSGRANTCREATE DATABASE IF NOT EXISTS均可重复执行;PostgreSQL 分支非幂等CREATE DATABASE/CREATE USERIF NOT EXISTS),重复执行会报错,需注意脚本重跑场景。
  4. 远程访问授权:MySQL/MariaDB 分支创建了@'0.0.0.0'@'%'两个主机项,允许数据库用户从任意地址连接;若仅需本机访问,可自行覆写任务收紧 host 匹配。
  5. 安全基线:供给完成后建议在防火墙(provision:firewall已放行 22/80/443,见 recipe/provision.php)基础上,根据实际需要决定是否对外暴露数据库端口;本配方默认不修改 MySQL/MariaDB 的监听配置。

相关资源

  • 配方源码:recipe/provision/databases.php
  • 自动生成文档:docs/recipe/provision/databases.md
  • 上层供给配方:recipe/provision.php 与 docs/recipe/provision.md
  • 交互函数实现:src/functions.php(ask/askChoice/askHiddenResponse/run/invoke/set/get
  • 兄弟供给模块:recipe/provision/nodejs.php、recipe/provision/php.php、recipe/provision/user.php、recipe/provision/website.php

【免费下载链接】deployerThe PHP deployment tool with support for popular frameworks out of the box项目地址: https://gitcode.com/gh_mirrors/de/deployer

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 20:41:25

本地AI Agent两小时实操指南:LangChain+Ollama+Llama3部署

1. 这不是装系统&#xff0c;是给电脑装“脑子”——从标题看懂AI Agent的本质与实操门槛 “花两小时装了ai agent……”——看到这个标题&#xff0c;我第一反应不是点开&#xff0c;而是笑了。笑完立刻打开终端敲了几行命令&#xff0c;因为太熟悉这种状态&#xff1a;既兴奋…

作者头像 李华
网站建设 2026/9/24 20:41:23

Asyncio高并发调优:背压与批处理的工程实践

1. 并发拉满却更慢了&#xff1a;一次线上事故让我重新理解 Asyncio先讲个真实经历。之前维护的一个数据同步服务&#xff0c;用 asyncio 写了一个定时任务&#xff0c;需要从消息队列拉取几万条数据&#xff0c;再逐条写入下游存储。第一版代码写得很"自信"&#xf…

作者头像 李华
网站建设 2026/9/24 20:40:10

河道水质视觉检测系统:YOLOv8n轻量化部署与PyQt实战

简介&#xff1a;本资源是一套面向软件工程专业本科生的毕业设计实战项目&#xff0c;聚焦河道水质智能监测场景&#xff0c;提供基于Python的端到端水质检测系统完整实现。项目融合环境科学指标&#xff08;pH、溶解氧、氨氮等&#xff09;与算法工程实践&#xff0c;涵盖传感…

作者头像 李华
网站建设 2026/9/24 20:40:07

400张图+YOLOv8:工业手套质检落地实战指南

简介&#xff1a;本资源是一套专为YOLO系列目标检测算法训练与验证设计的手套识别数据集&#xff0c;面向计算机视觉初学者、AI开发者及工业质检场景实践者&#xff0c;解决小目标、高相似度手套类物体的检测模型训练数据匮乏问题。压缩包共1201个文件&#xff0c;含400张带标注…

作者头像 李华
网站建设 2026/9/24 20:40:02

Tauri vs Electron:桌面应用体积与架构权衡实战指南

1. 为什么 Electron 的“大”正在成为业务毒瘤&#xff1a;从 224MB 到 4.7MB 不是数字游戏&#xff0c;而是架构权衡的具象化你有没有在客户现场演示新桌面应用时&#xff0c;被一句“这软件怎么比微信还大&#xff1f;”当场钉在原地&#xff1f;我做过三个 Electron 项目&am…

作者头像 李华
网站建设 2026/9/24 20:39:11

Python零基础实战:从环境配置到爬虫、数据分析与可视化

1. 说在前面&#xff1a;为什么是“python 完”&#xff0c;以及怎么才算“完”前阵子有个朋友甩给我一句话&#xff1a;“python 完。”我第一反应是&#xff1a;怎么&#xff0c;Python 还能“完”&#xff1f;后来才明白&#xff0c;他想说的是“Python 玩完了”——这里特指…

作者头像 李华