介绍

介绍

我尝试编写一个自定义服务文件。

不幸的是我在 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

一些问题

  1. ssh 是分叉在它启动之后。
  2. ssh 隧道应该在后台运行
  3. systemd 进程默认以“简单”类型运行 - 它期望 StartExec 中的命令是主要服务(参见“1”)
  4. 很多时候,systemd 需要 PIDFile 才能知道你的服务是否处于活动状态。GuessMainPID 默认为是,但可能是,并且关于 ssh,错了。
  5. 你可以在当地摧毁隧道——无需带着剑去国外

这引入了很多复杂性,最好通过包装脚本来处理。

/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 文件。

致谢https://stackoverflow.com/a/15198031/2045924

答案2

这句话User=autossh是个错误。

该用户不存在。

创建用户后它就起作用了。

默认Type=simple工作得很好。

不需要包装脚本。

相关内容