DooTask 安装部署实战:`./cmd install` 一键安装流程、前置检查与故障处理指南
DooTask 安装部署实战:./cmd install 一键安装流程、前置检查与故障处理指南
导读
DooTask 的安装被设计为一条封装完整的命令 ./cmd install(赋权 → 起容器 → composer install → key:generate → migrate --seed → up -d),但"命令好敲"不等于"可以随便敲"。本文以官方安装流程为骨架,结合仓库内 cmd 脚本的真实实现,系统讲解安装前必须完成的 5 项前置检查、--port 与 --relock 两个关键参数的选择逻辑、安装执行与安装后的初始化(数据库密码重置),以及各类典型失败场景的处理矩阵。读完本文,你将能够在服务器上以"刚性流程、单次确认、失败即停"的方式安全完成 DooTask 的首次部署,并理解每一步背后的脚本实现依据。
一、安装的核心模型:单命令封装与职责边界
./cmd install 已经把整套安装封装为一条命令。从 cmd 的 handle_install() 函数可以还原出真实的执行链路,顺序为:
check_sudo:校验是否以 root 执行;check_instance:校验APP_ID是否与其他实例冲突;- (可选)
--relock清理依赖锁文件; permission_fix+ 目录权限检测:修复并验证bootstrap/cache、docker、public、storage等可写目录;- 端口设置与
check_port端口占用检测; docker-compose up php -d:先拉起 PHP 容器(依赖 mariadb、redis 健康后启动);composer install --optimize-autoloader:安装 PHP 依赖,并校验vendor/autoload.php是否生成;php artisan key:generate:生成应用密钥(APP_KEY为空时);switch_debug "false":写入生产模式;php artisan migrate --seed:建库、迁移并灌入种子数据;docker-compose up -d --remove-orphans:启动全部容器;wait_php_healthy兜底拉起 nginx,避免首启时序竞态;- 输出访问地址,并调用
docker/mysql/repassword.sh提示数据库密码。
因此,安装流程的正确姿态是:做好安装前把关、选对参数、执行前与用户确认、遇到已知失败按矩阵处理,而不是把脚本逻辑拆开重做,也不是遇错就"顺手改改别的地方"。
二、前置检查:全部通过才能继续
执行 ./cmd install 前,必须依次确认以下 5 项,任何一项不满足都不得继续。
1. 工作目录:必须在项目根
必须确认当前目录是项目根,且存在以下三个文件:
cmd(管理脚本,1229 行,见 cmd)docker-compose.yml(容器编排定义,见 docker-compose.yml).env.docker(环境变量模板,见 .env.docker)
脚本通过 WORK_DIR="$(pwd)" 取当前目录(见 cmd),容器将把项目目录以 -v ./:/var/www 的方式挂载进 PHP 与 nginx 容器,因此必须在正确的目录下执行。
2. Docker 与 Docker Compose:可用且 daemon 在运行
脚本内置 check_docker() 检查(见 cmd),但提前确认能更早报错:
docker --version可用;docker-compose version或docker compose version(v2+)可用;脚本会拒绝 v1 版本("Docker-compose 版本过低,请升级至 v2+");- Docker daemon 处于运行状态。
3. Node.js ≥ 20
check_node()(见 cmd)会同时检查 npm 与 node,并拒绝 v1x 版本("Node.js 版本过低,请升级至 v20+")。Node 主要用于前端构建(npx vite build)等场景,安装阶段的前置校验可以提前暴露环境问题。
4. APP_ID 不冲突
若 .env 中已有 APP_ID 且被其他实例占用,脚本 check_instance()(见 cmd)会报错。其实现原理是:通过 docker inspect dootask-php-${APP_ID} 查找容器的 /var/www 挂载来源({{range .Mounts}}{{if eq .Destination "/var/www"}}{{.Source}}{{end}}{{end}}),如果挂载路径存在且不等于当前工作目录,说明该 APP_ID 已被另一台实例使用。
此时必须停止,提示用户先清空 .env 里的 APP_ID 和 APP_IPPR 再重新安装。
5. sudo:必须 root 执行
check_sudo()(见 cmd)校验 $EUID -ne 0,非 root 直接报"请使用 sudo 运行此脚本"并退出。因此安装必须使用:
sudo ./cmd install
⚠️ 重操作提醒:安装会创建数据库并执行
migrate --seed(灌入种子数据)。在已有数据的环境上重装前,务必与用户确认,避免覆盖现有数据。
前置检查全部通过后,汇报检查结果,向用户确认一次再执行。
三、参数选择:只有两个参数,按需使用
| 参数 | 作用 | 何时用 |
|---|---|---|
--port <端口> |
指定 HTTP 端口(脚本会做端口占用检测) | 用户要自定义端口,或默认端口被占 |
--relock |
删除 node_modules/package-lock.json/vendor/composer.lock 后重装 |
谨慎:仅在依赖锁损坏、用户明确要求重建锁时用,会拖慢安装 |
--port 的底层检测
从源码看(cmd),check_port() 的占用检测方式很轻量:docker run --rm -p "${port}:80" --entrypoint true nginx:alpine——用一次容器端口绑定来探测端口是否可用,绑定失败即报"端口 xxx 已被占用,请指定其他端口"。默认端口来自 .env 的 APP_PORT,模板默认值为 2222(见 .env.docker)。
--relock 的影响范围
handle_install() 在检测到 --relock 时会执行:
rm -rf node_modules package-lock.json vendor composer.lock
随后重新执行 composer install 与前端依赖安装。由于删除范围包含 vendor 和 node_modules,重建依赖会显著拉长安装时间,因此默认不加,仅在用户明确要求或依赖锁确实损坏时使用。
不确定时不要自作主张加参数,按需询问用户。
四、执行安装
确认后执行(按用户选择带上参数):
sudo ./cmd install
# 或: sudo ./cmd install --port 8080
安装过程中的关键子步骤与源码对应关系:
| 阶段 | 脚本实现 | 说明 |
|---|---|---|
| 目录赋权 | permission_fix() |
项目根设为 755,可写目录归还给 SUDO_UID 调用用户并补组写权限 |
| 权限验证 | 目录权限检测循环 | 用 nginx:alpine 容器挂载各可写目录后 touch dootask.lock,逐个验证 bootstrap/cache、docker、public、storage 四个目录可写 |
| 依赖安装 | composer install --optimize-autoloader |
在 PHP 容器内执行,失败时检查 vendor/autoload.php 是否存在 |
| 密钥生成 | php artisan key:generate |
仅当 APP_KEY 为空时执行 |
| 数据库初始化 | php artisan migrate --seed |
建表 + 灌入种子数据(这是重操作的关键步骤) |
| 全量启动 | docker-compose up -d --remove-orphans |
启动 nginx、php、redis、mariadb、appstore 全部服务 |
容器拓扑一览
安装后系统中将出现 5 个容器(容器名均带 APP_ID 后缀,见 docker-compose.yml):
dootask-php-${APP_ID}:基于kuaifan/php:swoole-8.4镜像,运行 Laravel/Swoole 应用与 Supervisor 进程;dootask-nginx-${APP_ID}:nginx:alpine,映射${APP_PORT}:80与${APP_SSL_PORT:-0}:443;dootask-redis-${APP_ID}:缓存/队列/会话后端;dootask-mariadb-${APP_ID}:mariadb:10.7.3,数据目录挂载./docker/mysql/data;dootask-appstore-${APP_ID}:应用市场容器,需要访问 Docker socket。
网络 dootask-networks-${APP_ID} 与数据卷 dootask-shared-data-${APP_ID}、dootask-redis-data-${APP_ID} 也按 APP_ID 隔离,这正是 APP_ID 冲突检测存在的意义——保证多实例互不干扰。
五、安装成功后:访问地址与数据库密码重置
安装成功后脚本会输出访问地址:
地址: http://127.0.0.1:<APP_PORT>
并自动调用 container_exec mariadb "sh /etc/mysql/repassword.sh"(脚本末尾,见 cmd)。该脚本以卷挂载方式存在于 MariaDB 容器内(docker-compose.yml),源码见 docker/mysql/repassword.sh。
repassword.sh 支持三种用法:
./repassword.sh # 重置第一个管理员用户密码(随机生成 16 位)
./repassword.sh 123 # 重置 ID=123 的用户密码(随机生成)
./repassword.sh user@example.com # 重置指定邮箱用户的密码(随机生成)
./repassword.sh 123 newpass # 重置 ID=123 的用户密码为 "newpass"
./repassword.sh user@example.com newpass # 重置指定邮箱用户的密码为 "newpass"
其实现要点:纯数字参数按 userid 查询,其余按 email 查询;默认查询 identity LIKE '%,admin,%' 的第一个管理员;密码采用 md5(md5(明文) + 随机加密盐) 的双重哈希写入 users 表的 encrypt/password 字段。因此向用户报告时应包含两样信息:访问地址(http://127.0.0.1:<APP_PORT>)与数据库密码提示(管理员账号密码以脚本输出为准)。
六、失败处理:立即停止,原样报告
任何步骤失败立即停止,原样报告错误信息。不要自动重试,不要自动跳过。
常见失败与对应处理:
| 失败现象 | 处理方式 |
|---|---|
APP_ID(xxx)已被其他实例使用 |
停止,让用户清空 .env 的 APP_ID/APP_IPPR 再装 |
端口 xxx 已被占用 |
停止,让用户换 --port |
目录【xxx】权限不足 / 目录权限检测失败 |
这是目录属主/权限问题,引导用户统一修复权限后重装,不要自行随意 chmod/chown |
安装依赖失败(composer) |
报告,交用户决定(常因网络/镜像源) |
这些报错信息都能在 cmd 的多语言文案表中找到对应原文(例如"APP_ID(())已被其他实例使用:()"、"端口 () 已被占用,请指定其他端口"、"目录【()】权限不足!"),方便逐字比对定位。
七、禁止项与操作纪律(Red Flags)
禁止项速查
| 错误做法 | 正确做法 |
|---|---|
不加 sudo 直接 ./cmd install |
用 sudo ./cmd install(脚本强制 root) |
| 失败后"我再试一次"或自动跳过 | 立即停止,交还用户 |
| 在已有数据环境上不问就重装 | 先确认会 migrate --seed,可能影响现有数据 |
遇权限报错自己乱 chmod/chown |
走权限修复流程统一处理 |
不问就加 --relock |
默认不加;仅用户明确要求或锁损坏时用 |
Red Flags:出现这些念头立即停下
- "端口/权限报错了我顺手帮 TA 改一下别的" → 停下,只处理本次报的问题,按指引走对应处理流程;
- "种子数据应该没事,直接重装" → 不,先确认是否会覆盖现有数据;
- "sudo 麻烦,先试试不加" → 不,install 必须 root。
这条纪律的本质来自脚本实现:check_sudo 在 handle_install 的第一步就会强制退出非 root 执行(cmd),migrate --seed 又是数据库写操作(cmd 附近),所以"违反字面规则 = 违反流程精神",安装过程中的每一步确认都不应被省略。
八、延伸:环境变量与安装的隐含初始化
虽然 ./cmd install 不需要手工编辑配置,但了解 .env 的初始化逻辑有助于排查问题。脚本中的 env_init()(见 cmd)在安装时会:
- 若不存在
.env,则从.env.docker复制生成; DB_ROOT_PASSWORD为空时随机生成 16 位;APP_ID为空时随机生成 6 位;APP_IPPR为空时生成10.x.y形式的内部网段。
.env.docker 中的核心默认值(见 .env.docker):
| 变量 | 默认值 | 说明 |
|---|---|---|
APP_NAME |
DooTask |
应用名 |
APP_PORT |
2222 |
HTTP 访问端口 |
APP_ID / APP_IPPR |
空(安装时随机生成) | 实例唯一标识与内网段,多实例隔离的关键 |
DB_DATABASE / DB_USERNAME / DB_PASSWORD |
dootask / dootask / 123456 |
业务库账号(root 密码另行随机生成) |
DB_PREFIX |
pre_ |
表前缀,repassword.sh 的查询也依赖它 |
LARAVELS_LISTEN_PORT |
20000 |
Swoole 内部监听端口,供 nginx 反向代理与健康检查使用 |
安装完成后,如需修改端口、访问地址或环境变量,可分别使用 ./cmd port <端口>、./cmd url <地址>、./cmd env <键> <值>;日常维护还有 ./cmd update、./cmd mysql backup、./cmd artisan 等命令(见 cmd 的帮助信息),但注意它们同样遵循"确认后执行、失败即停"的操作纪律。
结语
DooTask 的安装之所以能保持稳定可复现,关键在于"单命令封装 + 刚性前置把关"的设计:脚本把易错的重操作(建库、迁移、灌种子数据)收敛进 ./cmd install,而操作者只需守住前置检查、参数选择、单次确认、失败即停四条纪律。理解了 cmd 中 check_sudo、check_docker、check_node、check_instance、check_port、handle_install 等函数的实现,你就能在任何一次安装异常时快速定位问题属于环境、参数还是权限,并按照处理矩阵安全地推进到部署成功。