事情起因
Redmine 作为一款项目管理软件,曾经很是流行,现如今风光不在,不过依然在某些场景下受到欢迎。
常见的 Redmine 使用方式为:Redmine + markdown + svn/git ,这种组合可以满足项目进度管理、代码管理、文档管理的需求。
在使用过程中,最为头疼的莫过于 markdown 的集成,官方给出的插件太过陈旧,而第三方插件,或多或少都会引起 redmine 访问不稳定,还会导致CPU跑满,机器宕掉,这一度让小伙伴的情绪处于失控的边缘,于是乎,就下决心动动这个老古董。
经过调研发现,redmine 3.x 版本内置了 markdown 插件,于是乎,把老版本的数据迁移到新版本似乎是个不错的选择。
这里有两个选择:
(1)可以在原 redmine 2.6 的基础上进行升级,不过之前安装的过程中,ruby 的版本已经有点混乱,做起来会比较麻烦,再者官方没有提供无缝升级文档,还有一个是 3.0 的数据库不兼容 2.6;
(2)当然也可以重新搭建一个新的 redmine 3.0,这样会更干净一些,后续的维护包袱也会小一些,所以下面就以此方法为准。
环境(迁移前)
系统:CentOS 6.6 x64
软件:Bitnami-Redmine 2.6
目录:/opt/redmine
服务器:11.11.11.11
环境(迁移后)
系统:CentOS 7.0 x64
软件:Bitnami-Redmine 3.0
目录:/opt/redmine
服务器:22.22.22.22
数据库备份(旧服务器)
这里有一个小插曲,之前安装的小伙伴说,没有留意安装过程中有让填写 mysql 密码,所以,有必要手动恢复一下 root 密码。
操作如下:
(1)停止 redmine
cd /opt/redmine
./ctlscript.sh stop
(2)使用安全模式启动 msyql,跳过权限认证(此处的操作可能会使数据库处于危险之中,所以操作之前一定在停掉mysql)
./mysql/bin/mysqld_safe --skip-grant-tables &
./mysql/bin/mysql -uroot
(3)恢复 mysql root 的密码为 123456
update mysql.user set password=PASSWORD('123456') where User='root';
flush privileges;
quit
(4)查找 mysql 进程,并且关闭
ps -ef|grep mysql
找到进程PID后,可以使用 kill -9 pid 命令来关掉进程
(5)启动 redmine
./ctlscript.sh start
(6)备份数据库到 当前目录的 bitnami_redmine.sql 文件
./mysql/bin/mysqldump -uroot -p'123456' bitnami_redmine > bitnami_redmine.sql
(7)使用文本工具编辑 bitnami_redmine.sql 文件,使用新的服务器 22.22.22.22 替换 旧的 11.11.11.11
数据库恢复(新服务器)
(8)安装 bitnami-redmine
安装不作为此文章的重点,所以,就选择性跳过了,后续我会再补一篇《Bitnami-Redmine 快速部署》文章。
此处只给出 bitnami-redmine 的下载地址 goto,下载之后,对照 README 文档操作就可以了,几乎是一键式安装,比较轻松。
(9)启动 bitnami-redmine
cd /opt/redmine
./ctlscript.sh start
(10)备份数据库
./mysql/bin/mysqldump -uroot -p'123456' bitnami_redmine > bitnami_redmine_bak.sql
(11)使用 mysql 命令清理 bitnami_redmine 数据库
./mysql/bin/mysql -uroot -p'123456'
DROP DATABASE bitnami_redmine;
CREATE DATABASE bitnami_redmine;
quit
(12)上传 bitnami_redmine.sql 到 /opt/redmine ,并恢复旧数据库
./mysql/bin/mysql -uroot -p'123456' bitnami_redmine < bitnami_redmine.sql
(13)接下来的基本上是体力活了
因为上面提到 redmine 从 2.6 升级到 3.0 数据库结构发生的改变,所以涉及到的数据表,需要手动修复
主要修改如下:
用户表 users
修改内容:删除了 email 字段,拆分为单独的邮件地址表 email_addresses
修复方法:users 表的插入语句,手动删除 email 字段即可;
至于新增的 email_addresses 表,懒一点的办法就是所有操作完成后,手动在管理后台中给每个用户添加邮件,每个用户60秒足够了(注意此处添加邮件会修改掉用户的密码,设置一个统一的,强制用户登录修改吧)
问题状态表 issue_statuses
修改内容:删除中 is_default 字段
修复方法:issue_statuses 表的插入语句,手动删除 is_default 字段即可;
角色表 roles
修改内容:添加了 users_visibility 字段
修复方法:roles 表的插入语句中,每个 VALLUES 的末字段添加一个 ‘all’ 即可
跟踪表 tracker
修改内容:添加了 default_status_id 字段
修复方法:tracker 表的插入语句中,每个 VALUES 的末字段添加一个 1 即可
WIKI表 wiki
修改内容:wiki_redirects 中,添加了 redirects_to_wiki_id 字段
修复方法:此处的旧项目中,并未用到此表,所以操作无从谈起
为了方便操作,可以将数据库修复操作,放在一个文件 bitnami_redmine_upgrade_26_to_30.sql 中,使用mysql命令行统一执行
【特别注意】如下代码中,出现了 … 字符,这里代表中,需要替换为你的旧数据库中的真实数据,如果没有数据,可以直接删除所在 INSERT 行
【此处有坑】保存此文件时,一定要注意,文档格式为UTF-8,否则在下面的导入中,会一直报错,在管理后台的表现就是,缺少数据
USE bitnami_redmine;
DROP TABLE IF EXISTS `email_addresses`;
CREATE TABLE `email_addresses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`address` varchar(255) NOT NULL,
`is_default` tinyint(1) NOT NULL DEFAULT '0',
`notify` tinyint(1) NOT NULL DEFAULT '1',
`created_on` datetime NOT NULL,
`updated_on` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `index_email_addresses_on_user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `issue_statuses`;
CREATE TABLE `issue_statuses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL DEFAULT '',
`is_closed` tinyint(1) NOT NULL DEFAULT '0',
`position` int(11) DEFAULT '1',
`default_done_ratio` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_issue_statuses_on_position` (`position`),
KEY `index_issue_statuses_on_is_closed` (`is_closed`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
LOCK TABLES `issue_statuses` WRITE;
INSERT INTO `issue_statuses` VALUES ...;
UNLOCK TABLES;
DROP TABLE IF EXISTS `roles`;
CREATE TABLE `roles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL DEFAULT '',
`position` int(11) DEFAULT '1',
`assignable` tinyint(1) DEFAULT '1',
`builtin` int(11) NOT NULL DEFAULT '0',
`permissions` text,
`issues_visibility` varchar(30) NOT NULL DEFAULT 'default',
`users_visibility` varchar(30) NOT NULL DEFAULT 'all',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
LOCK TABLES `roles` WRITE;
INSERT INTO `roles` VALUES ...;
UNLOCK TABLES;
DROP TABLE IF EXISTS `trackers`;
CREATE TABLE `trackers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL DEFAULT '',
`is_in_chlog` tinyint(1) NOT NULL DEFAULT '0',
`position` int(11) DEFAULT '1',
`is_in_roadmap` tinyint(1) NOT NULL DEFAULT '1',
`fields_bits` int(11) DEFAULT '0',
`default_status_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
LOCK TABLES `trackers` WRITE;
INSERT INTO `trackers` VALUES ...;
UNLOCK TABLES;
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`login` varchar(255) NOT NULL DEFAULT '',
`hashed_password` varchar(40) NOT NULL DEFAULT '',
`firstname` varchar(30) NOT NULL DEFAULT '',
`lastname` varchar(255) NOT NULL DEFAULT '',
`admin` tinyint(1) NOT NULL DEFAULT '0',
`status` int(11) NOT NULL DEFAULT '1',
`last_login_on` datetime DEFAULT NULL,
`language` varchar(5) DEFAULT '',
`auth_source_id` int(11) DEFAULT NULL,
`created_on` datetime DEFAULT NULL,
`updated_on` datetime DEFAULT NULL,
`type` varchar(255) DEFAULT NULL,
`identity_url` varchar(255) DEFAULT NULL,
`mail_notification` varchar(255) NOT NULL DEFAULT '',
`salt` varchar(64) DEFAULT NULL,
`must_change_passwd` tinyint(1) NOT NULL DEFAULT '0',
`passwd_changed_on` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_users_on_id_and_type` (`id`,`type`),
KEY `index_users_on_auth_source_id` (`auth_source_id`),
KEY `index_users_on_type` (`type`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
LOCK TABLES `users` WRITE;
INSERT INTO `users` VALUES ...;
UNLOCK TABLES;
DROP TABLE IF EXISTS `wiki_redirects`;
CREATE TABLE `wiki_redirects` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`wiki_id` int(11) NOT NULL,
`title` varchar(255) DEFAULT NULL,
`redirects_to` varchar(255) DEFAULT NULL,
`created_on` datetime NOT NULL,
`redirects_to_wiki_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `wiki_redirects_wiki_id_title` (`wiki_id`,`title`),
KEY `index_wiki_redirects_on_wiki_id` (`wiki_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
USE bitnami_redmine;
DROP TABLE IF EXISTS `email_addresses`;
CREATE TABLE `email_addresses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`address` varchar(255) NOT NULL,
`is_default` tinyint(1) NOT NULL DEFAULT '0',
`notify` tinyint(1) NOT NULL DEFAULT '1',
`created_on` datetime NOT NULL,
`updated_on` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `index_email_addresses_on_user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `issue_statuses`;
CREATE TABLE `issue_statuses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL DEFAULT '',
`is_closed` tinyint(1) NOT NULL DEFAULT '0',
`position` int(11) DEFAULT '1',
`default_done_ratio` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_issue_statuses_on_position` (`position`),
KEY `index_issue_statuses_on_is_closed` (`is_closed`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
LOCK TABLES `issue_statuses` WRITE;
INSERT INTO `issue_statuses` VALUES ...;
UNLOCK TABLES;
DROP TABLE IF EXISTS `roles`;
CREATE TABLE `roles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL DEFAULT '',
`position` int(11) DEFAULT '1',
`assignable` tinyint(1) DEFAULT '1',
`builtin` int(11) NOT NULL DEFAULT '0',
`permissions` text,
`issues_visibility` varchar(30) NOT NULL DEFAULT 'default',
`users_visibility` varchar(30) NOT NULL DEFAULT 'all',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
LOCK TABLES `roles` WRITE;
INSERT INTO `roles` VALUES ...;
UNLOCK TABLES;
DROP TABLE IF EXISTS `trackers`;
CREATE TABLE `trackers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL DEFAULT '',
`is_in_chlog` tinyint(1) NOT NULL DEFAULT '0',
`position` int(11) DEFAULT '1',
`is_in_roadmap` tinyint(1) NOT NULL DEFAULT '1',
`fields_bits` int(11) DEFAULT '0',
`default_status_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
LOCK TABLES `trackers` WRITE;
INSERT INTO `trackers` VALUES ...;
UNLOCK TABLES;
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`login` varchar(255) NOT NULL DEFAULT '',
`hashed_password` varchar(40) NOT NULL DEFAULT '',
`firstname` varchar(30) NOT NULL DEFAULT '',
`lastname` varchar(255) NOT NULL DEFAULT '',
`admin` tinyint(1) NOT NULL DEFAULT '0',
`status` int(11) NOT NULL DEFAULT '1',
`last_login_on` datetime DEFAULT NULL,
`language` varchar(5) DEFAULT '',
`auth_source_id` int(11) DEFAULT NULL,
`created_on` datetime DEFAULT NULL,
`updated_on` datetime DEFAULT NULL,
`type` varchar(255) DEFAULT NULL,
`identity_url` varchar(255) DEFAULT NULL,
`mail_notification` varchar(255) NOT NULL DEFAULT '',
`salt` varchar(64) DEFAULT NULL,
`must_change_passwd` tinyint(1) NOT NULL DEFAULT '0',
`passwd_changed_on` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_users_on_id_and_type` (`id`,`type`),
KEY `index_users_on_auth_source_id` (`auth_source_id`),
KEY `index_users_on_type` (`type`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
LOCK TABLES `users` WRITE;
INSERT INTO `users` VALUES ...;
UNLOCK TABLES;
DROP TABLE IF EXISTS `wiki_redirects`;
CREATE TABLE `wiki_redirects` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`wiki_id` int(11) NOT NULL,
`title` varchar(255) DEFAULT NULL,
`redirects_to` varchar(255) DEFAULT NULL,
`created_on` datetime NOT NULL,
`redirects_to_wiki_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `wiki_redirects_wiki_id_title` (`wiki_id`,`title`),
KEY `index_wiki_redirects_on_wiki_id` (`wiki_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
上传此文件到 /opt/redmine ,并执行更新操作
./mysql/bin/mysql -uroot -p'123456' < bitnami_redmine_upgrade_26_to_30.sql
(14)至此,所有数据库操作已经完成,下面开始文件附件操作
文件附件迁移(旧服务器)
(15)将 /apps/redmine/htdocs/files 下的所有文件打包,并拷贝至新服务器相同目录即可。
插件迁移(旧服务器)
(16)将 /apps/redmine/htdocs/plugins 下的所有文件打包,,并拷贝至新服务器相同目录即可。
(17)至此,迁移工作完成,浏览器中访问新版 redmine ,确认功能是否正常。
大功告成
参考资料
Bitnami Redmine Install goto
Redmine 数据迁移记录 goto
Redmine README.txt Redmine安装目录