如何使用systemd在启动时运行单个命令?

我想在启动后使用以下命令启动一个Apache Spark集群:
sudo ./path/to/spark/sbin/start-all.sh

当系统准备重新启动/关机时,请运行此命令:

sudo ./path/to/spark/sbin/stop-all.sh

如何开始?有没有一个基本的模板可以作为起点?
我尝试使用一个非常简单的(文件:/lib/systemd/system/spark.service):
[Unit]
Description=Spark service

[Service]
ExecStart=sudo ./path/to/spark/sbin/start-all.sh

没用。

请查看:https://wiki.ubuntu.com/SystemdForUpstartUsers - user680858
1嗨@WillemK,我已经看过这个页面了。我发现的问题是我不能只是用ExecStart=替换exec。另外,我以前没有使用过upstart。 - macourtney7
2你脚本路径前面的那个点看起来非常可疑。 - Andrea Lazzarotto
@AndreaLazzarotto 我觉得OP试图以OP在终端中的方式运行脚本,所以才有了“.”... - George Udosen
嗨 @AndreaLazzarotto,这是正确的。对于造成的任何困惑,我表示道歉。 - macourtney7
@George 是的,我也这么认为。然而,在服务中使用相对路径可能会因为不同的路径而导致错误。我建议改用绝对路径。 - Andrea Lazzarotto
@AndreaLazzarotto,我一直在尝试使用绝对路径,但正如您在我的答案中所看到的那样,我遇到了绝对路径错误。.sh位于/usr/lib/spark-2.1/sbin/start-all.sh,这就是我提供的路径。这不是绝对路径吗? - macourtney7
@macourtney7,请查看我的更新,并附上一个可行的教程链接,其中包含更全面的systemd选项。 - George Udosen
3个回答

您的.service文件应该如下所示:
[Unit]
Description=Spark service

[Service]
ExecStart=/path/to/spark/sbin/start-all.sh

[Install]
WantedBy=multi-user.target

现在,再走几步来启用和使用.service文件:
  1. 将其放置在/etc/systemd/system文件夹中,命名为myfirst.service

  2. 确保您的脚本可执行:

    chmod u+x /path/to/spark/sbin/start-all.sh
  3. 启动它:

    sudo systemctl start myfirst
  4. 设置开机自启:

    sudo systemctl enable myfirst
  5. 停止它:

    sudo systemctl stop myfirst

注意事项

  1. 您不需要在服务中使用sudo来启动Spark,因为默认的服务用户已经是root。

  2. 请查看下面的链接以获取更多systemd选项。

此外

现在我们上面所提到的只是基本设置,这里是一个完整的Spark设置:

[Unit]
Description=Apache Spark Master and Slave Servers
After=network.target
After=systemd-user-sessions.service
After=network-online.target
 
[Service]
User=spark
Type=forking
ExecStart=/opt/spark-1.6.1-bin-hadoop2.6/sbin/start-all.sh
ExecStop=/opt/spark-1.6.1-bin-hadoop2.6/sbin/stop-all.sh
TimeoutSec=30
Restart=on-failure
RestartSec=30
StartLimitInterval=350
StartLimitBurst=10
 
[Install]
WantedBy=multi-user.target

设置服务:

sudo systemctl start spark.service
sudo systemctl stop spark.service
sudo systemctl enable spark.service

进一步阅读

请阅读以下链接。Spark是一个复杂的设置,因此您应该了解它如何与Ubuntu的init服务集成。


1谢谢你的建议,我根据你的建议创建了一个文件。在运行sudo systemctl start spark时,我收到了以下错误信息:无法启动spark.service:spark.service单元加载不正确:参数无效。请查看系统日志和'systemctl status spark.service'以获取详细信息。 - macourtney7
systemctl status spark.service 的主要部分如下:可执行路径不是绝对路径spark.service: 服务缺少 ExecStart= 和 ExecStop= 设置。拒绝。 - macourtney7
问题有三个:1)需要Spark二进制路径(应该替换服务文件中的内容),2)Spark有一个关闭命令,是什么?3)你看了我给你的链接吗?我不使用Spark,所以请提供它们。 - George Udosen
@GeorgeUdosen谢谢你的回答,我的问题是在重启之后如何以特定命令来运行Spark?问题在这里https://askubuntu.com/questions/979498/how-to-start-a-zookeeper-daemon-after-booting-under-specific-user-in-ubuntu-serv - Soheil Pourbafrani
请注意,现在应将用户和管理单元放置在 /etc/systemd/system 而不是 /lib/systemd/system。在 /lib/systemd 中无法使用 systemctl enable myservice。请参阅 https://unix.stackexchange.com/questions/206315/whats-the-difference-between-usr-lib-systemd-system-and-etc-systemd-system - Gabriel Glenn

将以下文本复制粘贴到终端(以root身份)中,创建/root/boot.sh脚本并设置开机自动运行:
bootscript=/root/boot.sh
servicename=customboot

cat > $bootscript <<EOF
#!/usr/bin/env bash
echo "$bootscript ran at \$(date)!" > /tmp/it-works
EOF

chmod +x $bootscript

cat > /etc/systemd/system/$servicename.service <<EOF
[Service]
ExecStart=$bootscript
[Install]
WantedBy=default.target
EOF

systemctl enable $servicename

要修改参数,例如使用不同的$bootscript,只需手动设置该变量并在复制命令时跳过该行。
运行完命令后,您可以使用您喜欢的编辑器编辑/root/boot.sh,它将在下次启动时运行。您也可以立即运行它,方法是使用以下命令:
systemctl start $servicename

1我对systemd文档有点困惑,但是不应该是Type=oneshot RemainAfterExit=yes吗?否则systemd会认为任务处于非活动状态,除非自定义脚本保留一些进程在运行。 - Peter Lamberg
@PeterLamberg 我也尝试阅读了systemd的文档,但我们现在都在这里;) 我记得它们并不是很清楚,但我发布的答案在多个系统上对我有效(每当我需要时,我会再次访问此页面)。你是说,因为它被认为是“非活动的”,每次连续的“启动”调用都会重新运行脚本吗?因为对于一个shell脚本来说,我认为这是可以预期的。如果在重新启动之前必须“停止”实际上并未运行的东西,我会觉得很奇怪。 - Luc

在systemd中添加启动项是复杂而繁琐的。为了使这更加方便,我编写了一个工具add_service,它提供了一种简单的方法来快速添加systemd的启动项。
安装:
pip3 install add_service

使用方法:

python -m add_service [shell_file/cmd] [user (default `whoami`)]

例子:

python -m add_service ssh_nat.sh  # by default user is `whoami`
python -m add_service "`which python3` -m http.server 80" root

这是你的脚本吗?如果是的话,请在回答中明确说明,无论是在这里还是在https://unix.stackexchange.com/a/687324/70524中。 - muru