在Linux服务管理这个话题上,现在很多人一上来就是systemctl status、systemctl enable,这套思路当然没错。但如果你维护过一批CentOS 6或者更早的服务器,或者在面试中被问到“进程与服务管理命令”这个考点,chkconfig是个绕不开的名字。它和service、ntsysv一起,构成了SysV init时代服务管理的三件套,而chkconfig负责的恰恰是最容易被忽略、又最容易出问题的环节——开机自启动。
简单说,chkconfig是一个专门用来管理系统服务开机启动项的命令行工具。它能查看某个服务在哪些运行级别下会被自动拉起,也能一键开启或关闭自启动,还能把自定义脚本注册成系统服务。这篇文章我会把chkconfig的原理、常用参数、自定义服务脚本的写法、以及我实际维护过程中踩过的坑完整讲一遍,适合刚接触Linux运维的同学,也适合想系统整理这类命令的老手。
1. chkconfig到底是什么,为什么现在还值得学
1.1 它管什么,又不管什么
chkconfig是SysV init(System V初始化系统)时代的服务配置工具,它管理的对象是安装在/etc/init.d或/etc/rc.d/init.d目录下的服务脚本。它的核心职责只有一个:决定某个服务在系统进入不同运行级别时,是否自动启动。
注意它的边界:它不负责启动或停止服务,那是service命令干的。它也不负责查看进程当前在不在跑,那是ps、pgrep、top的事。chkconfig只回答一个问题——开机的时候,要不要把这个服务拉起来。
这个定位很纯粹,但也很关键。很多人刚接触Linux时,会把“服务没有开机自启”和“服务启动失败”混为一谈。实际上前者是chkconfig的管辖范围,后者要看服务脚本本身和日志。理解了这条边界,排查问题时思路会清晰很多。
1.2 为什么现在还值得学
有人可能会问:现在systemd都普及了,CentOS 7之后都在用systemctl enable,学chkconfig还有意义吗?我的看法是,非常有必要,至少有四个场景会用到它:
第一,存量服务器还在跑。不少企业的生产环境至今还有CentOS 6、老版Ubuntu、RHEL 6的机器。这些机器上的服务管理就是SysV这套体系,chkconfig是日常运维的必备命令。你总不能在老服务器上说“我只会systemctl”,那工作就没法开展了。
第二,国产化替代环境。如今很多基于老版本Linux改造的国产发行版,出于兼容性考虑,服务管理接口依然保留了chkconfig。哪怕系统底层换成了systemd,也常常提供一个chkconfig兼容层。会这个命令,遇到这类环境不会卡壳。
第三,面试高频考点。Linux面试题里,“怎么把一个服务设为开机自启”“怎么看某个服务是否开机自启”是标准题目。光答systemctl,面试官一旦追问旧系统或者问“讲讲运行级别”,没有chkconfig的知识储备就容易露怯。
第四,理解systemd的最佳历史教材。systemd里的target相当于运行级别的“语义化升级版”,systemctl enable背后做的事情,本质上和chkconfig在rcX.d目录里创建软链接是同一件事。把chkconfig搞明白,再看systemd的Wants、After、Requires这些概念,理解成本会低非常多。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 先搞懂运行级别和启动脚本机制
2.1 SysV init时代的启动链路
要真正理解chkconfig,不能只背命令,得先理解它背后的机制。SysV init的启动流程是这样的:内核启动后执行第一个用户态进程/sbin/init,init读取/etc/inittab,找到默认运行级别,比如id:3:initdefault:就表示默认进入运行级别3。然后init会去执行/etc/rc.d/rc3.d目录下的脚本(在Debian系是/etc/rc3.d)。
关键就在这个rc3.d目录。它里面存了一堆符号链接,链接指向/etc/rc.d/init.d下的真实服务脚本,链接命名规则是:S或K开头,加两位数字,再加服务名。S表示Start,启动时执行;K表示Kill,退出该运行级别时执行。数字决定执行顺序,数字越小越先执行。
举个例子,rc3.d里可能有S10network、S55sshd、S85nginx。系统进入运行级别3时,先启动网络(S10),再启动SSH(S55),最后启动Nginx(S85)。顺序错了,后面依赖网络的服务就会启动失败。
2.2 运行级别0到6的含义
运行级别这个概念在systemd时代被弱化了不少,但理解它仍然很重要。Linux标准运行级别一共有7个:
| 运行级别 | 含义 |
|---|---|
| 0 | 停机,init进入后直接关机 |
| 1 | 单用户模式,基本无网络,常用于救援 |
| 2 | 多用户模式,Debian系默认无网络服务 |
| 3 | 完整的多用户文本模式,服务器最常用 |
| 4 | 保留级别,一般未使用,可自定义 |
| 5 | 图形化多用户模式,桌面系统常用 |
| 6 | 重启 |
服务器默认一般是3,装了桌面环境的可能默认5。chkconfig --list输出里的0到6列,对齐的就是这7个级别。
2.3 chkconfig在链路中的角色
现在再看chkconfig就清晰了:它就是一个帮你在/etc/rc.d/rcX.d目录下创建、删除、查看S/K链接的工具。手动创建链接当然也可以,但chkconfig的优势在于:
第一,它会读取服务脚本头部的注释,自动计算出S和K后面的优先级数字,不用你手动拼文件名。第二,一条命令就能在多个运行级别下批量创建或删除链接,效率高得多。第三,它的--list输出把所有服务的自启动状态汇总成一张清单,运维巡检时非常直观。
2.4 和rc.local的对比
很多人提到开机自启,第一反应是往/etc/rc.local里加命令。这个做法能用,但它和chkconfig管理服务不是一回事。/etc/rc.d/rc.local本质上是S99local的链接,在多用户模式下由init在最后阶段调用,更像一个“启动兜底脚本”。
rc.local的缺点很明显:所有命令堆在一起,没法单独启停某个服务;执行顺序只能靠文本顺序硬排,一旦某行命令卡住了,后面的全部遭殃;也没有status、restart之类的状态管理能力。而chkconfig管理的是一个完整的init脚本,支持start、stop、restart、status,这才是“服务”该有的规范形态。所以我的建议是:能写成服务的,优先用chkconfig管理;rc.local只适合放一些临时性、一次性的启动命令。
3. 环境准备:哪些系统能用,怎么装
3.1 各发行版支持情况
chkconfig在不同发行版上的情况不太一样,先分清楚再上手,免得踩坑。
RHEL和CentOS 5、6系列是chkconfig的主场,系统安装的时候就会带上,无需额外安装。CentOS 7、8以及RHEL 7、8开始,默认使用systemd,chkconfig作为兼容包存在,可能默认装了,也可能没有。Debian和Ubuntu的传统体系是sysv-rc,管理命令叫update-rc.d,不是chkconfig。但Debian的软件仓库里也有chkconfig这个包,装上之后可以用,不过更推荐使用系统原生的update-rc.d,和init脚本的兼容性更好。
3.2 安装和验证
在CentOS 7上如果发现没有chkconfig,用yum装一下就行:
bash复制yum install -y chkconfig
在Debian或Ubuntu上:
bash复制apt install -y chkconfig
装完之后先验证一下:
bash复制chkconfig --list | head -20
如果是在CentOS 7这种systemd系统上执行,可能会看到一句提示,大意是“This output shows SysV services only and does not include native systemd services”,这不是错误,只是提醒你,原生systemd服务要用systemctl list-unit-files来看。这句提示很常见,别被它唬住。
3.3 练手环境建议
如果你想彻底练熟chkconfig,我最推荐的方式是装一台CentOS 6虚拟机。CentOS 6已经停止维护,不要用于生产,但作为学习环境完全够用,而且CentOS 6上chkconfig的行为最典型、最纯粹。如果嫌麻烦,CentOS 7上用兼容层也可以,体验会稍微有点差异,但核心命令都一样。实在不想装虚拟机,用Docker拉一个CentOS 6镜像也能玩,只是Docker里的init系统和宿主机不完全一样,部分系统服务测试会受限。
4. chkconfig常用命令全解析(真·速查版)
4.1 查看服务自启动状态:chkconfig --list
这是最常用的命令。不带参数执行,会把所有已注册服务在0到6运行级别下的开关状态列出来。输出大概是这样的:
text复制network 0:off 1:off 2:on 3:on 4:on 5:on 6:off
sshd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
nginx 0:off 1:off 2:off 3:off 4:off 5:off 6:off
含义很直白:network在2、3、4、5级别开机自启,0、1、6关闭。nginx全部都是off,说明它虽然注册了,但还没开启任何级别的自启动。
想看单个服务,直接指定服务名:
bash复制chkconfig --list sshd
如果服务不存在,会报类似error reading information on service sshd: No such file or directory的错误。实际巡检时最常用的组合是:
bash复制chkconfig --list | grep nginx
这样可以快速过滤出目标服务,不用在一长串列表里找眼睛。
4.2 注册和移除服务:--add 与 --del
--add用于把一个新脚本注册进chkconfig的管理范围。你新写了一个服务脚本放进了/etc/init.d,但还没有任何rcX.d链接时,必须执行一次:
bash复制chkconfig --add nginx
执行完之后,系统会根据脚本头部的注释,在相应运行级别目录下创建S或K链接。比如说脚本头声明了# chkconfig: 2345 85 15,chkconfig就会在rc2.d到rc5.d创建S85nginx,在rc0.d、rc1.d、rc6.d创建K15nginx。
--del是反向操作,把某个服务从启动项里移除:
bash复制chkconfig --del nginx
它会清掉所有运行级别下的相关符号链接。注意,服务脚本本身还留在/etc/init.d,只是不再参与开机自启。如果你连脚本都不想要,得手动删掉文件。
4.3 设置自启动:--level 和 on/off
核心操作来了。先指定运行级别,再指定服务名,最后写on或off:
bash复制chkconfig --level 3 nginx on
chkconfig --level 2345 nginx on
第一条是让nginx仅在运行级别3自启,第二条是在2、3、4、5四个级别都开启。第二种写法最常用,因为对服务器来说,文本模式(3)和图形模式(5)都会用到,2和4也一并打开,省得切换级别时服务状态不一致。
不带--level直接执行:
bash复制chkconfig nginx on
默认操作的是2、3、4、5这四个级别。off同理:
bash复制chkconfig nginx off
这里有一个容易混淆的点:chkconfig nginx off只会关掉2到5级别的自启动,如果你之前还在某个奇怪级别开了自启,最好用--level精确指定。
4.4 其他参数补充
--set可以一次性设置多个级别,写法大概是:
bash复制chkconfig --set nginx 35
不过不同版本的chkconfig对这个参数的支持有差异,有的版本更认可--level方式。实际使用中,--level已经能覆盖绝大多数场景,不用太过纠结。
还有一个--levels,和--level等价,只是写法习惯不同。--no-redirect这个参数比较冷门,在带systemd兼容层的系统上,可以禁止chkconfig把操作重定向给systemd,一般用不到,了解即可。
4.5 一行命令速查表
| 目标 | 命令 |
|---|---|
| 查看所有服务自启动状态 | chkconfig --list |
| 查看指定服务自启动状态 | chkconfig --list sshd |
| 注册新服务 | chkconfig --add nginx |
| 移除服务注册 | chkconfig --del nginx |
| 在2-5级别开启自启 | chkconfig --level 2345 nginx on |
| 在2-5级别关闭自启 | chkconfig --level 2345 nginx off |
| 不指定级别操作(默认2-5) | chkconfig nginx on/off |
5. 实战:把自定义服务脚本纳入chkconfig管理
5.1 服务脚本需要满足的条件
要纳入chkconfig管理,脚本必须满足几个条件。第一,放在/etc/init.d/目录下,并且要有可执行权限。第二,脚本头部至少要包含两行特殊注释:
bash复制#!/bin/bash
# chkconfig: 2345 85 15
# description: nginx is a high-performance web server
这两行就是chkconfig识别服务的关键情报。2345表示默认运行级别,85是启动优先级,会生成S85nginx这样的链接,15是停止优先级,对应K15nginx。第三,脚本需要支持start、stop、restart、status这类参数,因为service命令调用时就是通过$1传参的。
5.2 一个完整的Nginx管理脚本示例
我自己在旧机器上用过的一个Nginx管理脚本,精简后是这样:
bash复制#!/bin/bash
# chkconfig: 2345 85 15
# description: nginx is a high-performance web server
nginx=/usr/local/nginx/sbin/nginx
pidfile=/usr/local/nginx/logs/nginx.pid
prog="nginx"
case "$1" in
start)
echo -n "Starting $prog: "
if [ -f "$pidfile" ]; then
echo "already running"
exit 0
fi
$nginx
if [ $? -eq 0 ]; then
echo "OK"
else
echo "FAILED"
exit 1
fi
;;
stop)
echo -n "Stopping $prog: "
if [ ! -f "$pidfile" ]; then
echo "not running"
exit 0
fi
/bin/kill "$(cat $pidfile)" 2>/dev/null
rm -f "$pidfile"
echo "OK"
;;
restart)
$0 stop
sleep 1
$0 start
;;
status)
if [ -f "$pidfile" ]; then
echo "$prog is running (pid $(cat $pidfile))"
else
echo "$prog is not running"
fi
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac
exit 0
这段脚本不是万能模板,但结构很典型:路径变量统一放头部,方便修改;start、stop、restart、status四个基本操作都有;加了一些基础的pidfile判断,避免重复启动或误杀。你在实际使用时要根据自己的软件安装路径、pid文件位置做调整。
5.3 加入chkconfig并开启自启动
脚本写好后,按这个顺序操作:
bash复制chmod +x /etc/init.d/nginx
先手动执行启动,验证脚本本身没问题:
bash复制/etc/init.d/nginx start
如果发现启动失败,先别往下走,排查脚本里的路径、权限、pidfile逻辑,直到start和stop都能正常跑通。确认没问题后,手动停掉服务,恢复初始状态:
bash复制/etc/init.d/nginx stop
然后注册服务:
bash复制chkconfig --add nginx
再设2到5级别自启动:
bash复制chkconfig --level 2345 nginx on
检查一下状态:
bash复制chkconfig --list nginx
这时应该能看到nginx在2到5级别都是on。再验证一下符号链接是否真的建好了:
bash复制ls -l /etc/rc.d/rc3.d/ | grep nginx
正常会输出类似S85nginx -> ../init.d/nginx这样的链接。完成这一步,重启机器,Nginx就会自动启动了。
5.4 启动顺序数字怎么选
优先级数字的选择是有讲究的。启动时,S后面的数字从小到大执行,数字越小越先启动。所以你的服务如果依赖网络、数据库、或者别的中间件,启动数字一定要排在它们后面。一般来说,network是S10,sshd是S55,自定义服务建议取80到90之间,既避开了系统关键服务,又能保证在大多数依赖之后启动。
停止时K的规则反过来,数字越小越先停止。所以停止优先级一般取一个较小的值,比如15,这样关机的时你的服务会先停,然后才是网络等底层组件。当然这个不是绝对,取决于你脚本头里第三个数字怎么填。
5.5 跟rc.local对比:什么时候用哪个
如果一个服务有完整的启停脚本,我强烈建议用chkconfig管理。但如果你只是想让某个程序开机跑一下,没有复杂的启停逻辑,往/etc/rc.local里加一行也完全没问题。两者不冲突,但适用场景不同。rc.local适合“一次性启动命令”,chkconfig适合“可管理服务”。判断标准很简单:如果你以后还想单独stop、restart这个进程,那它就是服务,应该纳入chkconfig。
6. 实战:服务自启动的巡检与调整
6.1 全量导出与巡检
实际运维中,我经常要给一批服务器做自启动巡检。几十台机器一台台登录看太慢了,一般是写一个循环,把每台机器的chkconfig --list结果导出到本地文件,再统一分析:
bash复制for host in server01 server02 server03; do
ssh "$host" "chkconfig --list" > "chkconfig_${host}.txt"
done
导出之后,重点看3和5级别哪些服务是on,逐一和业务核对,是不是都有必要。这个动作在旧系统上相当于给服务器做了一次“开机启动项体检”。
6.2 关闭不需要的服务
有些服务默认开启,但实际业务根本用不到,比如bluetooth、cups、postfix、avahi-daemon这些。在服务器上关掉它们,可以减少资源占用,还能降低被攻击面。操作很简单:
bash复制chkconfig --level 2345 cups off
或者直接:
bash复制chkconfig cups off
但要注意,off只是关掉了开机自启,并不会立刻停止当前正在运行的服务。如果你想立刻停掉,还得手动执行:
bash复制service cups stop
我的习惯是关闭前先做一次备份,防止后续发现误关又找不到原来的状态:
bash复制chkconfig --list > /root/chkconfig_backup_$(date +%F).txt
这个习惯救过我一次,有一次我把一台机器上的NTP服务关了,后来发现业务有同步时间需求,还好有备份,一条条对照恢复起来快很多。
6.3 改启动顺序解决依赖问题
还有一个常见场景是启动顺序不对。比如业务A的脚本依赖MySQL,但A在S50,MySQL在S85,结果A启动时MySQL还没起来,连接数据库失败。
解决办法是修改业务A的init脚本头,把启动数字调到MySQL之后。比如MySQL是S85,那A至少得是S90:
bash复制# chkconfig: 2345 90 10
改完之后,先删掉再重新注册,让链接按新数字重建:
bash复制chkconfig --del A
chkconfig --add A
有人可能会想,直接手动重命名rcX.d下的符号链接,把S50A改成S90A不就行了?这样做确实能生效,但chkconfig内部的状态和实际链接可能不一致,以后再执行--add或--del时容易出乱子。所以规范做法还是改脚本头,然后del/add重建。
6.4 面试高频考点速答
这里整理几个面试常问的点,方便临时抱佛脚:
问:如何让httpd服务在运行级别3和5开机自启?答:chkconfig --level 35 httpd on。
问:chkconfig --list输出里,0:off、1:off、2:on、3:on、4:on、5:on、6:off是什么意思?答:表示该服务在0、1、6级别不自启,在2、3、4、5级别自启。
问:chkconfig --add和--del的作用是什么?答:注册和注销服务的自启动项,本质是在对应运行级别目录下创建或删除S/K符号链接。
问:chkconfig能代替service启动服务吗?答:不能,chkconfig只管自启动配置,实际启停服务用service命令。
这些问题如果理解了前面的原理,基本不用背也能答出来。
7. 常见问题与故障排查
7.1 报错信息速查表
| 现象 | 可能原因 | 处理方法 |
|---|---|---|
| service xxx does not support chkconfig | 脚本头缺少# chkconfig和# description行 | 补上注释后重新chkconfig --add |
| chkconfig --add后开机不生效 | 脚本头级别配置不对、脚本不可执行、脚本内路径错误 | 检查默认运行级别、可执行权限、脚本内容 |
| chkconfig --list看不到某个服务 | 服务未被注册,或者它是systemd原生服务 | 用chkconfig --add注册,或者用systemctl list-unit-files查看 |
| chkconfig xxx off后服务还在运行 | off只改开机自启,不影响当前进程 | 手动service xxx stop |
| 服务启动顺序不对 | 脚本头优先级数字设置不合理 | 修改脚本头数字,然后del/add重建链接 |
7.2 经典报错:does not support chkconfig
这个报错出现频率非常高,很多新手一看到就懵。其实原因就一个:/etc/init.d/xxx脚本头部缺少# chkconfig和# description这两行。chkconfig是靠这两行来解析运行级别和优先级的,识别不了就报“不支持”。
解决方法是打开脚本,在头部补上:
bash复制# chkconfig: 2345 85 15
# description: some description
保存后重新执行:
bash复制chkconfig --add xxx
基本
