我一直在解决 sysVinit 服务在 systemd 环境中启动时无法正常上线的问题。我发现,当/etc/systemd/system/
所述服务不存在服务文件或覆盖时,它会正确自动启动。在这种情况下,据我了解,systemd 应该通过读取系统上存在的“遗留”sysvinit 脚本来动态加载启动脚本,尽管我对此不是 100% 清楚。
我感到困惑的是,一旦我将 edit --full 选项传递给所述服务的 systemctl,就会生成一个平面文件,/etc/systemd/system/
并且所述服务现在无法在启动时自动启动。使用编辑选项并尝试添加任何覆盖似乎也会导致服务无法启动。
如果需要,示例如下...
系统工作时的示例
服务(在 Centos 上),在本例中称为“ProgramExample”,有一个 init 脚本放置在/etc/init.d/programexample
和 中/etc/rc.d/init.d/programexample
:
# ls -l /etc/rc.d/init.d/programexample
-rwxr-xr-x. 1 root root 2264 Mar 29 14:11 /etc/rc.d/init.d/programexample
不存在服务文件/etc/systemd/system/
:
# ls -lh /etc/systemd/system/programexample.service
ls: cannot access /etc/systemd/system/programexample.service: No such file or directory
此配置中的 Systemctl 状态输出:
# systemctl status programexample.service
● programexample.service - LSB: Start Program Example at boot time
Loaded: loaded (/etc/rc.d/init.d/programexample; bad; vendor preset: disabled)
Active: active (exited) since Wed 2017-03-29 15:53:06 CDT; 14min ago
Docs: man:systemd-sysv-generator(8)
Process: 1297 ExecStart=/etc/rc.d/init.d/programexample start (code=exited, status=0/SUCCESS)
Mar 29 15:53:05 centos7-box systemd[1]: Starting LSB: Start ProgramExample at boot time...
Mar 29 15:53:05 centos7-box su[1307]: (to programexample) root on none
Mar 29 15:53:06 centos7-box programexample[1297]: ProgramExample (user programexample): instance name set to centos7-box
Mar 29 15:53:06 centos7-box programexample[1297]: instance public base uri set to https://192.168.0.148.programexample.net/programexample/
Mar 29 15:53:06 centos7-box programexample[1297]: instance timezone set to US/Central
Mar 29 15:53:06 centos7-box programexample[1297]: starting java services
Mar 29 15:53:06 centos7-box programexample[1297]: ProgEx server started.
Mar 29 15:53:06 centos7-box systemd[1]: Started LSB: Start ProgramExample at boot time.
通过上述配置,无需在 /etc/systemd/system/ 中创建/放置任何文件,ProgramExample 服务即可正常自动启动。
使用一次systemctl edit --full
(或仅):edit
将任何编辑传递给 systemctl 后,我观察到以下情况:
- 平面文件或覆盖目录将放置在 /etc/systemd/system/ 中
- 所述服务(在本例中为 ProgramExample)无法在引导时启动。
- 我将无法使用 systemctl“启用”所述服务
此配置中的 Systemctl 状态输出(编辑后):
# systemctl status programexample.service
● programexample.service - LSB: Start ProgramExample at boot time
Loaded: loaded (/etc/rc.d/init.d/programexample; static; vendor preset: disabled)
Active: inactive (dead)
Docs: man:systemd-sysv-generator(8)
/etc/systemd/system/
这是使用选项时生成并放置的服务文件edit --full
:
# Automatically generated by systemd-sysv-generator
[Unit]
Documentation=man:systemd-sysv-generator(8)
SourcePath=/etc/rc.d/init.d/programexample
Description=LSB: Start ProgramExample at boot time
Before=runlevel2.target
Before=runlevel3.target
Before=runlevel4.target
Before=runlevel5.target
Before=shutdown.target
Before=adsm.service
After=all.target
After=network-online.target
After=postgresql-9.4.service
Conflicts=shutdown.target
[Service]
Type=forking
Restart=no
TimeoutSec=5min
IgnoreSIGPIPE=no
KillMode=process
GuessMainPID=no
RemainAfterExit=yes
ExecStart=/etc/rc.d/init.d/programexample start
ExecStop=/etc/rc.d/init.d/programexample stop
ExecReload=/etc/rc.d/init.d/programexample reload
这里发生了什么?我是否正确,如果没有 /etc/systemd/system/ 中的平面服务文件和/或服务覆盖目录,systemd 会从所述服务的初始化脚本动态读取此信息?我已经尝试多次迭代编辑 /etc/systemd/system/ 中的服务文件并将默认文件保留在适当的位置,但无法自动启动工作或服务进入“启用”状态。
我相信出于兼容性和并发性原因,最好为 systemd 配置提供一个 systemd .service 文件,而不是依赖 systemd 从初始化脚本 LSB 标头中读取,但 systemd 创建的默认文件无法启动或与许多其他文件一起启用我尝试过的 .service 文件的更简单的迭代。
答案1
我现在发现问题是 systemd-sysv-generator 自动生成的服务文件缺少带有 WantedBy 选项的安装部分。我将以下内容添加到 /etc/systemd/system/programexample.service 生成的文件中,这使我能够正确启用该服务:
[Install]
WantedBy = multi-user.target
之后我跑了
systemctl daemon-reload
确保 systemd 读取我的服务文件。
现在我收到了一条正确的通知,表明我的服务实际上已在某个地方进行了符号链接以“启用”:
[root@centos7-box ~]# systemctl enable programexample.service
Created symlink from /etc/systemd/system/multi-user.target.wants/programexample.service to /etc/systemd/system/programexample.service.
这个链接帮助我更好地理解服务文件。
我不喜欢 systemd-sysv-generator 默认情况下不包含带有 WantedBy 选项的安装部分。如果 systemd 可以动态读取 LSB 标头并在启动时正确启动服务,为什么它不相应地生成服务文件?我想 systemd 会遇到一些成长的烦恼是可以预料的。
2020 年 7 月 7 日更新:
在与 Debian Buster 合作并尝试启用 SysVInit 遗留服务时,我收到了这条精彩的消息,我相信这会为我在 2017 年处理此问题时节省一些时间:
Synchronizing state of programexample.service with SysV service script with
/lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable programexample
The unit files have no installation config (WantedBy=, RequiredBy=, Also=,
Alias= settings in the [Install] section, and DefaultInstance= for template units).
This means they are not meant to be enabled using systemctl.
Possible reasons for having this kind of units are:
• A unit may be statically enabled by being symlinked from another unit's
.wants/ or
.requires/ directory.
• A unit's purpose may be to act as a helper for some other unit which has
a requirement dependency on it.
• A unit may be started when needed via activation (socket, path, timer,
D-Bus, udev, scripted systemctl call, ...).
• In case of template units, the unit is meant to be enabled with some
instance name specified.
答案2
就我而言,该问题是由于系统上有 2 个不同的 java 版本引起的,其中一个版本(Oracle JDK)后来安装在我系统中的 jenkins 上。我确实运行了alternatives -config java命令并将java设置为与jenkins一起安装的开放jdk版本。并重新启动詹金斯服务器服务。就是这样。