2026/10/13 3:53:25

chkconfig 原理与实战:运行级别下的开机自启服务管理

chkconfig 原理与实战:运行级别下的开机自启服务管理 新装了一台系统装好某个自己编译的服务之后开机默认不会自动拉起。你手动启动一次服务倒是活了可下次重启它又躺平了。反过来有些服务明明没打算让它开机自启每次重启它却“不请自来”白白占着端口和内存。这类场景在还在使用 SysV init 管理方式的老环境里基本都是靠 chkconfig 来解决的。作为【Linux命令大全】系统设置部分的第 005 篇这篇不打算把命令参数像字典一样抄一遍而是从原理到实操把 chkconfig 从头到尾讲透。适合三类人还在维护老版本系统的运维老手、准备各类认证考试的备考人员以及想真正理解 Linux 服务启动机制、而不是只会上 systemctl enable 的命令行爱好者。1. 先弄明白 chkconfig 到底在改什么很多教程一上来就教你怎么敲命令却不说清楚命令背后发生了什么。结果就是你学会了chkconfig --add但下次换个环境、换个服务照样一脸懵。所以我习惯先讲原理哪怕只花三分钟后面排错能省三小时。1.1 七个运行级别就是七套“开机剧本”SysV init 时代系统不是只有一个“开机启动项”清单而是按运行级别runlevel分成 06 七套独立清单。你可以把它们理解成七套剧本进入图形桌面时执行一套进入纯命令行多用户环境时执行另一套关机维护时再执行另一套。这七个级别的定义在 Linux 里基本是约定俗成的运行级别含义0关机1单用户模式常用于维护和修复不启动网络2多用户模式但默认不启用 NFS部分发行版不区分 2/33完整的多用户文本模式服务器最常用4预留通常未使用5图形化多用户模式桌面环境默认进入6重启服务器类系统默认会进入级别 3 或 5。你可以在终端里执行runlevel查看当前所在的级别输出类似N 3N 表示上一次运行级别为空开机后没有切换过3 就是当前运行级别。这个数字非常关键因为 chkconfig 调整的正是“某个服务在哪些运行级别里自启、在哪些级别里不自启”。1.2 服务脚本和 rc 目录里的符号链接明白了运行级别还要知道 chkconfig 操作的对象到底是什么。在 SysV 体系下每个服务通常对应/etc/init.d/或/etc/rc.d/init.d/下的一个脚本比如sshd、network、crond。这些脚本本质上就是个可执行的 shell 脚本启动、停止、重启的逻辑都写在里面。但光有脚本还不够系统不会自己去猜测“这个脚本在开机时要不要执行”。于是就有了/etc/rc.d/rc0.d/到/etc/rc.d/rc6.d/这七个目录分别对应 06 运行级别。每个目录里放的不是脚本副本而是指向/etc/init.d/下脚本的符号链接链接名有固定格式以S开头的表示在进入该运行级别时启动Start以K开头的表示在进入该运行级别时停止Kill可以理解为终止字母后面紧跟两位数字表示执行顺序优先级举个例子如果/etc/rc.d/rc3.d/目录下有S85sshd这个符号链接就说明系统进入运行级别 3 时会按 85 这个序号执行 sshd 脚本的 start 逻辑。如果你在 rc3.d 目录里看到的是K85sshd那系统进入级别 3 时会执行 sshd 脚本的 stop 逻辑。chkconfig 干的事情本质上就是增删和调整这些符号链接。chkconfig --add sshd会在对应目录里创建以 S 开头的链接chkconfig --del sshd会移除这些链接chkconfig sshd on/off则是切换链接名字前缀是 S 还是 K。搞懂这一点你在心里就能建立起整套服务的启动调用链而不是当黑盒来用。1.3 chkconfig 在启动链路里的位置开机时内核启动第一个进程 init通常就是 PID 1init 读取默认运行级别然后依次执行对应 rc 目录下所有 S 开头的脚本。脚本名里的数字决定了先后顺序S10network 会先于 S85sshd 执行这样网卡起来之后依赖网络的 sshd 才能正常启动。chkconfig 并不真正负责“现在立刻启动或停止服务”这件事。现在启动服务用service 服务名 start或者直接执行/etc/init.d/服务名 start而 chkconfig 只负责设置“开机时要不要启动、在哪个级别启动、排在什么位置”。很多新手容易混淆看到chkconfig sshd on之后立刻检查服务状态发现 sshd 没起来就以为命令失效了。其实它只改了开机自启配置想让当前会话立即生效还是要手动 start。2. 动手前先给系统做个体检怎么看 chkconfig 的当前状态在改任何配置之前第一步永远是搞清楚现状。尤其是接触一台别人维护过的老服务器你根本不知道前任运维做了什么操作。先查、再改、后验证这套流程在任何系统管理任务里都不会错。2.1 确认环境不是所有系统都自带 chkconfigchkconfig 通常预装在使用 SysV init 的老版本发行版中。如果你在终端里执行chkconfig --list提示找不到命令先确认系统目前用的是不是 systemd命令如下ps -p 1 -o comm输出如果是systemd说明这是现代 systemd 环境它可能通过兼容层提供了 chkconfig 命令也可能干脆没装。输出如果是init说明还是老式 SysV 环境此时大概率自带 chkconfig。在基于 RPM 的老发行版里安装命令通常是yum install chkconfig在基于 Debian 的系统里也可以用apt-get install chkconfig。不过我得提醒一句在纯 systemd 的新系统上不建议为了用 chkconfig 而特意去装它来管理服务应该直接systemctl enable/disable否则配置可能写不进 systemd 真正的单元配置里造成“看起来生效、重启后不听话”的隐患。2.2 用--list看清服务的完整自启状态确认命令可用后直接输入chkconfig --list这是你日常巡检时最常用的命令。输出会列出系统里所有受 chkconfig 管理的 SysV 服务以及它们在每个运行级别的状态大致长这样crond 0:off 1:off 2:on 3:on 4:on 5:on network 0:off 1:off 2:on 3:on 4:on 5:on sshd 0:off 1:off 2:on 3:on 4:on 5:on从左到右依次是服务名然后是 0 到 6 七个级别的开关状态。2:on 3:on表示在运行级别 2 和 3 下开机自启0:off表示级别 0 下不自启这很合理因为级别 0 是关机你总不希望系统在关机流程里还去尝试启动 sshd。有些服务还会显示成单独一段尤其是通过 xinetd 管理的服务输出风格不太一样。比如rexec on rlogin on这种情况下chkconfig --list直接给出的是“通过 xinetd 启用/停用”的状态控制方式和独立服务不完全一样。2.3 单独查一个服务并区分“开机自启”和“当前运行”指定服务名可以看某个服务的详细状态chkconfig --list sshd输出像这样sshd 0:off 1:off 2:on 3:on 4:on 5:on如果系统提示服务名不存在或没有 chkconfig 信息说明这个服务并不是由 SysV init 脚本管理的。这里我必须强调一个新手极易踩的坑chkconfig 输出的 on/off 只代表“下次开机时是否自动启动”跟服务当前是否在运行没有任何关系。要看当前运行状态得用service sshd status systemctl status sshd # 如果是 systemd 环境或者直接ps -ef | grep sshd ss -lntp | grep sshd我见过有人执行chkconfig sshd off然后问“为什么 sshd 还在跑”这不是命令失效而是这个操作本来就不会热卸载服务。它只是告诉系统下次重启的时候别再自动拉起 sshd。想要立刻停掉需要再加一句service sshd stop。3. 核心操作解析添加、删除、调整服务自启状态体检完了下面进入正题。我会从添加一个新服务开始一步一步把 chkconfig 的常用操作串起来。这里的每个操作我都建议你先在测试机上执行一遍再上生产毕竟开机自启配置改错了重启以后服务乱七八糟排查成本会比现在高很多。3.1 服务脚本里的“chkconfig 注释行”到底是什么chkconfig 并不是把/etc/init.d/下所有文件都当服务。它识别一个服务脚本有一个硬性前提脚本头部必须包含一段特殊格式的注释。典型的服务脚本开头长这样#!/bin/bash # chkconfig: 2345 80 20 # description: sshd is the OpenSSH daemon.第二行# chkconfig: 2345 80 20是核心它包含三部分信息2345默认在哪些运行级别启用80在对应 rc 目录里使用 S80 作为启动符号链接的序号戳20执行停止操作时使用 K20 作为停止符号链接的序号戳这段注释不是给人看的而是给 chkconfig --add 解析的。它回答了三个问题这个脚本支持哪些级别启动顺序排多少停止顺序排多少如果没有这一行执行chkconfig --add时会直接报错提示“服务不支持 chkconfig”所以自研脚本想接入 chkconfig 管理第一件事就是写好这个注释头。选择启动序号时有个通用原则依赖网络的服务排 60 之后中间件、数据库类服务排 80 左右基础网络服务在 1030。留出余量别把序号全挤在一起否则多个服务并行执行时顺序不对后启动的服务可能因为依赖项没起来而报错。3.2--add把一个服务纳入 chkconfig 管理假设我写了一个自研服务的启动脚本/etc/init.d/myapp脚本头部已经写好了 chkconfig 注释。接下里的操作顺序是chmod 755 /etc/init.d/myapp chkconfig --add myapp chkconfig --list myapp第一行给脚本加上执行权限没有执行权限chkconfig 即使建立了符号链接系统启动时也无法执行脚本。第二行让 chkconfig 读取脚本头部注释并按照注释里的级别和序号在对应 rc 目录里创建 S 开头的符号链接。第三行验证结果。执行--add之后你可以在 rc3.d 目录里直接验证链接是否生成ls -l /etc/rc.d/rc3.d/ | grep myapp正常情况下会看到类似S80myapp - ../init.d/myapp的符号链接。S80 中的 80 就是脚本注释行里指定的启动序号。另外一个细节--add不只是新增它还承担“重新生成默认配置”的功能。如果某个服务的符号链接被手工改乱了重新执行--add会根据脚本注释重置默认状态这也是后面排错时的修复手段之一。3.3on/off切换服务在各个级别的自启状态添加完服务后想要快速开启或关闭自启直接用chkconfig myapp on chkconfig myapp off不带--level参数时on/off作用于脚本注释行里2345指定的所有级别。也就是说chkconfig myapp off会把这几个级别里的 S 链接改成 K 链接chkconfig myapp on则把对应级别的链接恢复为 S。如果只想修改特定级别用--level指定例如只在级别 3 和 5 开启chkconfig --level 35 myapp on这个命令非常实用。比如图形桌面环境不常用但服务器跑在级别 3就可以只让服务在 3 和 5 下自启而级别 2、4 保持关闭避免在维护模式或自定义级别里额外拉起服务。reset子命令也是一个隐藏工具chkconfig --level 35 myapp reset它会把指定级别的状态恢复成脚本注释行里的默认值。如果脚本已经删了--list查不到reset 也就无从谈起。这个命令适合你手欠改乱了配置想一键回到标准状态时使用。3.4 调整服务启动优先级控制开机执行顺序前面提到的启动序号80、20决定了服务在开机执行时的先后顺序。chkconfig 本身不直接提供“把序号改成 85”这样的子命令要改序号只能编辑/etc/init.d/myapp脚本头部的注释行然后重新添加服务。具体操作vim /etc/init.d/myapp # 把 # chkconfig: 2345 80 20 改成 # chkconfig: 2345 85 15 chkconfig --del myapp chkconfig --add myapp--del会把旧序号生成的符号链接全部清理掉--add再按新序号生成一批新的。这样服务在 rc3.d 目录里的链接名就会从S80myapp变成S85myapp启动顺序自然延后。这里要特别解释一下启动顺序的意义。开机脚本是按序号从小到大执行的数字越小越先执行。如果你的服务依赖数据库那数据库脚本的序号就要小于你的服务序号否则你的服务启动时连不上数据库可能直接启动失败。反过来如果两个服务的序号完全相同执行顺序就看 init 脚本的串行执行方式了在部分实现里不保证稳定所以规划序号时尽量错开 510 的间隔。3.5--del把服务移出 chkconfig 管理chkconfig --del myapp执行后rc 目录里所有指向/etc/init.d/myapp的符号链接都会被移除chkconfig --list myapp也就查不到这个服务了。需要说明的是--del只删除符号链接不会删除/etc/init.d/myapp这个脚本本身。这一点很像rpm -e不会删配置文件一样属于安全设计。如果你确实想让这个服务从系统里彻底消失再手动执行rm -f /etc/init.d/myapp但更稳妥的做法是先--del确认不再需要脚本后再把脚本文件移到备份目录不建议直接rm。老服务器上一个完整的服务脚本里可能还包含环境变量定义、启动参数逻辑删了再想恢复就得凭记忆重写十分痛苦。4. 我踩过的坑chkconfig 实战排错清单这一节全部来自真实环境里常见的问题。网上很多文章只讲命令怎么用不讲命令报错怎么处理。我把这些年维护老系统时遇到的高频问题整理成清单遇到直接按图索骥找答案。4.1 chkconfig: command not found原因就两个一是系统没装 chkconfig二是这个系统换代到了 systemd默认不带 SysV 管理工具。处理方式# 老版本发行版 yum install chkconfig # Debian 系 apt-get install chkconfig装完了再看chkconfig --list。假如是 systemd 环境安装 chkconfig 后你会发现很多服务根本列不出来因为那些服务是用 systemd unit 管理的chkconfig 看不到。这时候转型systemctl才是正解别在 chkconfig 上死磕。4.2 提示 “service xxx does not support chkconfig”这个报错几乎 90% 是因为服务脚本头部缺少有效注解。打开脚本看一眼head -20 /etc/init.d/xxx如果没有下面两行或者格式写错了# chkconfig: 2345 80 20 # description: xxx service补齐后再执行chkconfig --add xxx另外还要注意脚本的换行符必须是 Unix 格式LF不要拿 Windows 编辑器存成 CRLF。格式错误的话chkconfig 解析注释行时会失败报同样的错误。如果脚本里已经存在 chkconfig 注释却还是报不支持可以检查脚本首行#!/bin/bash是否正常以及文件是否有执行权限。4.3 使用 --add 之后--list 里却看不到这个服务这种情况通常不是命令没执行而是目录不对。chkconfig 默认扫描/etc/init.d/、/etc/rc.d/init.d/这些目录。如果你的脚本放在自定义路径比如/opt/myapp/init.d/chkconfig 根本不会去扫描。解决办法是把脚本放到标准位置或者创建软链接ln -s /opt/myapp/init.d/myapp /etc/init.d/myapp chmod 755 /opt/myapp/init.d/myapp chkconfig --add myapp还有另一个隐蔽原因脚本头部注释里指定的级别全是类似-或0这种无效值。chkconfig 添加成功但 rc 目录里没有为任何运行级别生成 S 链接--list里服务名就显示成空状态。检查注释行是否写成# chkconfig: - 80 20改为正常的 2345 等数字即可。4.4 服务明明设成了 off重启后却还是自动起来了这是最迷惑人的一个坑。chkconfig xxx off明明执行成功了重启后服务依然在跑。我排查过几次原因基本落在三类第一服务由 xinetd 托管。有些服务不是独立脚本而是挂在 xinetd 超级守护进程下。chkconfig --list xinetd会显示为 on/off 状态你要调整的是 xinetd 管理下的服务条目而不是直接操作服务本身的 SysV 脚本。通过chkconfig 服务名 off可能改的是另一个层面。第二其他启动机制接管了。现代系统上可能存在/etc/rc.local或 systemd 的残留配置里面直接用命令调用了服务的启动脚本。开机时 init 在启动完所有 SysV 服务后还会执行/etc/rc.local如果里面写了service xxx start就算 chkconfig 层面是关的服务照样会被拉起来。检查方式grep -i xxx /etc/rc.local第三服务被另一个脚本间接拉起了。比如应用 A 的启动脚本里有一句“如果应用 B 不在运行就启动应用 B”这种情况下单纯关掉 B 的自启状态还会被 A 在启动时拖带起来。排查时不能只看单个服务要看完整启动链。4.5 误删了某个服务怎么快速恢复误执行chkconfig --del之后如果脚本还在恢复非常容易chkconfig --add 服务名它会按脚本注释里的默认级别和序号重新生成链接等于一键恢复出厂状态前提是注释行没被改过。如果脚本也误删了那就只能看备份了。所以我在老服务器上操作前习惯把 rc 目录里的符号链接清单提前备份一份ls -l /etc/rc.d/rc*.d/ /tmp/rc_links_backup.txt这个文件不占多少空间但遇到回滚场景时能帮你快速重建符号链接关系比对着文档猜可靠得多。4.6 常用命令速查表目标命令查看所有服务自启状态chkconfig --list查看单个服务状态chkconfig --list 服务名按默认配置添加服务chkconfig --add 服务名设置指定级别自启chkconfig --level 35 服务名 on关闭指定级别自启chkconfig --level 35 服务名 off全部常用级别自启chkconfig 服务名 on全部常用级别关闭chkconfig 服务名 off恢复默认状态chkconfig --level 35 服务名 reset移除服务管理chkconfig --del 服务名5. chkconfig 与现代 systemd 的对照迁移很多读者现在的主力环境已经是 systemd看到 chkconfig 可能觉得没必要学。这个想法有一定道理但现实是大量老系统还在服役你迟早会碰到。把两者对照着理解能少走很多弯路。5.1 核心功能对照表操作SysV / chkconfigsystemd / systemctl查看服务自启状态chkconfig --listsystemctl list-unit-files --typeservice单个服务自启状态chkconfig --list 服务名systemctl is-enabled 服务名设置开机自启chkconfig 服务名 onsystemctl enable 服务名关闭开机自启chkconfig 服务名 offsystemctl disable 服务名立即启动service 服务名 startsystemctl start 服务名立即停止service 服务名 stopsystemctl stop 服务名查看运行状态service 服务名 statussystemctl status 服务名能看到两者在逻辑上是一一对应的。chkconfig 维护 rc 目录符号链接systemctl 维护的是/etc/systemd/system、/usr/lib/systemd/system下的 unit 文件及其 enable/disable 状态。理念变了但“配置开机时是否启动”这个目标没变。5.2 在新系统上偶尔还会碰到 chkconfig 的场景即使默认 init 是 systemd有些新系统为了兼容老脚本仍然会安装 chkconfig 兼容包。执行chkconfig --list时部分 SysV 服务名称仍然能显示出来但这些只是兼容层。调整这些服务自启状态最终还是会映射到 systemd 的机制上。我遇到过的最典型场景是给老客户做系统迁移从旧版本迁到新版本应用侧还依赖 chkconfig 做安装后配置。安装脚本里写的是chkconfig --add myapp chkconfig myapp on迁移到 systemd 新环境后如果系统里没有兼容层安装脚本会直接失败。这种时候要么在脚本里加一层 systemd 判断要么在目标机上补装兼容包。作为运维你得心里有底不是“新系统不能再用 chkconfig”而是“要看你装的那个兼容包到底干了什么”。5.3 老经验迁移到新平台时的一点建议如果你是从 chkconfig 时代过来的人切换到 systemctl 初期最容易踩的坑是混淆enable和start。systemctl enable对应 chkconfig on只改开机自启systemctl start对应 service start立即生效。所以在新系统上排查服务起不来要同时看is-enabled和is-active两个维度别像以前一样只查 chkconfig --list 就完事。反过来如果你先学的是 systemctl再回头用 chkconfig也请记住chkconfig --list 显示的是“自启配置”不是“当前活动状态”。这是两套机制最本质的认知差异把它刻在脑子里踩坑概率能少一半。从最初接触 chkconfig 到现在我个人最大的体会是这类命令的学习核心不在于记住多少参数而是理解它背后管理的是哪些文件和状态。chkconfig 管的是符号链接systemctl 管的是 unit 文件理解了这一层换再新的系统也不怕。最后再分享一个习惯每次改完 chkconfig 配置我都会立即执行chkconfig --list 服务名验证一遍再重启一次测试机确认结果绝不只靠命令输出就判断“应该没问题”。做系统管理验证永远比配置更重要。