我尝试编写一个自定义服务文件。
不幸的是我在 journalctl 中没有看到输出。
这是我的单位文件:
root@om:~# cat /etc/systemd/system/ssh-tunnel-foo-de.service
[Unit]
Description=Tunnel For ssh-tunnel-foo-de
After=network.target
[Service]
User=autossh
ExecStart=/usr/bin/ssh -o "ExitOnForwardFailure yes" -o "ServerAliveInterval 60" -N -R 1080:localhost:1080 [email protected]
ExecStartPre=-/usr/bin/ssh [email protected] "for pid in $$(ps -u tunnel | grep sshd| cut -d' ' -f1); do kill -9 $$pid; echo kill old ssh process $$pid; done"
Restart=always
RestartSec=5s
StartLimitInterval=0
[Install]
WantedBy=multi-user.target
日志输出:
root@om:~# journalctl -u ssh-tunnel-foo-de
Apr 01 10:12:28 om systemd[1]: Stopped Tunnel For ssh-tunnel-foo-de.
Apr 01 10:12:28 om systemd[1]: Starting Tunnel For ssh-tunnel-foo-de...
Apr 01 10:12:28 om systemd[1]: Started Tunnel For ssh-tunnel-foo-de.
Apr 01 10:12:28 om systemd[1]: ssh-tunnel-foo-de.service: Main process exited, code=exited, status=217/USER
Apr 01 10:12:28 om systemd[1]: ssh-tunnel-foo-de.service: Unit entered failed state.
Apr 01 10:12:28 om systemd[1]: ssh-tunnel-foo-de.service: Failed with result 'exit-code'.
我该如何调试错误。我猜有些 stderr 输出丢失了。
答案1
介绍
你最初的问题是如何从 systemd 获得更多输出。请查看如何调试 systemd unit ExecStart
但是让我们先看看是否能让您的服务正常运行。
关于 systemd
一些问题
- ssh 是分叉在它启动之后。
- ssh 隧道应该在后台运行
- systemd 进程默认以“简单”类型运行 - 它期望 StartExec 中的命令是主要服务(参见“1”)
- 很多时候,systemd 需要 PIDFile 才能知道你的服务是否处于活动状态。GuessMainPID 默认为是,但可能是,并且是关于 ssh,错了。
- 你可以在当地摧毁隧道——无需带着剑去国外
这引入了很多复杂性,最好通过包装脚本来处理。
/etc/systemd/system/ssh-tunnel-foo-de.service
[Unit]
Description=Tunnel For ssh-tunnel-foo-de
After=network-online.target
[Unit]
Description=Tunnel For ssh-tunnel-foo-de
After=network-online.target
[Service]
User=autossh
ExecStart=/home/autossh/bin/ssh-tunnel.sh start
ExecStop=/home/autossh/bin/ssh-tunnel.sh stop
PIDFile=/home/autossh/bin/ssh-tunnel.pid
Restart=always
RestartSec=5s
StartLimitInterval=0
SuccessExitStatus=255
Type=forking
[Install]
WantedBy=multi-user.target
systemd 说明
包装器脚本将 pid 保存到 PIDFile。如果您更改位置,则必须保持服务文件和包装器脚本同步。
您必须将“类型”设置为 forking,以便 systemd 知道正在发生 fork。
SuccessExitStatus - 似乎进程在 255 时终止 - 因此我们处理这个问题,以便停止的服务在停止后不会被列为“失败”。
等待 network-online.target 启动。这意味着您实际上有一个网络连接,而不仅仅是一个网络管理堆栈。 https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/ https://www.freedesktop.org/software/systemd/man/systemd.unit.html#
包装脚本:
/home/autossh/bin/ssh-tunnel.sh
当然,您需要决定实际上想要将其放置在哪里并相应地修复路径。
#!/bin/bash
[email protected]
usage () {
echo "usage: $0 {start|stop}"
exit
}
cd $HOME/bin
case $1 in
"start")
/usr/bin/ssh -M -S socket-${MYHOST} -fnNT -o BatchMode=yes -o ExitOnForwardFailure=yes -o ServerAliveInterval=60 -R 1080:localhost:1080 ${MYHOST}
EC=$? ; [ $EC -ne 0 ] && exit $EC
PID=$(/usr/bin/ssh -S socket-${MYHOST} -O check socket-${MYHOST} 2>&1 | awk '/Master running \(pid=/ { sub(/^.+pid=/,"") ; sub(")","") ; print }')
echo $PID > $HOME/bin/ssh-tunnel.pid
;;
"stop")
/usr/bin/ssh -S socket-${MYHOST} -O exit ${MYHOST}
/bin/rm -f $HOME/bin/ssh-tunnel.pid
exit 0
;;
*) usage ;;
esac
一些解释:
查找 ssh 的一些参数。
- -M 和 -S 建立一个主连接和一个命名的套接字来控制主服务器。
- f-进入后台
- n – 防止从标准输入读取(-f 暗示)
- N——没有远程命令
- T – 禁用伪终端分配
“启动”部分设置隧道和“主控”。然后它向主控查询隧道的 pid,并将其保存到 pid 文件中,以方便 systemd 使用。如果以 root 身份运行,则可以保存到 /var/run/*pid。
“stop”部分连接到主服务器并发出“exit”。然后删除 pid 文件。
答案2
这句话User=autossh
是个错误。
该用户不存在。
创建用户后它就起作用了。
默认Type=simple
工作得很好。
不需要包装脚本。