在早期的操作系统中,系统管理员很喜欢把一些操作系统启动时最后需要运行的脚本写在 /etc/rc.local 中,这个执行脚本(需要具有可执行属性)是操作系统启动时最后执行的启动脚本。

切换到RHEL/CentOS 7之后,systemd接管了init模式的启动脚本,实际上已经不再适合使用rc.local启动脚本。但是为了兼容一些老系统习惯,保留了一个称为 rc.lcoal.service 的服务来引用 /etc/rc.local

注意 :实际上systemd执行的并不是/etc/rc.local,而是/etc/rc.d/rc.local脚本,这个执行程序可以通过sudo systemctl status rc-local指令看到输出如下

● rc-local.service - /etc/rc.d/rc.local Compatibility
   Loaded: loaded (/usr/lib/systemd/system/rc-local.service; static; vendor preset: disabled)
   Active: active (exited) since Thu 2017-08-31 10:21:19 CST; 4 days ago

Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.

可以看到上述输出中采用的兼容rc.local的方法是配置了systemd配置文件/usr/lib/systemd/system/rc-local.service,其内容如下

[Unit]
Description=/etc/rc.d/rc.local Compatibility
ConditionFileIsExecutable=/etc/rc.d/rc.local
After=network.target

[Service]
Type=forking
ExecStart=/etc/rc.d/rc.local start
TimeoutSec=0
RemainAfterExit=yes

/etc/rc.local则是/etc/rc.d/rc.local的软链接:

$ls -lh /etc/rc.local
lrwxrwxrwx 1 root root 13 Jun 21 09:25 /etc/rc.local -> rc.d/rc.local

rc.local执行结果不一致问题排查

CentOS 7操作系统测试服务器,在/etc/rc.local中有2条指令分别设置CPU p-state governor:

x86_energy_perf_policy performance
cpupower frequency-set -g powersave

上述rc.local脚本仅作为测试案例,非真实使用。

但是启动后检查 cpupower frequency-info 输出显示,CPU governor 有时候显示performance,有时候又显示为powersave

按照rc.local脚本内容执行顺序,powersave应该覆盖performance,最终得到结果预期是powersave。但是偶然也出现performance生效,这说明还有其他设置在起作用,

  • 检查rc.local服务状态
#systemctl status rc.local
● rc.local.service
   Loaded: not-found (Reason: No such file or directory)
   Active: inactive (dead)
  • 检查/var/log/messages日志,其中显示有:
Jun 13 17:48:47 server.example.com systemd[1]: Starting /etc/rc.d/rc.local Compatibility...

这表明操作系统启动时执行了rc.local兼容模式

  • 注意,系统日志中还显示在执行rc.local同时还执行了Configure CPU power related settings
Jun 13 17:48:47 server.example.com systemd[1]: Started /etc/rc.d/rc.local Compatibility.
Jun 13 17:48:47 server.example.com systemd[1]: Started Configure CPU power related settings.

由于systemd为了加速系统启动,执行启动服务采用了并行模式,所以对于没有依赖关系的服务,启动先后顺序是不可预知的。这就带来了一个问题,同时有多处执行cpupower策略设置,如果配置相互矛盾,则执行结果不可预知。

通过stat /var/lock/subsys/local可以查看到rc.local执行的详细时间(该文件是rc.local执行时touch的文件可作为执行时间戳),对比systemctl status cpupower就可以看到是同一秒执行的两个程序,导致cpupower frequency-set -g <governor>结果不可控。

排查一

  • 在RHEL/CentOS 7平台是通过systemd管理cpupower,该服务读取了/etc/sysconfig/cpupower环境配置文件来设置CPU governor
  • systemd配置了rc-local.service兼容以往RHEL5/6的启动脚本/etc/rc.d/rc.local,但是systemd启动脚本是采用并行方式,所以rc.local.servicecpupower.service执行的先后顺序不固定
rc-local.service                                       loaded active exited    /etc/rc.d/rc.local Compatibility
  • 如果在rc.local中配置了和cpupower.service配置的governor不一致的设置,则不能保证正确执行 - 后执行的脚本设置将覆盖前一个脚本设置。

排查二

解决了上述systemd并发启动执行顺序问题,依然发现有某些服务器在执行rc.local时候出现没有执行cpupower frequency-set -g powersave。仔细排查发现,/etc/rc.local/etc/rc.d/rc.local脚本的软链接被破坏,/etc/rc.local被替换成一个实际的文本脚本。

这个问题的引发是因为在rpm包的SPEC文件的%post段落中,采用sed -i /powerManagement/d /etc/rc.local修订配置文件。但是,从RHEL/CentOS 7开始,/etc/rc.local是一个软链接文件。

sed在读取文件之前不会检查文件是否是软链接,所以sed转换之后覆盖原文件(sed相当于将原文件通过流方式过滤改成,然后通过管道生成临时文件,然后删除掉原文件,再将临时文件重命名成原文件)。这就导致了如果原文件是一个软链接,就会在修改后转变成实体文件。

GNU sed 提供了一个--follow-symlinks参数,可以检测修改的是软链接,而实现对软链接指向的实体文件的修改,避免破坏软链接。

详细排查参考如何避免sed -i破坏文件的软链接

参考

results matching ""

    No results matching ""