一年半后……

一年半后……

我找到了这个 systemd 服务文件来启动 autossh 来维持 ssh 隧道:https://gist.github.com/thomasfr/9707568

[Unit]
Description=Keeps a tunnel to 'remote.example.com' open
After=network.target

[Service]
User=autossh
# -p [PORT]
# -l [user]
# -M 0 --> no monitoring
# -N Just open the connection and do nothing (not interactive)
# LOCALPORT:IP_ON_EXAMPLE_COM:PORT_ON_EXAMPLE_COM
ExecStart=/usr/bin/autossh -M 0 -N -q -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" -p 22 -l autossh remote.example.com -L 7474:127.0.0.1:7474 -i /home/autossh/.ssh/id_rsa

[Install]
WantedBy=multi-user.target

有没有办法配置 systemd 在服务。

我不想创建 N 系统服务文件,因为我想避免复制粘贴。

除了“remote.example.com”将被其他主机名替换之外,所有服务文件都将相同。

一年半后……

我大约一年半前问过这个问题。

我的想法已经改变。是的,使用 systemd 可以做到这一点,这很好,但我将来会使用配置管理。

为什么 systemd 要实现一种模板语言并替换 %h?.. 我认为这没有意义。

几个月后,我认为应该从不同的层面解决这个循环和模板问题。我现在会使用 Ansible 或 TerraForm 来解决。

答案1

好吧,假设仅有的每个单位文件的变化是remote.example.com部分,你可以使用实例化 服务

systemd.unit手册页中:

可选地,单元可以在运行时从模板文件实例化。这允许从单个配置文件创建多个单元。如果 systemd 查找单元配置文件,它将首先在文件系统中搜索文字单元名称。如果没有成功,并且单元名称包含“@”字符,systemd 将查找共享相同名称但实例字符串(即“@”字符和后缀之间的部分)被删除的单元模板。例如:如果服务[电子邮件保护]被请求但未找到同名文件,systemd 将查找[电子邮件保护]如果找到,则从该配置文件实例化一个服务。

基本上,您创建一个单元文件,其中包含%i发生差异的变量(通常是),然后当您“启用”该服务时它们会链接起来。

例如,我有一个名为的单元文件,如下所示:/etc/systemd/system/[email protected]

[Unit]
Description=AutoSSH service for ServiceABC on %i
After=network.target

[Service]
Environment=AUTOSSH_GATETIME=30 AUTOSSH_LOGFILE=/var/log/autossh/%i.log AUTOSSH_PIDFILE=/var/run/autossh.%i.pid
PIDFile=/var/run/autossh.%i.pid
#Type=forking
ExecStart=/usr/bin/autossh -M 40000 -NR 5000:127.0.0.1:5000 -i /opt/ServiceABC/.ssh/id_rsa_ServiceABC -l ServiceABC %i

[Install]
WantedBy=multi-user.target

然后我启用了

[user@anotherhost ~]$ sudo systemctl enable [email protected]
ln -s '/etc/systemd/system/[email protected]' '/etc/systemd/system/multi-user.target.wants/[email protected]'

并且可以与

[user@anotherhost ~]$ sudo systemctl start [email protected]
[user@anotherhost ~]$ sudo systemctl status [email protected]
[email protected] - AutoSSH service for ServiceABC on somehost.example
   Loaded: loaded (/etc/systemd/system/[email protected]; enabled)
   Active: active (running) since Tue 2015-10-20 13:19:01 EDT; 17s ago
 Main PID: 32524 (autossh)
   CGroup: /system.slice/system-autossh.slice/[email protected]
           ├─32524 /usr/bin/autossh -M 40000 -NR 5000:127.0.0.1:5000 -i /opt/ServiceABC/.ssh/id_rsa_ServiceABC -l ServiceABC somehost.example.com
           └─32525 /usr/bin/ssh -L 40000:127.0.0.1:40000 -R 40000:127.0.0.1:40001 -NR 5000:127.0.0.1:5000 -i /opt/ServiceABC/.ssh/id_rsa_ServiceABC -l ServiceABC somehost.example.com

Oct 20 13:19:01 anotherhost.example.com systemd[1]: Started AutoSSH service for ServiceABC on somehost.example.com.
[user@anotherhost ~]$ sudo systemctl status [email protected]
[user@anotherhost ~]$ sudo systemctl status [email protected]
[email protected] - AutoSSH service for ServiceABC on somehost.example.com
   Loaded: loaded (/etc/systemd/system/[email protected]; enabled)
   Active: inactive (dead) since Tue 2015-10-20 13:24:10 EDT; 2s ago
  Process: 32524 ExecStart=/usr/bin/autossh -M 40000 -NR 5000:127.0.0.1:5000 -i /opt/ServiceABC/.ssh/id_rsa_ServiceABC -l ServiceABC %i (code=exited, status=0/SUCCESS)
 Main PID: 32524 (code=exited, status=0/SUCCESS)

Oct 20 13:19:01 anotherhost.example.com systemd[1]: Started AutoSSH service for ServiceABC on somehost.example.com.
Oct 20 13:24:10 anotherhost.example.com systemd[1]: Stopping AutoSSH service for ServiceABC on somehost.example.com...
Oct 20 13:24:10 anotherhost.example.com systemd[1]: Stopped AutoSSH service for ServiceABC on somehost.example.com.

如您所见,%i单元文件中的所有实例都被替换为somehost.example.com

还有更多说明符您可以在单元文件中使用它,但我发现%i在这种情况下效果最好。

答案2

这是一个 Python 示例,这正是我所寻找的。@服务文件名中的允许您启动 N 个进程:

$ cat /etc/systemd/system/[email protected]

[Unit]
Description=manages my worker service, instance %i
After=multi-user.target

[Service]
PermissionsStartOnly=true
Type=idle
User=root
ExecStart=/usr/local/virtualenvs/bin/python /path/to/my/script.py
Restart=always
TimeoutStartSec=10
RestartSec=10

有多种调用方法

启用各种计数,例如:

  • 启用 30 名工作人员:

    sudo systemctl enable my-worker\@{1..30}.service
    
  • 启用 2 个 worker:

    sudo systemctl enable my-worker\@{1..2}.service
    

然后一定要重新加载:

sudo systemctl daemon-reload

现在您可以通过多种方式启动/停止:

  • 开始 1:

    sudo systemctl start [email protected]
    
  • 开始多个:

    sudo systemctl start my-worker@{1..2}
    
  • 停止多个:

    sudo systemctl stop my-worker@{1..2}
    
  • 检查状态:

    sudo systemctl status my-worker@1
    

更新:要将实例作为一个服务进行管理,您可以执行以下操作:

/etc/systemd/系统/[电子邮件保护]

[Unit]
Description=manage worker instances as a service, instance %i
Requires=some-worker.service
Before=some-worker.service
BindsTo=some-worker.service

[Service]
PermissionsStartOnly=true
Type=idle
User=root
#EnvironmentFile=/etc/profile.d/optional_envvars.sh
ExecStart=/usr/local/virtualenvs/bin/python /path/to/my/script.py
TimeoutStartSec=10
RestartSec=10

[Install]
WantedBy=some-worker.service

/usr/bin/some-worker-start.sh:

#!/bin/bash
systemctl start some-worker@{1..10}

/etc/systemd/system/some-worker.service:

[Unit]
Description=manages some worker instances as a service, instance

[Service]
Type=oneshot
ExecStart=/usr/bin/sh /usr/bin/some-worker-start.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

现在您可以使用sudo systemctl some-worker (start|restart|stop)

以下是一些供您使用的样板script.py

#!/usr/bin/env python

import logging


def worker_loop():
    shutdown = False
    while True:

        try:
            if shutdown:
                break

            # Your execution logic here.
            # Common logic - i.e. consume from a queue, perform some work, ack message
            print("hello world")

        except (IOError, KeyboardInterrupt):
            shutdown = True
            logging.info("shutdown received - processing will halt when jobs complete")
        except Exception as e:
            logging.exception("unhandled exception on shutdown. {}".format(e))


if __name__ == '__main__':
    worker_loop()

答案3

GregL 的回答对我帮助很大。下面是我在代码中使用的单元模板示例,该模板使用了上面用于 gearman 作业服务器的示例。我编写了一个 shell 脚本,该脚本允许我使用这个模板创建 X 个“工作者”。

[Unit]
Description=az gearman worker
After=gearman-job-server.service

[Service]
PIDFile=/var/run/gearman_worker_az%i.pid
Type=simple
User=www-data
WorkingDirectory=/var/www/mysite.com/jobs/
ExecStart=/usr/bin/php -f gearman_worker_az.php > /dev/null 2>&1
Restart=on-success
KillMode=process

[Install]
WantedBy=multi-user.target

答案4

我已经搜索过类似任务的解决方案,实际上已经找到了一个,我相信它更容易完成,但应该是黑客(这里没有提到)

我需要在 vpn 创建隧道后创建多个 ssh 连接,因此我创建了一个依赖于 tun 设备并使用适当的命令调用 shell 脚本的服务。

服务 /etc/systemd/system/ssh_tunnel.service:

[Unit]
Description=Reverse SSH Service to access hidden services
ConditionPathExists=|/usr/bin
Wants=sys-devices-virtual-net-tun0.device
After=network.target sys-devices-virtual-net-tun0.device

[Service]
Type=forking
ExecStart=/bin/sh /etc/openvpn/ssh_tunnels.sh 
RemainAfterExit=yes
TimeoutSec=0
GuessMainPID=no

[Install]
WantedBy=multi-user.target

/etc/openvpn/ssh_tunnels.sh:

!/bin/bash
#sleep 15

echo 'Tunelling some ports'
killall -HUP ssh

su - user -c 'ssh -f [email protected] -p 9999 -L :3690:svn.newbox.ru:3690 -L :8888:10.1.20.55:80 -L :8181:10.1.10.10:80 -N -vvv'

ssh -i /home/user/.ssh/id_rsa -f [email protected] -p 9999 -L :587:mail.domain.ru:587 -L :995:mail.newbox.ru:995 -L :22:10.1.2.1:22 -N -vvv &

exit 0

结果:

# systemctl status ssh_tunnel.service
● ssh_tunnel.service - Reverse SSH Service to access hidden services
     Loaded: loaded (/etc/systemd/system/ssh_tunnel.service; enabled; vendor preset: disabled)
     Active: active (running) since Fri 2020-03-20 16:01:07 UTC; 22min ago
    Process: 156 ExecStart=/bin/sh /etc/openvpn/ssh_tunnel.sh (code=exited, status=0/SUC>
      Tasks: 2 (limit: 4915)
     Memory: 3.8M
     CGroup: /system.slice/ssh_tunnel.service
             ├─166 ssh -f [email protected] -p 9999 -L :3690:svn.newbox.ru:3690 -L :8888:10.1.20.55:80 ->
             └─168 ssh -i /home/user/.ssh/id_rsa -f [email protected] -p 9999 -L :587:mail.newbox.ru:5>
...

但是,我还没有检查它是如何在 vpn 重启后存活下来的,但这是另一个话题。

相关内容