用一个 systemd 服务文件启动 N 个进程

gue*_*tli 44 daemon systemd

我找到了这个 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
Run Code Online (Sandbox Code Playgroud)

有没有办法将 systemd 配置为在一个服务中启动多个隧道。

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

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

1.5年后...

我大约在 1.5 年前问过这个问题。

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

为什么 systemd 应该实现模板语言并替换 %h?..我觉得没有意义。

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

Gre*_*egL 51

好吧,假设每个单元文件唯一改变的是remote.example.com零件,您可以使用实例化 服务

systemd.unit手册页:

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

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

例如,我有一个名为的单元文件/etc/systemd/system/autossh@.service,如下所示:

[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
Run Code Online (Sandbox Code Playgroud)

然后我启用了

[user@anotherhost ~]$ sudo systemctl enable autossh@somehost.example.com
ln -s '/etc/systemd/system/autossh@.service' '/etc/systemd/system/multi-user.target.wants/autossh@somehost.example.com.service'
Run Code Online (Sandbox Code Playgroud)

并且可以互动

[user@anotherhost ~]$ sudo systemctl start autossh@somehost.example.com
[user@anotherhost ~]$ sudo systemctl status autossh@somehost.example.com
autossh@somehost.example.service - AutoSSH service for ServiceABC on somehost.example
   Loaded: loaded (/etc/systemd/system/autossh@.service; 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/autossh@somehost.example.com.service
           ??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 autossh@somehost.example.com
[user@anotherhost ~]$ sudo systemctl status autossh@somehost.example.com
autossh@somehost.example.com.service - AutoSSH service for ServiceABC on somehost.example.com
   Loaded: loaded (/etc/systemd/system/autossh@.service; 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.
Run Code Online (Sandbox Code Playgroud)

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

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

  • 哇,systemd 太棒了。 (2认同)

rad*_*tek 25

这是一个python示例,这正是我要找的。将@在该服务名让你开始数处理:

$ cat /etc/systemd/system/my-worker@.service

[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
Run Code Online (Sandbox Code Playgroud)

调用它的各种方法

启用各种计数,例如:

然后一定要重新加载:

sudo systemctl daemon-reload
Run Code Online (Sandbox Code Playgroud)

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

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

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

[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
Run Code Online (Sandbox Code Playgroud)

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

#!/bin/bash
systemctl start some-worker@{1..10}
Run Code Online (Sandbox Code Playgroud)

/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
Run Code Online (Sandbox Code Playgroud)

现在您可以管理所有实例 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()
Run Code Online (Sandbox Code Playgroud)