宝塔环境安装 Redis 踩坑复盘:从 chkconfig 缺失到启动脚本修复
前言
这次排障看起来是在“安装 Redis”,实际上中间连续踩了三层坑:
-
宝塔安装脚本提示
chkconfig: command not found -
手动安装
chkconfig时又失败,表面看是包安装失败,实际上是系统路径布局异常 -
chkconfig修好后,Redis 仍然启动失败,日志里出现Failed to configure LOCALE for invalid locale name
如果只盯着表面提示,很容易在错误方向上越走越远。
这篇文章把整条处理链完整记录下来,适合在宝塔、CentOS Stream 9、Redis 8 这类场景里做参考。
环境信息
-
系统:CentOS Stream 9
-
面板:宝塔
-
Redis 版本:8.0.5
-
安装路径:
/www/server/redis
第一个现象:宝塔安装 Redis 时提示 chkconfig: command not found
在宝塔安装 Redis 时,日志里出现了下面的提示:
redis.sh: line 85: chkconfig: command not found
redis.sh: line 86: chkconfig: command not found
这一步很容易让人下意识得出一个结论:
“系统里缺少 chkconfig,装一下就好了。”
这个结论只对了一半。
第一反应:直接安装 chkconfig
于是执行:
dnf install -y chkconfig
但安装并没有成功,而是报了这种错误:
Error unpacking rpm package chkconfig-1.24-2.el9.x86_64
错误:事务失败
这时候如果只看表面,还是很容易误判成:
-
RPM 数据库坏了
-
磁盘满了
-
DNF 源有问题
-
包本身有问题
但这些都不是根因。
第二层定位:不是磁盘,也不是 DNF,而是系统路径冲突
首先排除了最常见的基础问题:
1. 磁盘和 inode 充足
df -h /
df -i /
确认系统盘空间和 inode 都很富余,所以不是“磁盘写不进去”。
2. chkconfig 确实没装上
rpm -qa | grep '^chkconfig'
dnf list installed chkconfig
结果确认未安装。
3. 拉取更详细的安装日志
使用更详细的输出重新安装:
dnf install -y chkconfig -v
这一次才看到真正关键的信息:
错误:解压压缩文件 在文件 /etc/init.d 失败:
cpio: File from package already exists as a directory in system
这句话直接把问题点出来了:
chkconfig 包在安装时,需要处理 /etc/init.d 这个路径,但当前系统里的 /etc/init.d 状态不符合包预期。
根因分析:/etc/init.d 被当成普通目录使用了
继续检查:
ls -la /etc/init.d
ls -la /etc/rc.d/init.d
发现当前系统里:
-
/etc/init.d是一个真实目录 -
里面还有宝塔残留脚本:
-
bt -
nginx -
redis
而在 RHEL/CentOS 体系里,/etc/init.d 正常情况下通常应该指向:
/etc/rc.d/init.d
也就是说,这台机子当时的状态是:
-
标准 SysV init 路径布局被破坏
-
宝塔脚本把服务脚本直接塞进了
/etc/init.d -
chkconfig安装时遇到了路径冲突,于是解包失败
这也是为什么“只是缺少 chkconfig”这个判断不够完整。
修复方案:把 /etc/init.d 恢复成标准软链接
处理思路是三步:
-
先把已有脚本迁移到标准目录
-
再把
/etc/init.d恢复成软链接 -
然后重新安装
chkconfig
第一步:迁移已有脚本
先把原来目录中的脚本移动到标准位置:
mkdir -p /etc/rc.d/init.d
mv /etc/init.d/bt /etc/rc.d/init.d/
mv /etc/init.d/nginx /etc/rc.d/init.d/
mv /etc/init.d/redis /etc/rc.d/init.d/
第二步:恢复 /etc/init.d 软链接
移除原有目录后建立软链接:
rmdir /etc/init.d
ln -s rc.d/init.d /etc/init.d
验证:
ls -ld /etc/init.d /etc/rc.d/init.d
readlink -f /etc/init.d
如果正常,应该看到:
/etc/init.d -> rc.d/init.d
第三步:重新安装 chkconfig
再执行:
dnf install -y chkconfig
这次安装就成功了。
验证:
command -v chkconfig
chkconfig --version
rpm -q chkconfig
例如:
/usr/sbin/chkconfig
chkconfig 版本 1.24
chkconfig-1.24-2.el9.x86_64
到这里,第一层问题才算真正修完。
第二个现象:Redis 启动日志出现 Failed to configure LOCALE for invalid locale name
在 chkconfig 装好后,Redis 开始能执行启动逻辑,但日志里反复出现:
Failed to configure LOCALE for invalid locale name.
看起来像只是“警告”,但这次实际表现是:
-
Redis 日志里有启动记录
-
但
6379没监听 -
redis-cli ping失败
也就是说,这不是单纯“可以忽略的提示”,而是伴随启动失败一起出现的。
第三层定位:Redis 不是配置坏了,而是被启动环境带崩了
先检查实际状态:
ps -ef | grep redis-server | grep -v grep
ss -lntp | grep 6379
redis-cli -h 127.0.0.1 -p 6379 ping
结果确认:
-
没有 Redis 常驻进程
-
没有
6379监听 -
ping直接拒绝连接
接着检查系统 locale:
locale
localectl status
env | grep -E '^(LANG|LC_|LANGUAGE)='
系统环境类似:
LANG=zh_CN.UTF-8
LC_ALL=
继续查看 Redis 启动脚本:
sed -n '1,220p' /etc/rc.d/init.d/redis
关键启动逻辑大致是:
sudo -u redis $EXEC $CONF
这个写法会直接继承当前 shell 的 locale 环境。
而 Redis 8 在当前这套环境下,启动时对 locale 的处理出了问题。
关键验证:手工用中性 locale 启动 Redis
为了验证是不是 locale 导致的,直接手工执行:
cd /www/server/redis
LANG=C LC_ALL=C ./src/redis-server ./redis.conf
结果 Redis 正常启动,日志里出现:
Server initialized
Ready to accept connections tcp
再验证:
ss -lntp | grep 6379
redis-cli -h 127.0.0.1 -p 6379 ping
返回:
PONG
这一步就把根因坐实了:
-
Redis 配置文件没坏
-
不是端口冲突
-
不是权限问题
-
是启动脚本继承的 locale 环境导致 Redis 8 启动异常
最终修复:改 Redis 启动脚本
既然手工启动时 LANG=C LC_ALL=C 可用,那么最稳的做法,就是把这个环境直接写进启动脚本。
把:
sudo -u redis $EXEC $CONF
改成:
LANG=C LC_ALL=C sudo -u redis $EXEC $CONF
同时顺手补一个更可靠的启动结果校验。
因为宝塔原脚本存在一个问题:
-
不管 Redis 是否真的启动成功
-
它都会直接输出
Starting redis success!
这会让排障非常误导。
所以把启动逻辑改成:
echo "Starting redis server..."
LANG=C LC_ALL=C sudo -u redis $EXEC $CONF
sleep 1
if [ -f "${PIDFILE}" ] && ps -p $(cat ${PIDFILE}) > /dev/null 2>&1; then
echo ${REDIS_PORT} > /www/server/redis/start.pl
echo "Starting redis success!"
else
echo "Starting redis failed!"
exit 1
fi
这样做有两个好处:
-
启动时不再受当前 shell locale 干扰
-
脚本会判断 Redis 是否真的起来,而不是盲目报成功
修复后的验证结果
修改完成后重新启动:
/etc/rc.d/init.d/redis start
验证状态:
/etc/rc.d/init.d/redis status
redis-cli -h 127.0.0.1 -p 6379 ping
ps -ef | grep redis-server | grep -v grep
结果正常:
redis is running! (1414491)
PONG
redis 1414491 ... /www/server/redis/src/redis-server 127.0.0.1:6379
这说明:
-
Redis 成功启动
-
6379已监听 -
本机访问正常
这次排障最大的经验
1. 不要只盯第一层报错
看到:
chkconfig: command not found
很容易直接得出“装个 chkconfig 就行”的结论。
但真正卡住安装的是:
cpio: File from package already exists as a directory in system
前者只是表面现象,后者才是根因。
2. 包安装失败时,优先看详细日志
像这种:
Error unpacking rpm package
如果不加 -v 或不看 DNF/RPM 详细日志,很难知道到底是:
-
磁盘问题
-
权限问题
-
文件冲突
-
包损坏
而这次其实是标准路径冲突。
3. 服务脚本“显示成功”不代表服务真的成功
宝塔 Redis 脚本原本有个典型问题:
-
启动命令执行后,不判断服务状态
-
直接回显成功
这种脚本在排障时非常坑人。
比较稳的习惯是:启动后一定要再做一次真实校验。
例如:
ps -ef | grep redis-server | grep -v grep
ss -lntp | grep 6379
redis-cli -h 127.0.0.1 -p 6379 ping
4. Redis 8 对环境更敏感时,脚本要尽量“中性”
如果服务端程序会受 locale、编码、环境变量影响,那么启动脚本里最好显式指定一个保守环境,例如:
LANG=C
LC_ALL=C
这样可以减少“交互式 shell 正常、面板启动异常”的情况。
关键命令汇总
查看 chkconfig 安装失败的真实原因
dnf install -y chkconfig -v
修复 /etc/init.d
mkdir -p /etc/rc.d/init.d
mv /etc/init.d/bt /etc/rc.d/init.d/
mv /etc/init.d/nginx /etc/rc.d/init.d/
mv /etc/init.d/redis /etc/rc.d/init.d/
rmdir /etc/init.d
ln -s rc.d/init.d /etc/init.d
安装 chkconfig
dnf install -y chkconfig
手工验证 locale 是否是问题根因
cd /www/server/redis
LANG=C LC_ALL=C ./src/redis-server ./redis.conf
验证 Redis 是否真的启动
ss -lntp | grep 6379
redis-cli -h 127.0.0.1 -p 6379 ping
ps -ef | grep redis-server | grep -v grep
总结
这次问题如果压缩成一句话,其实是:
宝塔安装 Redis 失败,不只是因为缺少 chkconfig,而是系统 /etc/init.d 路径布局异常导致 chkconfig 装不上;chkconfig 修好后,Redis 8 又因为启动脚本继承 locale 环境而异常退出,最终通过修正路径布局和启动脚本才彻底跑通。
整个处理链可以概括成:
-
发现
chkconfig: command not found -
安装
chkconfig失败 -
详细日志定位到
/etc/init.d路径冲突 -
恢复
/etc/init.d -> /etc/rc.d/init.d -
成功安装
chkconfig -
Redis 日志出现
Failed to configure LOCALE for invalid locale name -
手工用
LANG=C LC_ALL=C启动验证 -
修改宝塔 Redis 启动脚本
-
Redis 正常监听
6379并返回PONG
如果你的环境也是:
-
CentOS Stream 9
-
宝塔
-
Redis 8
而且你同时遇到了:
-
chkconfig: command not found -
Error unpacking rpm package chkconfig -
Failed to configure LOCALE for invalid locale name
那么这篇复盘基本就是一条完整的排障路线图。