1つのsystemdサービスファイルでNプロセスを開始します


36

sshトンネルを維持するためにautosshを起動する次のsystemdサービスファイルを見つけました: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

1つのサービスで複数のトンネルを開始するようにsystemdを構成する方法はありますか。

コピーと貼り付けを避けたいので、N個のシステムサービスファイルを作成したくありません。

「remote.example.com」が他のホスト名に置き換えられることを除いて、すべてのサービスファイルは同一です。

1.5年後...

およそ1.5年前にこの質問をしました。

私の心は少し変わりました。はい、それはsystemdでこれを行うことができます(私はまだ使用しています)が、将来は構成管理を使用します。

systemdがテンプレート言語を実装し、%hを置き換える必要があるのはなぜですか?

数か月後、構成を自動化するツールを使用して、このループとテンプレートを解決する必要があると思います。現在、ウィキペディアでこのリストのツールを1つ使用しています。


つまり、構成管理システムを使用して、ほぼ同じサービスファイルを複数生成し、このタスクを実行するということですか?うーん、多分。このような問題のほとんどと同様に、これらを区別する明確な境界線はありません。
pgoetz

@pgoetz config managementはまだ私にとっては新しいですが、この質問のトピックを見ると有益です:systemdサービスファイルを知っている誰もがそれを理解するでしょう: 。systemdだけでなく、/ etcのすべての構成に知識を使用できるため、構成管理システムを学習して使用する方が理にかなっていると思います。
ゲットリ

回答:


47

さて、ユニットファイルごとに変更されるのは部品だけであると仮定remote.example.comすると、Instantiated Serviceを使用できます。

systemd.unitmanページから:

必要に応じて、実行時にテンプレートファイルからユニットをインスタンス化できます。これにより、単一の構成ファイルから複数のユニットを作成できます。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

次に有効にしたもの

[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'

と相互作用することができます

[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.

ご覧のとおり%i、ユニットファイル内ののすべてのインスタンスはに置き換えられますsomehost.example.com

ただし、ユニットファイルで使用できる指定子は他にもたくさんありますが、%iこのような場合に最適です。


すごい、systemdは素晴らしい。
ゲットリ

起動するものを含め、ブート時に自動的に起動する方法は示しません。
クレイグヒックス

Systemdの場合、enableアクションは、起動時にユニット/サービスを開始させるものです。
GregL

インスタンスを個別に有効化/無効化できますか?
Soumya Kanti

ええ、それを有効/無効にするときにやっていることです。
GregL

15

これが私が探していたpythonの例です。@サービスのファイル名に使用すると、Nプロセスを開始することができます:

$ 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

呼び出すためのさまざまなメソッド

たとえば、さまざまなカウントを有効にします。

  • 30人のワーカーを有効にします。

    sudo systemctl enable my-worker\@{1..30}.service
    
  • 2人のワーカーを有効にします。

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

その後、必ずリロードしてください:

sudo systemctl daemon-reload

これで、さまざまな方法で開始/停止できます。

  • 開始1:

    sudo systemctl start my-worker@2.service
    
  • 複数開始:

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

    sudo systemctl stop my-worker@{1..2}
    
  • ステータスを確認します。

    sudo systemctl status my-worker@1
    

更新:インスタンスを1つのサービスとして管理するには、次のようにします。

/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

/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()

@radek:私が理解していない2つのこと:最初に、%iはユニットファイルの説明でのみ使用されます。開始コマンドはどのように開始するかをどのように知るのですか?第二に、どのsystemctl some-worker (start|restart|stop)インスタンスで作業するかをどのように知るのですか?
U.ウィンドル

%iは、サービスファイル名の@からの出力です。2番目の部分は既に回答で説明されていますNow you can start/stop then in various ways
radtek

スクリプトが関与していなければ、彼の答えは不完全だと思います。ほとんどの「魔法」は、欠落しているスクリプト内で行われます。
U.ウィンドル

ここで実際に完全に機能するソリューションを提供しました。どの「スクリプト」を参照していますか?/path/to/my/script.pyは、あなたが望むものなら何でもかまいません。キル信号を受信するまで実行し続ける何か。質問はpythonに固有のものではないことに注意してください。
radtek

うわー、一度に複数を開始できますか?心を吹き飛ばした...
rogerdpack

1

GregLの答えは私を大いに助けてくれました。以下は、ギアマンジョブサーバーに対して上記の例を使用してコードで使用したユニットテンプレートの例です。この1つのテンプレートを使用して、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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.