Systemdサービスは終了せずに実行されます


30

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

systemdはプロセスを開始し、を使用してType=forkingいる場合は別のプロセスをフォークすることを期待します。さらに、execStartシェル拡張として実行されないため&、最後にバックグラウンドフラグとして認識されることはありません。
-grochmal

私の悪いは、私がそれをテストしていました。それでは、タイプはシンプルでなければなりませんか?
madmanali93

2
私が間違っていなければ、jekyllはrailsタイプのもの、つまりrubyの小さなwebyサーバーです。ええ、Type=simple適切です。また、これは私がrootとして実行するアプリケーションの種類ではありません。少なくともインターネットに接続されたマシンではそうではありません(あなたのケースではないかもしれません)。
-grochmal

簡単に働いてくれてありがとう。また、このコマンドは、Apache用の静的htmlを生成して、jekyllがサーバー上で機能しないようにします。ルートとして実行すれば問題ないはずです。しかし、それを議論していたかどうかはわかりません。
madmanali93

ああ、それがそうです--incremental:)。ええ、ルートとしてファイルを再生成してもセキュリティ上の問題はありません。もちろん、これらのファイルはユーザー指定ではありません。
-grochmal

回答:


54

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

  • simple -自己をバックグラウンド化せず、シェルに接続されたままである長時間実行プロセス。
  • forking -自身をフォークして、それを実行したプロセスから切り離し、事実上バックグラウンドを行う典型的なデーモン。
  • oneshot -終了が予想される短命のプロセス。
  • dbus -シンプルに似ていますが、プロセスの起動完了の通知はdbus経由で送信されます。
  • notify -シンプルに似ていますが、プロセスの起動完了の通知はinotify経由で送信されます。
  • idle -シンプルに似ていますが、ジョブがディスパッチされた後にバイナリが開始されます。

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

代わりに、Type=simpleデフォルトのを使用して、行を完全に削除して同じ効果を得ることができます。このモードでは、systemdはプロセスの起動が完了するのを待たず(これがいつ発生したかを知る方法がないため)、すぐに依存サービスを実行し続けます。あなたの場合は何もないので、これは問題ではありません。

セキュリティに関する小さなメモ:

ルートとしてサービスを実行していますが、これは非特権ユーザーとして実行するよりも安全性が低いため推奨されません。その理由は、コマンドの実行を何らかの方法で許可するjekyllの脆弱性がある場合(おそらく解析中のコードを介して)、攻撃者はシステムを完全に所有するために他に何もする必要がないからです。一方、非特権ユーザーとして実行されている場合、攻撃者はそのユーザーと同程度の損害しか与えられず、システムを完全に所有するためにルート権限を取得する必要があります。ただし、攻撃者が行かなければならない余分なレイヤーを追加するだけです。

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

ただし、単にこのサーバーから静的ファイルを提供し、サーバーを最新の状態に保つ場合、これらの攻撃は非常に起こりそうにありませんが、可能です。システムの重要度に基づいて、リスクとセットアップのオーバーヘッドを比較検討するのはお客様の責任ですが、これらのヒントはどちらもセットアップが非常に簡単で、メンテナンスオーバーヘッドがほとんどありません。


0

@ Michael Daffinのソリューションに加えて、デーモン化ツールを使用forkingして、次の例に示すように使用を実現することもできます。

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

#!/bin/bash

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

まだお持ちでない場合は、次のようにdaemonizeをインストールしてください。

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


systemdがサービスを開始する代わりにdaemonize+ を使用する利点は何ですか?forkに書き込まれるレガシープログラムをサポートするためのsystemdの一種の互換性設定です。Type=forkingType=simpleType=forking
ヨハンマイレン

それは同等の解決策だと思います。OPに代替ソリューションを提供し、プロセスをデーモン化する方法に関する質問でもあるため、/ etc / init.dで既に使用したこのツールを彼に認識させたかっただけです。
マイケル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.