1. 为什么必须迁:CentOS 7 停服之后的现实压力与迁移思路
1.1 憋了快一年,为什么这次非迁不可
CentOS 7 停止维护这件事,大家心里都有数,但真正被逼到必须动手,往往是某次安全扫描报告里冒出来十几个 CVE,或者等保测评要求整改。堡垒机不像普通业务系统,它管着所有服务器的登录入口,一旦系统本身存在未修复漏洞,攻击者拿下堡垒机就等于拿下了整个机房的钥匙。
我在这次迁移前也纠结过一阵子:Jumpserver 跑得好好的,用户、资产、授权策略几千条,贸然迁出问题怎么办?但后来想通了,CentOS 7 的镜像源已经全面进入 vault 归档阶段,yum 装个基础包都要绕来绕去,更别说安全补丁了。堡垒机这种核心安全设施,长期跑在一个已被上游放弃的操作系统上,本身就是最大的风险。所以接到“CentOS 7 全量替换”的指令后,我第一反应就是:Jumpserver 必须作为第一批迁走的核心系统——先迁最要命的,再铺开其他业务。
这次迁移,我的目标系统选的是 Rocky Linux 9。原因很直接:Rocky Linux 是 RHEL 9 的二进制兼容发行版,运维习惯和 CentOS 几乎一致,systemd 管理服务、firewalld 配置防火墙、dnf 装包,这些操作可以无缝平移。对于想把 CentOS 7 尽快替换掉的团队来说,Rocky Linux 9 的学习成本最低,社区活跃,企业用起来也放心。
1.2 Jumpserver 组件拆解:迁移前先把架构看透
迁移 Jumpserver 前,一定要先把它的组件结构摸清楚。Jumpserver 不是一个单进程程序,而是由多个子服务协作组成:
- core:核心 API 服务,负责认证、授权、资产管理、审计等主逻辑。
- koko:SSH 协议的字符型连接代理,用户通过 Web 终端连 Linux 服务器,走的就是它。
- lion:RDP/VNC 协议的图形连接代理,连 Windows 服务器用的。
- magnus:数据库代理,支持通过堡垒机连接 MySQL、Oracle 等数据库。
- lina / luna:前端静态资源服务,负责渲染 Web 界面。
- celery:后台任务队列,处理会话录像清理、邮件通知、定期任务等。
- redis:缓存和任务队列的载体,保存临时会话状态。
- mysql / postgresql:核心业务库,用户、资产、权限、审计记录的最终存储。
理解了这套架构,迁移时就知道要搬哪些东西了。不是把整个目录拷过去就能跑,而是要确保新环境里每个组件版本匹配、数据库数据完整、密钥文件一致。很多人在迁移后遇到“用户登录不上”、“会话录像看不了”之类的怪问题,十有八九是只迁了数据库,没管密钥和持久化目录。
1.3 迁移方案的选型:同版本复刻,还是借机升级
迁移方案上,我见过两条路线。
第一条是在 Rocky Linux 9 上直接部署一套和旧环境同版本(或同大版本)的 Jumpserver,然后把数据导入。好处是风险最小、验证路径最短,适合把堡垒机当“生产基础设施”、追求稳定压倒一切的团队。
第二条是借迁移机会把 Jumpserver 跨版本升级。比如 CentOS 7 上跑的 v2.x,直接趁迁移升到 v3.x 甚至 v4.x。好处是能少折腾一次,坏处是同时叠加了“操作系统版本变化”和“Jumpserver 大版本变化”两个变量,出问题时很难定位是系统问题还是应用问题。
我的建议是:如果旧堡垒机当前版本还处于官方支持周期内,优先走第一条路线——新系统装同版本,数据迁移验证通过后,再找窗口单独升级版本。如果旧版本实在太老(比如 v2.x),那就先在新环境装好已测试兼容的 v3.x 版本,再把旧数据导进来,尽量一次完成系统切换和版本刷新,但提前做足兼容性测试。
2. 新环境部署:Rocky Linux 9 上的基础组件与 Jumpserver 安装
2.1 系统层面的准备工作,少一步后面都麻烦
Rocky Linux 9 安装时我建议选择 Minimal 版本,减少不必要的软件包,降低攻击面。装完系统后,先做几件基础工作。
第一件事是配置好 dnf 源。CentOS 7 时代习惯了 yum,Rocky Linux 9 默认用 dnf,虽然命令用法几乎一样,但部分参数有差异,比如yum clean all对应dnf clean all,旧脚本里的yum命令在新系统上要替换。
第二件事是关闭 SELinux 或正确配置策略。Jumpserver 官方安装脚本在检测到 SELinux 为 enforcing 模式时,经常会执行某些目录读写操作失败。我不太建议无脑关闭 SELinux,但在隔离的内网环境里,实际运维时关闭它往往是最省事的方案。如果你必须保持 enforcing,那就要单独给 Jumpserver 相关端口和目录打策略标签,这个工作量不小,而且每次升级都可能要重新调整。
# 临时关闭 SELinux setenforce 0 # 永久关闭,编辑 /etc/selinux/config sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config第三件事是安装常用基础工具和时间同步。堡垒机是审计设备,时间不准会导致会话记录时间错乱,直接影响追责审计。所以 chrony 必须配好,而且要让堡垒机同步到公司内部统一的时间源。
dnf install -y vim wget tar lsof net-tools chrony systemctl enable --now chronyd timedatectl set-timezone Asia/Shanghai2.2 数据库与缓存的初始化:字符集和时区最容易踩坑
Jumpserver 元数据可以存在 MySQL 或 PostgreSQL 里。我这次用的是 MySQL 8.0。在 Rocky Linux 9 上安装 MySQL 8.0,直接用官方源即可。
安装完成后,创建库和账号时要特别留意字符集。Jumpserver 在安装阶段会把建表 SQL 执行到数据库里,如果库的默认字符集不是 utf8mb4,后面一旦遇到生僻字、特殊符号,就可能出现乱码或者写入报错。
dnf install -y mysql-server redis systemctl enable --now mysqld redisCREATE DATABASE jumpserver DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; CREATE USER 'jumpserver'@'%' IDENTIFIED BY 'Your_Strong_Password'; GRANT ALL PRIVILEGES ON jumpserver.* TO 'jumpserver'@'%'; FLUSH PRIVILEGES;还要把 MySQL 的时区参数和连接层字符集调整好。
SET GLOBAL time_zone = '+08:00'; SET GLOBAL character_set_server = utf8mb4;Redis 做缓存,一般本地部署就够用。如果 Redis 设置了密码,要在 Jumpserver 配置里对应填好;没设密码的话,至少把 Redis 绑定地址限制为 127.0.0.1,别暴露到外部网络。
2.3 Jumpserver 本体的部署:官方安装器比手工部署靠谱得多
从 v3.x 开始,官方统一推荐使用 jumpserver/installer 仓库的安装器部署。相比手工拉代码、一个个启动组件,这样的方式对依赖关系的处理省心非常多,升级也方便。
拿到安装器后,先解压进入目录,编辑config.txt,把数据库和 Redis 连接信息填成步骤 2.2 里建好的内容:
cd /opt tar xf jumpserver-installer-v3.14.4.tar.gz cd jumpserver-installer-v3.14.4# config.txt 关键配置段 DB_HOST=127.0.0.1 DB_PORT=3306 DB_USER=jumpserver DB_PASSWORD=Your_Strong_Password DB_NAME=jumpserver REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_PASSWORD=然后执行安装脚本:
./jmsctl.sh install安装完成后,用./jmsctl.sh status查看各组件状态,确保 core、koko、lion、magnus 等都处于运行状态。我用官方安装器部署过多次,只要网络正常、磁盘空间够,基本一次能过。常见的问题是“容器无法启动”,多数是数据库连接信息填错,或者 MySQL 版本不兼容。
这里有一个很容易被忽略的点:Jumpserver 新版本的组件大多跑了 Docker 容器里,即使你是用裸机部署方式,Docker 环境也是必需的。安装器会自动处理 Docker 安装,但如果你的网络环境受限、无法访问 Docker Hub,那就要提前准备离线镜像包,否则安装器会在拉镜像时卡住。生产环境尽量用离线包方式把安装器和镜像一次性拷到新机器上,速度比在线拉取快得多,也不容易中断。
2.4 域名入口与 Nginx 反向代理配置
Jumpserver 自带的安装器默认是用 Nginx 容器对外提供 Web 服务,默认监听 80 端口。实际生产环境里,堡垒机一般会通过域名访问,并且启用 HTTPS。网上有不少教程直接让改容器内的 Nginx 配置,但我不建议这么做,升级容器后配置很容易被重置。
更稳的做法是:Jumpserver 容器内继续用默认的 HTTP 80 端口,在宿主机上另装一个 Nginx,做反向代理和 SSL 终止。这样证书轮换、Nginx 调优都独立于 Jumpserver 自身。
server { listen 443 ssl; server_name jump.example.com; ssl_certificate /etc/nginx/ssl/jump.crt; ssl_certificate_key /etc/nginx/ssl/jump.key; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /ws/ { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; } }注意 WebSocket 的location /ws/配置不能丢,Jumpserver 的 Web 终端就是靠 WebSocket 维持实时连接的。如果不转发Upgrade头,用户在 Web 终端里敲命令会时不时断连,这是很多人忽略的“小问题”。
3. 数据备份与迁移执行:把旧堡垒机完整“搬”过去
3.1 迁移前必须备份的东西,一个都不能少
Jumpserver 的数据并不全在数据库里。我列一下这次迁移我实际备份的内容:
- MySQL 业务库全量备份:用户、资产、授权规则、系统配置,这是核心中的核心。
- Redis 持久化数据:保存了部分缓存和会话状态,虽然很多能重建,但最好一并备份。
/opt/jumpserver安装目录(或你的部署路径):安装配置、证书、密钥等全在这里面。- core 的
data目录里的密钥文件:这是很多人忽略的致命点。 - 历史会话录像和操作日志:这是堡垒机的审计价值所在,丢了等于审计能力直接清零。
这里单独强调一下密钥文件。Jumpserver 里的资产登录凭据,很多是以加密方式存在数据库里的,但解密依赖 core 服务密钥目录下的 key 文件。如果只导数据库、不迁移密钥,你会发现所有资产密码都解不开,用户无法通过堡垒机登录任何服务器。这个坑特别典型,我在论坛上看到过不止一次。
所以迁移策略很简单:新环境部署好同版本 Jumpserver 后,先停掉 core 服务,用旧环境的密钥文件覆盖新环境的对应目录,再启动服务。顺序不能反,否则 Jumpserver 会重新生成新密钥导致数据失配。
3.2 数据库和 Redis 的备份操作
备份数据库时,建议用mysqldump加--single-transaction参数,这样备份期间不会锁表,对正在使用的生产环境友好一些。同时,把存储函数、触发器、事件一起备份。
mysqldump -ujumpserver -p --single-transaction --routines --triggers --events jumpserver > jumpserver_backup_$(date +%F).sqlRedis 备份最简单的方式就是触发一次BGSAVE,然后把生成的dump.rdb文件拷走。
redis-cli BGSAVE cp /var/lib/redis/dump.rdb /backup/redis_dump.rdb再把 Jumpserver 相关目录打包。
tar czf jms_full_backup_$(date +%F).tar.gz /opt/jumpserver这一步做完,你手里就有了旧环境的完整快照。备份文件建议异地或者单独存储,不要在旧服务器本地放一份就完事,万一迁移过程中旧服务器出问题,备份也丢了那就真的欲哭无泪。
3.3 数据导入与组件切换
新环境 Jumpserver 安装并验证启动正常后,开始数据导入。
数据库恢复前,先停掉新环境的 core 和 celery 服务,避免写入操作和恢复的数据产生冲突。
./jmsctl.sh stop mysql -ujumpserver -p jumpserver < jumpserver_backup_$(date +%F).sqlRedis 的恢复是把备份的dump.rdb放到新 Redis 的持久化目录,覆盖新生成的文件,然后重启 Redis。
systemctl stop redis cp /backup/redis_dump.rdb /var/lib/redis/dump.rdb chown redis:redis /var/lib/redis/dump.rdb systemctl start redis最后,把旧环境的密钥目录同步过去,再启动 Jumpserver:
rsync -av old-server:/opt/jumpserver/core/data/keys/ /opt/jumpserver/core/data/keys/ ./jmsctl.sh start同步密钥时要注意目录权限,Jumpserver 容器内用户对密钥文件的可读权限必须正确,否则 core 还是无法用密钥解密资产口令。
3.4 版本差异的兼容性处理
如果你的旧堡垒机是 v2.x,而新装了 v3.x,数据导入后多半会遇到“版本升级”提示。Jumpserver 在启动时会检测数据库结构版本,并自动执行迁移脚本。这个过程通常能完成,但如果跨的版本太远,建议按官方升级路径走,先在旧版本上逐步升级到某个过渡版本,再导出数据。
我的实际做法是:先在旧机器上把 Jumpserver 升级到与目标环境同一版本,确认业务正常后,再备份导入新环境。这样数据库结构始终是一套,导入后不会出现“结构太老、脚本跑不动”的问题。
4. 上线验证与安全检查:迁移完成不等于迁移成功
4.1 功能验证清单:从登录到业务侧的完整链路
数据导入只是第一步,真要宣布迁移成功,得把整个业务链路完整跑一遍。我每次迁移都会列一张验证清单,一项一项打勾:
- Web 管理页面能否正常登录,admin 账号是否可用。
- 用户和用户组数据是否完整,密码策略是否和旧环境一致。
- 资产列表是否齐全,包括 Linux、Windows、网络设备、数据库资产。
- 授权规则是否正确绑定,用户是否能正常看到被授权的资产。
- Web 终端连接 Linux 资产,敲命令是否流畅,字符终端是否卡顿。
- RDP 连接 Windows 资产,远程桌面能否正常打开。
- 数据库代理连接 MySQL、Oracle,是否能正常执行查询。
- 文件传输功能,SFTP 上传下载是否正常。
- 会话录像是否正常录制、回放。
- 命令过滤规则是否生效,高危命令是否被拦截。
你可能觉得这么多项,一个个测太费时间,但堡垒机这东西,任何一个功能静默失效都可能在后续使用中造成大麻烦。而且迁移后相当一段时间内,用户会集中用堡垒机办公,如果有功能异常,上报的都是突发状况,不如现在一条一条过清楚。
4.2 数据一致性核对
功能验证之外,数据层面也要抽查。我的做法是挑几类关键数据进行总量对比:
- 比对用户总数、资产总数、授权规则数。
- 抽查几个高权限账号,看资产列表和授权是否完整。
- 随机找一条授权规则,解绑再绑定,看状态是否同步。
检查时发现一个细节问题:旧环境的账号口令如果被密钥文件加密,导入新环境时必须确保密钥文件版本一致,否则授权规则在界面上看着正常,但实际连接资产时会报“认证失败”。所以“先配密钥、再导数据、再启服务”这个顺序一定要坚持。
4.3 防火墙与系统安全的复核
新系统上线前,还要过一遍安全配置。
# 只放行必要端口 firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --permanent --add-port=2222/tcp firewall-cmd --reloadJumpserver 默认 SSH 连接端口是 2222,koko 组件需要监听这个端口对外提供 SSH 转发。如果用户习惯用原生 SSH 客户端连接堡垒机,这个端口必须在防火墙放行。
另外,MySQL 和 Redis 如果和 Jumpserver 在同一台机器,那它们的端口最好只监听本机,不要让 3306 和 6379 暴露到外网。尤其 Redis,很多人因为偷懒不设密码,还直接监听 0.0.0.0,结果被扫到后植入挖矿程序,这是老生常谈的问题了。
4.4 旧系统保留多久比较稳妥
迁移切量之后,旧堡垒机不要立即销毁。至少要保留一到两周的观察期,万一新环境出现只在特定场景下才触发的异常,还能切回旧环境应急。
实际操作时,我会在旧机器网络层直接限制来源 IP,只允许少数管理员的 IP 访问,同时保留完整的只读权限,防止误操作改变旧系统状态。等新环境稳定运行、所有的历史录像都确认能正常回放后,再下线旧机器。
5. 实战踩坑记录与排查技巧
5.1 字符集问题:乱码和写入报错的元凶
这次迁移遇到的一个明显问题是:从旧库导出的 SQL 文件,默认可能是 latin1 字符集,导入到 utf8mb4 的新库后,中文全是乱码。
排查过程很简单,导入后随便看一眼用户昵称就发现问题了。解决方法是备份导出时不要偷懒,明确指定字符集:
mysqldump -ujumpserver -p --default-character-set=utf8mb4 --single-transaction jumpserver > backup.sql导入时也指定字符集,双保险:
mysql -ujumpserver -p --default-character-set=utf8mb4 jumpserver < backup.sql5.2 Redis 启动异常:持久化文件引入的兼容性问题
第一次在新系统恢复 Redis 时,因为版本小版本不一致,直接拿旧环境的dump.rdb覆盖过去,导致 Redis 启动失败。报错信息是持久化文件版本不匹配或者加载失败。
排查思路很简单,启动 Redis 时开日志看具体报错。解决办法是把 Redis 升级到一致版本后再加载旧 RDB 文件,或者通过旧环境redis-cli --rdb命令导出兼容性更好的备份文件。
这里也提醒一下,如果新旧 Redis 大版本差距很大(比如 5.x 到 7.x),直接覆盖 RDB 文件基本会失败,最好的办法是让 Redis 版本尽量保持统一。
5.3 防火墙和 SELinux 的隐形拦截
还有一次比较耐人寻味的故障是:Jumpserver 界面显示正常,但用户从 Web 终端连资产时一直超时。我一度以为是 koko 组件问题,后来排查才发现是新防火墙规则只放行了 80/443 端口,koko 和外部通信的端口没放行。
所以部署新环境时,一开始就把 2222 等端口列入放行名单,别等用户抱怨了再补救。SELinux 的坑则更隐蔽——即使关掉了,也建议确认一下sestatus输出是 disabled 还是 permissive,因为临时关闭和永久关闭是两回事,重启后策略会重新加载。
5.4 历史录像和日志文件的存储规划
迁移后另一个容易被忽视的点,是历史会话录像的存储。Jumpserver 的录像文件默认存在本地持久化目录,很多公司的录像文件动辄几百 GB,迁移时必须规划好磁盘空间。
我在这次迁移前特意给数据盘做了扩容,并建议后续把/opt/jumpserver里的录像存储目录单独挂载到独立数据盘,避免日志和录像把系统盘塞满。录像文件一般不会被频繁读取,但是要长期保留,用对象存储归档会更好。
5.5 迁移之后的工作总结
这次从 CentOS 7 迁移到 Rocky Linux 9,整体过程是顺利的,但顺利建立在对每个环节都做了预案的基础上。迁移最忌讳想当然,觉得“反正都是 Linux,直接复制过去跑一遍就行”。堡垒机牵扯到数据库、缓存、密钥、录像、网络代理、Web 服务,任何一环脱节都可能出问题。
最后再分享一个小技巧:迁移前花十分钟把旧环境的完整依赖清单导出一份,包括 Jumpserver 版本号、MySQL 版本、Redis 版本、Nginx 版本,以及各个配置文件的关键项。新环境部署时照着这个清单一步步对齐,比事后回忆省力得多,也不容易漏项。