我找到了这个 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 重启后存活下来的,但这是另一个话题。