直接说结论:禅道这种“PHP+MySQL+ Apache”全家桶式的老牌项目管理工具,用 Docker 来装,是我目前觉得最省心的方式,没有之一。尤其当你手头就是一台 Windows 工作机、一台 CentOS 服务器,或者想给团队快速搭一套内部管理系统时,Docker 方案能把两三个小时的部署时间压缩到十分钟以内,而且后续升级、迁移、备份都变得异常清晰。
如果你已经决定用 Docker 安装禅道,那这篇文章就是给你准备的。我默认你对 Docker 只有最基础的概念,甚至没装过也行。下面我会从环境准备、镜像选择、容器启动、数据持久化,到首次访问配置、升级备份和常见故障排查,把整条链路完整过一遍。中间会穿插很多我踩过的坑,比如 Docker Desktop 启动时提示虚拟化没开、容器起来之后打不开页面、升级时把数据搞丢这类问题,都会给出对应的解决方法。
1. 为什么我坚持用容器跑禅道,而不是直接装源码包
先聊一个很多人会问的问题:禅道官网上明明提供了 Windows 一键安装包、Linux 源码包,还有集成环境,为什么我还要用 Docker 再包一层?
我在早期部署禅道的时候,确实也用过一键安装包。它的原理是把 Apache、PHP、MySQL 全部打到一个压缩包里,解压之后启动两个服务就能用。听起来很省事,但实际用起来有几个很麻烦的点:
第一,环境隔离很差。一键安装包的 Apache 默认会用 80 端口,MySQL 默认会用 3306 端口。如果机器上已经跑了 Nginx、MySQL、Redis,端口冲突会让你调到头大。你想改配置,还得去翻 zbox 目录下的各种配置文件,路径不熟的人很容易改坏。
第二,迁移困难。假如你要从一台旧服务器迁到新服务器,要么重新装一个同样版本的一键包,要么手动把禅道源码和 MySQL 数据目录一起拷过去。中间只要版本不一致,数据库结构和 PHP 扩展对不上,站点起来之后各种白屏、报错。
第三,环境不一致导致的问题很隐蔽。比如同样一套源码,在 Windows 上和 Linux 上跑,文件权限、PHP 扩展、数据库字符集都可能不一样。有时候本地明明好好的,到服务器上就是登录不了,或者中文乱码。这种问题排查起来非常费劲,因为问题不一定出在禅道本身,而是出在环境里。
Docker 方案把这些问题一次解决。镜像里面已经把 Apache、PHP、MySQL 和禅道源码全部封装好了,你在哪台机器上拉起来,运行环境都是一模一样的。端口可以随意映射,数据目录可以挂载到宿主机,容器删了重建也只是瞬间的事。再加上 Docker 镜像本身就是分层结构,升级时拉一个新版本镜像重建容器,比手工覆盖源码要可靠很多。
这就像以前你为了吃一道菜,得自己从种菜、杀鸡、生火开始;现在人家把整道菜连同锅碗瓢盆打包成一个“菜单”,你只需要在任意厨房里把这个“菜单”跑起来,就能端出同一道菜。Docker 镜像就是那个“菜单”。
所以我的建议是:只要你的机器能装 Docker,就直接用 Docker 部署禅道。它可能是目前平衡“省事”和“可控”最好的方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 先把Docker环境备好:Windows、macOS、Linux的真实差别
既然是“用 Docker 安装禅道”,那 Docker 本身得先跑起来。不同系统下的安装方式差别挺大,我分开说。
2.1 Windows 用户:重点解决 Docker Desktop 启动报错
Windows 上目前最主流的方式是装 Docker Desktop。这个工具本身不复杂,但有一个非常经典的报错,几乎每天都有新手遇到:
Docker Desktop failed to start because virtualization support wasn't detected
翻译过来就是:没检测到虚拟化支持。这个问题有 90% 的可能是以下两个原因之一:
第一,BIOS/UEFI 里没有开启虚拟化。你需要重启电脑进 BIOS,找到 Intel Virtualization Technology(Intel 平台)或 SVM Mode(AMD 平台),把它设为 Enabled。保存重启后再试。
第二,你的 Windows 版本没有启用 WSL2 或 Hyper-V。Docker Desktop 在 Windows 上运行,底层依赖 WSL2 或者 Hyper-V 虚拟化组件。你可以用管理员权限打开 PowerShell,运行:
powershell复制wsl --status
如果显示 WSL 未安装,或者版本是 WSL1,就需要先安装 WSL2。最简单的方式是在管理员 PowerShell 里执行:
powershell复制wsl --install
装完重启电脑,再打开 Docker Desktop 通常就正常了。还有一个小细节,Docker Desktop 如果要基于 WSL2 运行,需要在 Settings -> General 里勾选 Use the WSL 2 based engine。
我踩过的另一个坑是:Windows 10 版本过低,Docker Desktop 直接提示“we've detected that you have an incompatible version of Windows”。这个问题没有什么优雅的解法,要么升级 Windows 10/11 到较新的大版本,要么换用 Docker Toolbox(但我不建议,太老了)。如果你装的是 Windows 10,尽量保持在 21H2 以上;Windows 11 基本没有这个限制。
2.2 macOS 用户:装 Docker Desktop 最省心
macOS 上装 Docker Desktop 基本没有什么坑,直接从官网下载 dmg 文件拖拽安装就行。如果你是 Apple Silicon 芯片(M1/M2/M3),下载时记得选对应芯片的版本,不然性能会打折。
启动之后建议把 Resources 里的内存调大一点。禅道镜像自带的 MySQL 启动比较吃内存,默认 2GB 可能够用,但如果你同时跑很多容器,建议给 Docker 分配 4GB 以上。
2.3 Linux 用户:直接装 docker-ce 或 docker.io
Linux 下我建议直接用发行版提供的 Docker 包,除非你有特殊需求。以 CentOS 7 为例,常见操作是:
bash复制sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
sudo systemctl enable docker
如果是 Ubuntu/Debian,也可以直接:
bash复制sudo apt update
sudo apt install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker
注意 Linux 下 Docker 服务启动失败的话,大概率是配置有问题,可以用 sudo journalctl -u docker --no-pager | tail -50 看日志,常见原因包括存储驱动不匹配、内核版本太旧、iptables 配置冲突等。
2.4 镜像下载慢:配置镜像加速器
安装完 Docker 后,第一件事我建议配置镜像加速。禅道官方镜像有些比较大,如果不加速,下载速度可能让人崩溃。在国内云服务器上,常见的做法是在 /etc/docker/daemon.json 里写入:
json复制{
"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"]
}
如果是 Windows/Mac 的 Docker Desktop,在 Settings -> Docker Engine 里,把上面的 JSON 内容合并进去然后重启即可。加速器不一定永远稳定,如果某个地址不通,就换一个再试。加速不是必须的,但配上之后体感会好很多。
验证 Docker 是否装好,一个指令就够了:
bash复制docker version
能同时看到 Client 和 Server 的信息,就说明环境已经是可用的状态。
3. 拉镜像和起容器:一条命令里藏着的关键细节
很多人第一次搜“docker 安装禅道”,会看到各种五花八门的老教程,镜像名都不一样。这里先澄清一下镜像怎么选。
3.1 镜像名与 tag 的选择
禅道官方推荐的 Docker 镜像,较早时期的名称是 easysoft/zentao,后来逐步迁移到了 hub.zentao.net/app/zentao。如果你直接 docker pull easysoft/zentao:latest,新版本可能拉不到了,或者拉到的版本很老。
我的建议是:以禅道官网最新文档为准。一般情况下,你可以用类似这样的命令拉取:
bash复制docker pull easysoft/zentao:latest
如果拉取失败,再去禅道官网或开源中国镜像页查一下当前使用的镜像标识。另外需要注意,latest 不是一直不变的概念,如果你要正式使用,最好拉取一个明确的版本号,比如 12.6.3、15.5 这种,方便后面做版本管理。
这里贴一个早期我部署时用过的稳定组合,仅供参考(具体以官网最新文档为准):
| 组件 | 说明 |
|---|---|
| 镜像 | easysoft/zentao / hub.zentao.net/app/zentao |
| 内置服务 | Apache + PHP + MySQL |
| 默认端口 | 容器内 80(HTTP)、3306(MySQL) |
| 数据目录 | /www/zentaopms 或 /opt/zbox 等,取决于镜像版本 |
3.2 完整的 docker run 命令
下面是我实际部署时用的命令模板(以老版镜像为例):
bash复制docker run -d \
--name zentao-server \
-p 8080:80 \
-p 3307:3306 \
-e USER="root" \
-e PASSWD="123456" \
-v /opt/zentao/zentaopms:/www/zentaopms \
-v /opt/zentao/mysql:/var/lib/mysql \
easysoft/zentao:latest
逐项解释一下这些参数都是干什么的,因为很多人就是盲目照抄,出了问题不知道从哪里调。
-d:后台运行容器。--name:给容器起名,方便后面docker exec -it zentao-server bash进入容器。-p 8080:80:把宿主机 8080 端口映射到容器内 80 端口。这样你访问 http://服务器IP:8080 就能打开禅道。如果你确定宿主机 80 端口是空闲的,直接用-p 80:80当然更清爽。-p 3307:3306:把宿主机 3307 端口映射到容器内 MySQL 端口。这样你从宿主机连数据库时,用127.0.0.1:3307就能连上容器里的 MySQL,避免和宿主机已有 MySQL 冲突。-e USER/-e PASSWD:设置容器内 MySQL 的 root 账号密码。这个如果不设,默认值要看镜像说明,老版本默认 root 密码是 123456,不同版本可能不同。-v挂载目录:这是最重要的一项,我单独在下一节里细说。
3.3 启动之后如何确认一切正常
容器跑起来之后,先别急着访问页面,按顺序做三个检查:
bash复制docker ps
看容器状态是不是 Up。如果状态是 Exited 或 Restarting,说明容器没起来,需要看日志:
bash复制docker logs zentao-server --tail 100
启动过程中如果日志停在一个位置不动,说明 Apache 或 MySQL 还在初始化,耐心再等几十秒。MySQL 首次初始化数据会花点时间,尤其是容器里如果做了大量数据表导入操作。
最后验证端口是否通了:
bash复制curl -I http://127.0.0.1:8080
返回 HTTP 200,说明 Web 服务已经起来了。
4. 数据落盘和备份,比安装本身重要十倍
我见过一些新手把禅道跑起来之后就再也不管了,直到某一天容器被误删、电脑重启之后数据全没,才意识到问题的严重性。这里我要非常认真地说:Docker 容器本身是“一次性”的东西,凡是没有挂载到宿主机上的数据,容器一删就真的没了。
4.1 必须挂载的目录有哪些
不同版本的禅道镜像,目录结构略有差别。老版本的镜像,核心数据主要是两处:
/www/zentaopms:禅道程序源码、附件等。/var/lib/mysql:MySQL 数据库文件。
新版本镜像可能对应 /opt/zbox 之类的路径,或者把源码和数据库统一放在某个目录下。所以实操之前,请务必看一下你拉取的镜像的官方说明,确认要挂载哪些路径。
我个人的习惯是,把挂载目录统一放在宿主机一个独立路径下,比如 /opt/zentao,里面再分子目录:
bash复制mkdir -p /opt/zentao/zentaopms
mkdir -p /opt/zentao/mysql
这样宿主机上所有禅道数据都在一个目录里,备份的时候直接打包这个目录就行。
4.2 为什么必须用 -v 挂载,而不是拷贝出文件
有些教程教你“数据备份就是用 docker cp 把容器里的文件拷出来”。这个做法能应急,但不适合日常使用。因为容器每次重建,路径和状态都会变,手动 docker cp 很容易漏掉某些文件。
正确做法是:在启动容器的时候就通过 -v 把数据目录挂载出来。容器内写数据,实时落到宿主机目录,也就是真正的持久化。以后不管容器怎么删、怎么换镜像,数据都在宿主机目录里躺着,心里踏实。
4.3 备份与恢复的常用姿势
备份我一般用两种方式结合。
第一种,文件级备份。直接打包整个禅道数据目录:
bash复制tar -czvf zentao_backup_$(date +%Y%m%d).tar.gz /opt/zentao
恢复的时候,解压回原路径,再重新跑一个同样的 docker run 命令挂载这个目录即可。
第二种,数据库级备份。进入容器,通过 mysqldump 导出数据库:
bash复制docker exec zentao-server mysqldump -uroot -p123456 zentao > zentao_db.sql
这里的库名可能叫 zentao,也可能叫 zentao_15.x,你用 docker exec zentao-server mysql -uroot -p123456 -e "show databases;" 看一下就知道。数据库级备份适合日常定时备份,脚本里可以这样写:
bash复制docker exec zentao-server mysqldump --default-character-set=utf8 -uroot -p123456 zentao > /opt/zentao/backup/zentao_$(date +%Y%m%d_%H%M%S).sql
恢复数据库文件时,先进入 MySQL:
bash复制docker exec -it zentao-server mysql -uroot -p123456
然后执行:
sql复制CREATE DATABASE zentao DEFAULT CHARACTER SET utf8;
USE zentao;
SOURCE /path/to/zentao_db.sql;
注意 MySQL 的字符集要和原库一致,否则中文数据容易乱码。禅道对字符集比较敏感,这个坑我踩过,后来一律在导入前先确认 SHOW VARIABLES LIKE 'character_set_database';。
4.4 用 docker-compose 管理更省心
如果你要长期使用,我建议直接写一个 docker-compose.yml,把端口、环境变量、卷都固化下来。下面是一个参考示例:
yaml复制version: "3"
services:
zentao:
image: easysoft/zentao:latest
container_name: zentao-server
ports:
- "8080:80"
- "3307:3306"
environment:
- USER=root
- PASSWD=123456
volumes:
- /opt/zentao/zentaopms:/www/zentaopms
- /opt/zentao/mysql:/var/lib/mysql
restart: unless-stopped
以后启动只需要一个命令:
bash复制docker compose up -d
这样哪怕容器被误删,一条命令就能把整个禅道环境拉起来,数据一点不丢。
5. 首次访问配置:数据库连接、时区与端口冲突排雷
容器起来了,页面也能打开了,但距离系统真正可用,还有最后几步。很多人在这一步卡住,问题主要集中在数据库连接、端口冲突、时区不对这几个方面。
5.1 打开安装向导,填写数据库信息
浏览器访问 http://你的IP:8080,正常会看到禅道的安装向导界面。比较新的版本会让你选择“全新安装”或“升级已有系统”,全新安装直接点进去,然后填写数据库信息。
这里有个关键点:数据库地址怎么填?
如果你用的是容器内置的 MySQL,而且直接在浏览器里操作安装向导,那么数据库地址一般填 127.0.0.1 或 localhost,端口是 3306。注意这是“容器内视角”,不是宿主机视角。因为 PHP 进程跑在容器里,它访问 localhost 指的就是容器自身。
如果你在页面上填的是宿主机 IP 或者映射端口 3307,反而可能连不上,因为容器内访问宿主机的网络路径要绕一圈,而且还要看容器网络模式。所以我个人建议:用内置 MySQL 时,数据库地址就老老实实填 127.0.0.1:3306,账号密码填 docker run 时 -e 设置的那个。
很多人在这一步填错后,页面会提示数据库连接失败。解决办法就是回到上面说的“容器内视角”重新理解:容器内的 3306 是 MySQL 真正的监听端口,宿主机上的 3307 只是为了“从宿主机连接”而映射出来的。
5.2 端口冲突怎么办
如果在 docker run 时发现端口被占用,Docker 会直接报错退出。比如宿主机 80 端口已经被 Nginx 用了,你再用 -p 80:80 就会失败。
解决办法有两个:
第一,换一个宿主机端口。比如 -p 8080:80,访问地址改成 8080。
第二,如果一定要用 80,就先停掉占用的进程。Linux 下可以执行:
bash复制sudo netstat -tlnp | grep :80
sudo systemctl stop nginx
甚至把 Nginx 设置为不随系统启动:
bash复制sudo systemctl disable nginx
Windows 下,经常遇到的坑是 IIS 或“World Wide Web Publishing Service”占用了 80 端口。可以在“服务”里把 World Wide Web Publishing Service 停掉,或者通过 net stop http 查看还有哪些进程在监听。
5.3 时区问题:页面时间比实际时间慢 8 小时
这是一个非常经典的问题。容器默认时区可能是 UTC,而你在东八区,导致禅道里显示的创建时间、操作日志总是比实际时间慢 8 小时。
解决办法是在启动容器时设置时区环境变量:
bash复制-e TZ=Asia/Shanghai
如果你容器已经跑起来了,不想重建,可以进入容器修改时区,比如:
bash复制docker exec -it zentao-server bash
然后看容器内有没有 /usr/share/zoneinfo/Asia/Shanghai,如果有,可以做一个软链接替换 /etc/localtime,并设置 TZ 环境变量。不过最干净的方案还是在 docker run 时直接加 -e TZ=Asia/Shanghai,或者写在 docker-compose.yml 里。
另外,MySQL 的时区也可能影响某些时间字段。确保 MySQL 的 time_zone 设置和系统一致,可以在 MySQL 里执行:
sql复制SET GLOBAL time_zone = '+08:00';
但注意 MySQL 重启后这个设置可能失效,更稳妥的方式是在 MySQL 配置文件里加上 default-time-zone='+08:00'。容器内改配置比较麻烦,所以一般用环境变量方式解决即可。
5.4 安装完成后第一次登录
安装向导走完后,禅道会自动生成管理员账号,通常默认是 admin。不同版本初始化密码可能不一样,老版本是 123456,新版本可能要求你在向导里直接设置。如果你登录时提示密码错误,可以看安装完成页面上的提示,或者在容器日志里找初始密码。
登录进去之后,第一件事建议进入“后台”修改管理员密码,然后创建普通用户并分配权限。禅道的权限体系默认比较细致,建议先读一下官方文档里的角色说明,避免把管理员账号到处传播。
6. 升级、日志和日常维护的实战经验
最后一部分聊聊禅道跑起来之后的长期维护。日常维护最核心的三件事:升级、备份、看日志。
6.1 禅道版本升级的正确姿势
禅道官方经常会有安全更新和功能更新。用 Docker 部署之后,升级流程其实很清晰,但前提是你做好了数据持久化。
整体步骤是:
- 备份当前数据和数据库。
- 拉取新版本的镜像。
- 停掉旧容器。
- 用同样的挂载目录、同样的端口、同样的环境变量,重新跑一个新容器。
- 打开页面,按提示执行数据库升级脚本。
举个例子,假设现在用的是 easysoft/zentao:12.6.3,要升级到 15.5,可以先:
bash复制docker stop zentao-server
docker rm zentao-server
docker pull easysoft/zentao:15.5
然后重新执行 docker run,注意 -v 挂载的目录和之前保持一致。启动后访问页面,禅道如果发现版本不一致,会自动跳转到“升级”页面,照着提示点下一步即可。
这里有几个重要的注意事项:
- 升级前一定要对数据库做一次文件级或 SQL 级备份。因为禅道的升级脚本会执行数据库结构变更,一旦中途失败,如果你没有备份,可能会得到一个不完整的数据库。
- 跨大版本升级(比如从 12 升到 15)一定要先看官方升级路线图。有些大版本不能直接跨版本升,需要逐个版本升。这一步最容易踩坑,我建议去禅道官网查一下对应版本的升级指引,不要盲目拉 latest。
- 升级后如果出现白屏或 500 错误,优先看容器日志,确认是 PHP 扩展缺失、数据库连接失败还是文件权限问题。容器镜像自带的环境应该是一致的,所以这类问题相对少见。
6.2 日常日志和容器状态检查
说实话,禅道容器跑稳定之后,日常其实没什么事可做。但有一点我建议养成习惯:周期性检查一下容器状态和磁盘空间。
看容器状态:
bash复制docker ps -a | grep zentao
docker logs zentao-server --tail 50
如果容器显示 Restarting,大概率是容器内 MySQL 启动失败。常见原因有磁盘满了、数据目录权限不对、内存不足。用 df -h 看磁盘,用 free -h 看内存,再对照日志基本能定位。
磁盘空间是很多禅道实例的隐藏雷区。附件上传、日志文件、MySQL binlog 都会慢慢吃磁盘。建议定期清理不需要的 binlog,或者在 MySQL 配置里限制 binlog 保留时间,避免数据目录无限膨胀。
6.3 容器内常用操作
有时候你想修改禅道配置,或者手动执行一些 SQL,可以进入容器:
bash复制docker exec -it zentao-server bash
进入之后,常见的查看命令:
bash复制# 查看 PHP 进程
ps aux | grep php
# 查看 MySQL 服务状态
mysqladmin -uroot -p123456 status
# 查看禅道版本
cat /www/zentaopms/VERSION
想退出容器直接输入 exit 即可。
这里再提一个很多人容易忽略的问题:容器里改的文件,如果目录没有挂载到宿主机,容器重建后修改会丢失。所以如果你在容器里改了配置文件,最好也同步到挂载目录中,或者直接把配置文件放到挂载目录里做软链接。否则下次重建容器,你改的东西就没了。
6.4 最后分享一个我自己的维护习惯
在我实际维护过的禅道环境里,最让我省心的做法不是备份脚本写得有多花哨,而是严格遵守了“容器不存任何数据”的原则。所有需要保留的东西,包括附件、数据库、配置文件,全部放到宿主机挂载目录里。这样容器对我来说就像一个随时可以丢弃和重建的“进程”,而不是一台需要小心翼翼对待的虚拟机。
具体到备份节奏,我一般每周做一次文件级全量备份,每天做一次数据库 SQL 导出备份。备份文件保留最近 30 天,超出就自动删除。这个脚本用 crontab 就能实现,逻辑很简单,但关键时刻真的能救命。
如果你也是第一次用 Docker 部署禅道,建议先把这套流程完整走一遍,再正式往里面录入数据。等容器删了重建过一轮之后,你就会发现,所谓“Docker 部署禅道”,真正难的根本不是安装,而是理解数据在哪里、环境如何隔离、备份如何落地。这几件事想通了,后面就顺了。
