システムサービスは終了せずに実行されます。

システムサービスは終了せずに実行されます。

私はjekyllの独自のサービスを作成し、サービスを開始するときに強制終了する必要があるため、バックグラウンドプロセスとして実行されていないようctrlですc。 --watchのため、フォアグラウンドにとどまります。それをバイパスし、バックグラウンドで実行する方法を知りません。どんなアイデアがありますか?

# /etc/systemd/system/jekyll-blog.service

[Unit]
Description=Start blog jekyll

[Service]
Type=forking
WorkingDirectory=/home/blog
ExecStart=/usr/local/bin/jekyll build --watch --incremental -s /home/blog -d /var/www/html/blog &
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
User=root
Group=root

[Install]
WantedBy=multi-user.target

答え1

Systemdは、さまざまな種類のサービス、特に次のいずれかを処理できます。

  • simple- 自分をバックグラウンドに置かずにシェルに接続したままにする長期実行プロセスです。
  • forking- 自分をフォークして実行中のプロセスから分離し、効果的にバックグラウンドに配置する一般的なデーモンプロセスです。
  • oneshot- 終了すると予想される短期プロセスです。
  • dbus- 単純ですが、プロセス開始完了通知がdbusを介して送信されます。
  • notify- シンプルだがプロセス開始完了通知がinotifyを介して送信されます。
  • idle- 単純さと同じですが、ジョブが渡された後にバイナリが起動します。

お客様が選択した場合、Type=forkingこれは systemd がプロセス自体が分岐し、親プロセスが終了するのを待っていることを意味します。これは、プロセスが正常に開始されたことを示します。ただし、プロセスはこれを行いません。プロセスはフォアグラウンドに残るため、systemctl start無期限に停止するか、プロセスがクラッシュするまで停止します。

代わりにType=simpleこれがデフォルトなので、ラインを完全に削除して同じ効果を得ることができます。このモードでは、systemdはプロセスの開始が完了するのを待ちません(これが起こるのかわからないため)、すぐに実行および依存サービスを続行します。あなたの場合ではないので、それは問題ではありません。

セキュリティに関する小さな注意:

サービスをrootとして実行しますが、権限のないユーザーとして実行するよりも安全性が低いため、使用しないことをお勧めします。その理由はもしどういうわけか、コマンドの実行を可能にするjekyllの脆弱性(おそらく解析中のコードを介して)は、攻撃者が他のアクションをとらずにシステムを完全に制御できるようにします。一方、権限のないユーザーとして実行している場合、攻撃者はそのユーザーと同じくらいダメージを与える可能性があり、システムを完全に制御するにはroot権限を取得しようとする必要があります。これは攻撃者が通過しなければならない追加の階層を追加するだけです。

Webサーバーを実行しているユーザーと同じユーザーとして簡単に実行できますが、そうすることで他の潜在的な攻撃にさらされる可能性があります。ユーザーがシステム上のファイルを操作できるようにするWebサーバーに脆弱性がある場合は、生成されたHTMLファイルまたは最悪の場合はソースファイルを変更して、サーバーが必要に応じてサービスを提供できます。ただし、結果ファイルとソースファイルをWebサーバーからのみ読み取ることができ、権限のない他のユーザーが書き込める場合は、Webサーバーを攻撃して簡単に変更することはできません。

ただし、そのサーバーで静的ファイルを提供し、サーバーを最新の状態に保つ場合、これらの攻撃はほとんど発生しませんが、それでも可能です。システムの重要性に応じて設定コストとリスクを比較するのはユーザーの責任です。しかし、両方のヒントはセットアップが非常に簡単で、メンテナンスコストがほとんどまたはまったく必要ありません。

答え2

また、@マイケル・ダフィンソリューションを使用することもできます。悪魔forking次の例のように使い方を達成するためのツールです。

systemdをデーモン化して制御したい小さなシェルスクリプトを次のように保存します/home/pi/testscript.sh

#!/bin/bash

while true;
do
    sleep 1
    echo -n "."
done

まだデーモンをインストールしていない場合は、次のようにインストールしてください。

sudo apt install daemonize

次に、ファイルサービス定義ファイルを作成します。

sudo vi /etc/systemd/system/testomat.service
# It is not recommended to modify this file in-place, because it will
# be overwritten during package upgrades. If you want to add further
# options or overwrite existing ones then use
# $ systemctl edit testomat.service
# See "man systemd.service" for details.

# copied from https://github.com/bitcoin/bitcoin/blob/master/contrib/init/bitcoind.service and modified by Michael 

[Unit]
Description=Test service
After=network.target

[Service]
ExecStart=daemonize -p /run/testomat/testomat.pid -o /home/pi/testscript.log /home/pi/testscript.sh
TimeoutSec=1200

# Make sure the config directory is readable by the service user
PermissionsStartOnly=true

# Process management
####################
Type=forking
PIDFile=/run/testomat/testomat.pid
Restart=on-failure
GuessMainPID = true

# Directory creation and permissions
####################################

# Run as pi:pi
User=pi
Group=pi

# /run/testomat
RuntimeDirectory=testomat
RuntimeDirectoryMode=0710

# /var/lib/testomat
StateDirectory=testomat
StateDirectoryMode=0710

# Hardening measures
####################

# Provide a private /tmp and /var/tmp.
PrivateTmp=true

# Mount /usr, /boot/ and /etc read-only for the process.
ProtectSystem=full

# Allow access to /home, /root and /run/user
# Chosing "false" is actually no hardening, this is just to demonstrate the usage of a service. Well, I could have omitted it. True. :)
ProtectHome=false

# Disallow the process and all of its children to gain
# new privileges through execve().
NoNewPrivileges=true

# Use a new /dev namespace only populated with API pseudo devices
# such as /dev/null, /dev/zero and /dev/random.
PrivateDevices=true

# Deny the creation of writable and executable memory mappings.
MemoryDenyWriteExecute=true

[Install]
WantedBy=multi-user.target

新しく作成されたサービスはsystemdで宣言する必要があります。

systemctl daemon-reload

これでサービスを開始でき、スクリプトが分岐します。予想通り、サービスはすぐにシェルに戻り始めます。結果は明らかです。

$ tail -f testscript.log 
.....................

関連情報