systemd/User (日本語)
systemd はユーザーに systemd のインスタンスを実行させてサービスを管理できる機能を提供しています。これによって systemd がユーザーによって実行されている時、特定のディレクトリに入っているユニットをユーザーが起動・停止・有効化・無効化することが可能です。このことは root や特別なユーザーではなく普通のユーザーとして通常実行される mpd などのデーモン・サービスで重宝します。また、メールの取得などの作業を自動化することも可能です。さらに、多少の注意が必要ですが、ユーザーサービスから xorg やウィンドウマネージャを実行することもできます。
Contents
利用方法
ユーザーがログインを行うと、systemd は自動的にユーザーサービスを管理する systemd --user インスタンスを起動します。このプロセスは、そのユーザーにセッションが残っているかぎり生存し、ユーザーの最後のセッションが閉じられた時に終了します。systemd のユーザーインスタンスを自動起動している場合、インスタンスはブート時に起動し、終了しません。デフォルトではユーザーサービスは何も実行されません。ユーザーサービスを使うことで、ソケットアクティベーションやタイマー、システムの依存関係や cgroups によるプロセスの制限など、systemd の恩恵を最大限活用して、デーモンや自動化されたタスクを実行できます。ユーザーユニットはシステムサービスと同じように以下のディレクトリに配置されます (優先度が低い順):
-
/usr/lib/systemd/user/: インストールしたパッケージに含まれているサービス -
/etc/systemd/user/: システムの管理者が配置する、全てのユーザーが使えるユーザーサービス -
~/.config/systemd/user/: ユーザーが配置する、そのユーザーのサービス
systemd のユーザーインスタンスが起動すると、default.target ターゲットが立ち上がります。その後 systemctl --user を使って手動で systemd のユーザーインスタンスを制御できるようになります。
基本設定
Systemd のユーザーインスタンスはログイン時に自動で起動します。正しく起動していることを確認するには、次のコマンドを使います: systemctl --user status。
ユーザーサービスは全て ~/.config/systemd/user に配置してください。ログイン時にサービスを実行したい場合は、自動実行したいサービスごとに systemctl --user enable service を実行してください。
D-Bus
プログラムによっては D-Bus ユーザーメッセージバスを必要とすることがあります。D-Bus は伝統的に dbus-launch によってデスクトップ環境の起動時に実行されています。しかしながら、D-Bus に依存するプログラムを systemd のユーザーサービスとして使う場合、依存関係を解決するために D-Bus サーバーも systemd サービスとして実行する必要が出てきます。
D-Bus を systemd サービスとして設定するには、以下を行う必要があります:
1. dbus サーバーのサービスユニットとソケットユニットを /etc/systemd/user/ に追加:
/etc/systemd/user/dbus.socket
[Unit] Description=D-Bus Message Bus Socket Before=sockets.target [Socket] ListenStream=%t/dbus/user_bus_socket [Install] WantedBy=default.target
/etc/systemd/user/dbus.service
[Unit] Description=D-Bus Message Bus Requires=dbus.socket [Service] ExecStart=/usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation ExecReload=/usr/bin/dbus-send --print-reply --session --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
2. 環境変数 DBUS_SESSION_BUS_ADDRESS を設定。以下のファイルを作成して、user@.service の設定ファイルを使うことで設定できます:
/etc/systemd/system/user@.service.d/dbus.conf
[Service] Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%I/dbus/user_bus_socket
3. root で以下を実行してソケットを有効化:
# systemctl --global enable dbus.socket
環境変数
systemd のユーザーインスタンスは .bashrc などに設定された環境変数を全く継承しません。systemd インスタンスに環境変数を設定する方法は3つあります:
-
/etc/systemd/user.confでDefaultEnvironmentオプションを使う。全てのユーザーユニットに影響します。 -
/etc/systemd/system/user@.service.d/に設定ファイルを追加する。てのユーザーユニットに影響します。 - 適宜、
systemctl --user set-environmentやsystemctl --user import-environmentを使う。環境変数を設定した後に起動したユーザーユニットには影響しますが、既に起動しているユニットには影響しません。
設定するべき変数としては DISPLAY や PATH などが考えられます。
DISPLAY
DISPLAY は X アプリケーションがどのディスプレイを使えばいいのか知るために使用されます。systemd ユニットから X アプリケーションを起動するつもりならば、この変数を設定しなくてはなりません。例:
/etc/systemd/user.conf
... DefaultEnvironment=DISPLAY=:0 ...
PATH
PATH 変数を .bashrc や .bash_profile で設定しても systemd では使うことができません。PATH をカスタマイズしており、それを利用するアプリケーションを systemd ユニットから起動する予定があるなら、systemd 環境に PATH を設定する必要があります。PATH を .bash_profile に設定している場合、以下を PATH 変数を設定した後の .bash_profile に追加するのが systemd で PATH を設定する一番簡単な方法です:
~/.bash_profile
systemctl --user import-environment PATH
systemd のユーザーインスタンスを自動起動
systemd のユーザーインスタンスはデフォルトでユーザーの最初のログイン時に実行され、ユーザーのセッションが閉じられた時に終了します。しかしながら、ブートした直後にインスタンスを起動して、セッションが閉じられてもユーザーインスタンスを実行し続ける方が、例えばセッションが開いてない時もユーザープロセスを実行したいときなどには便利です。linger を利用してこれを行います。特定のユーザーで linger を有効にするには以下のコマンドを使用:
# loginctl enable-linger username
Xorg と systemd
systemd ユニットの中で Xorg を実行する方法は複数存在します。以下の2つは、xorg プロセスで新しいユーザーセッションを起動するというのと、systemd のユーザーサービスから xorg を起動するという方法です。
ディスプレイマネージャを使わずに Xorg に自動ログイン
こちらを選択した場合、xorg サーバーでユーザーセッションを起動してその後ウィンドウマネージャなどを起動するために通常の ~/.xinitrc を実行するシステムユニットを起動します。
D-Bus を適切に設定して xlogin-git をインストールする必要があります。
雛形のファイルから xinitrc を設定して、/etc/X11/xinit/xinitrc.d/ のファイルが読み込まれるようにしてください。~/.xinitrc は実行したときに戻ってこないようにする必要があるため、最後のコマンドとして wait を記述するか、(ウィンドウマネージャなど) exec を追加して戻ってこないようにしてください。
セッションは自らの dbus デーモンを使用しますが、systemd ユーティリティには dbus.service インスタンスが必要です。この問題を解決するにはコマンドのエイリアスを作成します:
~/.bashrc
for sd_cmd in systemctl systemd-analyze systemd-run; do
alias $sd_cmd='DBUS_SESSION_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/dbus/user_bus_socket" '$sd_cmd
done
最後に、(root で) xlogin を有効にして起動時に自動ログインするようにしてください:
# systemctl enable xlogin@username
ユーザーセッションが systemd の範囲の中に収まるようになってユーザーセッションの全てが問題なく動作するはずです。
systemd のユーザーサービスとしての Xorg
また、systemd のユーザーサービスの中から Xorg を実行することもできます。他の X 関連のユニットを Xorg などに依存させることができるという点では有利な一方、以下で説明するようにいくつか欠点が存在します。
バージョン 1.16 から xorg-server は systemd とのより良い統合を2つの手段で提供しています:
- デバイス管理を logind に委託することで、非特権でも実行することが可能に (このコミット など Hans de Goede のコミットを参照)。
- ソケットによってサービスを有効化することが可能に (このコミット を参照)。これによって systemd-xorg-launch-helper-git が不要に。
残念ながら、非特権モードで xorg を実行できるようにするには、セッションの中で xorg を実行する必要があります。そのため、今のところユーザーサービスとして xorg を実行するのには (1.16 以前と同じように) root 権限で実行する必要があるというハンディキャップがあり、1.16 で導入された非特権モードを活用することはできません。
以下がユーザーサービスから xorg を起動する方法です:
1. /etc/X11/Xwrapper.config を編集して、xorg が root 権限を使ってどのユーザーでも動作するようにします:
/etc/X11/Xwrapper.config
allowed_users=anybody needs_root_rights=yes
2. 以下のユニットを ~/.config/systemd/user に追加:
~/.config/systemd/user/xorg@.socket
[Unit] Description=Socket for xorg at display %i [Socket] ListenStream=/tmp/.X11-unix/X%i
~/.config/systemd/user/xorg@.service
[Unit]
Description=Xorg server at display %i
Requires=xorg@%i.socket
After=xorg@%i.socket
[Service]
Type=simple
SuccessExitStatus=0 1
ExecStart=/usr/bin/Xorg :%i -nolisten tcp -noreset -verbose 2 "vt${XDG_VTNR}"
${XDG_VTNR} は xorg が起動する仮想ターミナルで、サービスユニットでハードコードするか、以下のコマンドを使って systemd 環境で設定します:
$ systemctl --user set-environment XDG_VTNR=1
3. 上で説明されているように DISPLAY 環境変数を設定します。
4. 次に、display 0 と tty 2 で xorg のソケットアクティベーションを有効化します:
$ systemctl --user set-environment XDG_VTNR=2 # So that xorg@.service knows which vt use $ systemctl --user start xorg@0.socket # Start listening on the socket for display 0
これで X アプリケーションを実行すると仮想ターミナル2で自動的に xorg が起動します。
XDG_VTNR 環境変数は .bash_profile から systemd 環境に設定することができ、ウィンドウマネージャなど、あらゆる X アプリケーションを xorg@0.socket に依存する systemd ユニットとして起動することが可能です。
ユーザーユニットを書く
サンプル
以下は mpd サービスのユーザーバージョンの例です。
~/.config/systemd/user/mpd.service
[Unit] Description=Music Player Daemon [Service] ExecStart=/usr/bin/mpd --no-daemon [Install] WantedBy=default.target
変数を使用したサンプル
以下は sickbeard.service のユーザーバージョンの例で、SickBeard が特定のファイルを見つけられるようホームディレクトリの変数を使っています:
~/.config/systemd/user/sickbeard.service
[Unit] Description=SickBeard Daemon [Service] ExecStart=/usr/bin/env python2 /opt/sickbeard/SickBeard.py --config %h/.sickbeard/config.ini --datadir %h/.sickbeard [Install] WantedBy=default.target
man systemd.unit に書かれているように、%h 変数はサービスを実行しているユーザーのホームディレクトリに置き換えられます。他にも systemd のマニュアルページで示されている変数が存在します。
X アプリケーションについての注意
ほとんどの X アプリは実行するのに DISPLAY 変数を必要とします (あなたのサービスファイルが起動しない理由として第一に挙げられるでしょう)。systemd のユーザーインスタンスでこの変数を設定する方法は #DISPLAY を見て下さい。もしくは、以下のようにユニットでこの変数を設定することもできます:
~/.config/systemd/user/parcellite.service
[Unit] Description=Parcellite clipboard manager [Service] ExecStart=/usr/bin/parcellite Environment=DISPLAY=:0 [Install] WantedBy=mystuff.target
ユースケース
永続的なターミナルマルチプレクサ
ウィンドウマネージャのセッションにログインする代わりに、ユーザーセッションでデフォルトで GNU Screen や Tmux などのターミナルマルチプレクサをバックグラウンドで実行したいということもあるでしょう。X ログインとログインを分割するのはディスプレイマネージャの代わりに TTY で起動したい場合にのみ有用です (その場合すべてを myStuff.target で起動するように記述できます)。
上述のようなタイプのユーザーセッションを作成するには、wm.target を作成する代わりに、multiplexer.target を作成します:
[Unit] Description=Terminal multiplexer Documentation=info:screen man:screen(1) man:tmux(1) After=cruft.target Wants=cruft.target [Install] Alias=default.target
cruft.target, like mystuff.target above, should start anything you think should run before tmux or screen starts (or which you want started at boot regardless of timing), such as a GnuPG daemon session.
You then need to create a service for your multiplexer session. Here is a sample service, using tmux as an example and sourcing a gpg-agent session which wrote its information to /tmp/gpg-agent-info. This sample session, when you start X, will also be able to run X programs, since DISPLAY is set.
[Unit] Description=tmux: A terminal multiplixer Documentation=man:tmux(1) After=gpg-agent.service Wants=gpg-agent.service [Service] Type=forking ExecStart=/usr/bin/tmux start ExecStop=/usr/bin/tmux kill-server Environment=DISPLAY=:0 EnvironmentFile=/tmp/gpg-agent-info [Install] WantedBy=multiplexer.target
Once this is done, systemctl --user enable tmux.service, multiplexer.target and any services you created to be run by cruft.target and you should be set to go! Activated user-session@.service as described above, but be sure to remove the Conflicts=getty@tty1.service from user-session@.service, since your user session will not be taking over a TTY. Congratulations! You have a running terminal multiplexer and some other useful programs ready to start at boot!
ウィンドウマネージャ
systemd のサービスとしてウィンドウマネージャを実行するには、まず Xorg を systemd のユーザーサービスとして実行する必要があります。以下では awesome を例として使います:
~/.config/systemd/user/awesome.service
[Unit] Description=Awesome window manager After=xorg.target Requires=xorg.target [Service] ExecStart=/usr/bin/awesome Restart=always RestartSec=10 [Install] WantedBy=wm.target