我有一个 systemd 服务,它是一个控制台应用程序,这意味着它是通过向其 stdin 发送命令来控制的,并将信息输出到 sdout。如何设置 systemd 服务,以便我可以连接到其标准输入并随时向其发出命令,然后与之分离,并在必要时重复?
答案1
我可以想出多种方法来做到这一点。当然,每个都有其自己的注意事项。
最直接的方法可能是创建一个带有专用 tty 的简单服务,类似于:
# /etc/systemd/system/systemd-interactive-simple-tty.service [Unit] Description=Example systemd interactive simple tty service After=getty.service [Service] # https://www.freedesktop.org/software/systemd/man/systemd.exec.html ExecStart=/usr/local/sbin/systemd-interactive.bash StandardInput=tty-force TTYVHangup=yes TTYPath=/dev/tty20 TTYReset=yes # https://www.freedesktop.org/software/systemd/man/systemd.service.html Type=simple RemainAfterExit=false Restart=always RestartSec=5s [Install] WantedBy=default.target
以下选项将与上述简单服务一起使用:
密谋(远程)控制文本模式虚拟控制台。这可能是你最好的选择(使用上面的 tty 服务)。它可以通过大多数扩展包存储库获得,并且使用起来很简单,如下所示:
conspy 20 # hit ESC+ESC+ESC (3 times quickly, to exit)
奇夫特工作方式与 /dev/ttyN 类似,
conspy
但使 /dev/ttyN 成为前台(本地)终端。它是的一部分知识库集合,并且默认安装在几乎每个现代 Linux 发行版上。这就是为什么我认为值得一提。主要的警告chvt
是它要求您使用附带的键盘,这可能不是您想要的。对于上面的服务示例,chvt
可以这样使用:chvt 20 # ALT+F1 to return to /dev/tty1
雷普特尔使用
ptrace(2)
系统调用附加到远程程序(通过它的 PID)。这是与conspy
&完全不同的方法chvt
,但也适用于上述服务定义。请记住
reptyr
,它本身并不真正支持“分离”。它的 termcap 支持也不是很强大。通常,reptyr
与屏幕和/或多路复用器因为它们提供了一种更无缝的“分离”方式;我发现reptyr
这是一个很棒的利基工具,可以将现有的 PID 移动到screen
会话、tmux
窗口或窗格中。也就是说;我把这个选项放在这里,尽管是最后,因为它仍然可以在
reptyr
没有screen
or 的情况下使用tmux
。主要的警告是,如果您中断该进程(例如 ^C),而不是将其(再次)重新复制到另一个 tty/pty(通过另一个 shell)。向进程发送中断可能会导致其中止,我相信您知道其余的事情。也许这没关系,特别是如果该进程不重要并且 systemd 服务配置为
Restart=always
如我上面所示。如果进程“中断”,那么 systemd 将自动重新启动它(systemd 的另一个很酷的功能!)。也有不同的值Restart
。 YMMV。reptyr
可通过大多数扩展包存储库获得并可以使用,如下所示:reptyr $(systemctl status systemd-interactive-simple-tty.service | grep Main\ PID | awk '{print $3}') # or just reptyr <pid>
另一种(更复杂[意味着有更多可能失败])方法是使用 screen 创建分叉服务,类似于:
# /etc/systemd/system/systemd-interactive-forking-screen.service [Unit] Description=Example systemd interactive forking screen service [Service] # https://www.freedesktop.org/software/systemd/man/systemd.exec.html ExecStartPre=-/usr/bin/screen -X -S ${SCREEN_TITLE} kill # [optional] prevent multiple screens with the same name ExecStart=/usr/bin/screen -dmS ${SCREEN_TITLE} -O -l /usr/bin/bash -c /usr/local/sbin/systemd-interactive.bash # https://www.freedesktop.org/software/systemd/man/systemd.service.html Type=forking Environment=SCREEN_TITLE=systemd-interactive RemainAfterExit=false Restart=always RestartSec=5s SuccessExitStatus=1 [Install] WantedBy=default.target
屏幕是一个全屏窗口管理器,它在多个进程之间复用一个物理终端。它比第一个简单选项中列出的任何内容都要复杂得多。就我个人而言,我已经使用屏幕很长时间了,并且感觉足够舒服,可以信任它来处理大多数事情。这是一个非常宝贵的工具。
与上述相比,主要优点是良好的 termcap 支持(尽管不如 tmux)。这只是意味着您的退格键、箭头等将比使用
conspy
或更好地工作reptyr
。screen
可以通过大多数根据包存储库,并且可以像这样使用:screen -r systemd-interactive # CTRL-A+D to detach
与分叉屏幕类似的方法是 fork
tmux
。的 systemd 服务tmux
与 的 systemd 服务几乎相同screen
。但是,我不会详细说明这一点,因为,已经很晚了而且我累了。是的,我用tmux
很多超过screen
(这些天)。事实上,我
tmux
现在正在 neovim 窗格中写这篇文章。但是,我仍然使用了screen
很长时间。根据我的经验和观点,tmux
对于这样的事情来说有点矫枉过正。 Suretmux
更新,具有更多功能,并且是一个更好的 shell 多路复用器,screen
但是……它甚至更复杂。伴随着额外的复杂性而来的是一些额外的不稳定。更重要的是,至少对我来说,
tmux
崩溃比屏幕更频繁。我将 screen 列为 #2,因为如果是我,对于类似的事情,我可能只会将 #1 与conspy
.取决于您的计划;命名管道...systemd 服务也支持它们! IE
StandardInput=/path/to/named/pipe|
... 和更多。
答案2
对我来说更简单的屏幕解决方案:
地点:
/home/someUser/.config/systemd/user/some.service
内容:
[Unit]
Description=someServer
Wants=network.target
After=network.target
[Service]
ExecStart=screen -S screenName -D -m /home/someUser/startServer.sh
[Install]
WantedBy=default.target