systemd/ユーザー

提供: ArchWiki
2018年5月10日 (木) 22:19時点におけるKusakata (トーク | 投稿記録)による版 (同期)
ナビゲーションに移動 検索に移動

関連記事

systemd はユーザーに systemd のインスタンスを実行させてサービスを管理できる機能を提供しています。これによって systemd がユーザーによって実行されている時、特定のディレクトリに入っているユニットをユーザーが起動・停止・有効化・無効化することが可能です。このことは root や特別なユーザーではなく普通のユーザーとして通常実行される mpd などのデーモン・サービスで重宝します。また、メールの取得などの作業を自動化することも可能です。さらに、多少の注意が必要ですが、ユーザーサービスから xorg やウィンドウマネージャを実行することもできます。

利用方法

ユーザーがログインを行うと、systemd は自動的にユーザーサービスを管理する systemd --user インスタンスを起動します。このプロセスは、そのユーザーにセッションが残っているかぎり生存し、ユーザーの最後のセッションが閉じられた時に終了します。systemd のユーザーインスタンスを自動起動している場合、インスタンスはブート時に起動し、終了しません。ユーザーサービスを使うことで、ソケットアクティベーションやタイマー、システムの依存関係や cgroups によるプロセスの制限など、systemd の恩恵を最大限活用して、デーモンや自動化されたタスクを実行できます。

ユーザーユニットはシステムサービスと同じように以下のディレクトリに配置されます (優先度が低い順):

  • /usr/lib/systemd/user/: インストールしたパッケージに含まれているサービス
  • ~/.local/share/systemd/user/: ホームディレクトリにインストールしたパッケージのユニット
  • /etc/systemd/user/: システムの管理者が配置する、全てのユーザーが使えるユーザーサービス
  • ~/.config/systemd/user/: ユーザーが配置する、そのユーザーのサービス

systemd のユーザーインスタンスが起動すると、default.target ターゲットが立ち上がります。その後 systemctl --user を使って手動で systemd のユーザーインスタンスを制御できるようになります。

ノート:
  • バージョン206から、systemd --user インスタンスはユーザーごとのプロセスであり、セッションごとのプロセスではないので注意してください。ソケットやステートファイルなどのユーザーサービスによって扱われるリソースはセッションごとではなくユーザーごとに割り振られる (ユーザーのホームディレクトリ上に存在する) というのが原則です。つまりユーザーサービスは全てセッションとは関係なく動作します。結果として、セッションの中で実行する必要があるプログラムはユーザーサービスの中で壊れてしまう可能性があります。systemd のユーザーセッションの扱い方は流動的であり確定していません。[1][2] が今後どうなるかのヒントになるでしょう。
  • systemd --usersystemd --system プロセスとは別のプロセスを起動します。ユーザーユニットからシステムユニットに依存したり参照することはできません。

基本設定

Systemd のユーザーインスタンスはログイン時に自動で起動します。正しく起動していることを確認するには、次のコマンドを使います: systemctl --user status

ユーザーサービスは全て ~/.config/systemd/user/ に配置してください。ログイン時にサービスを実行したい場合は、自動実行したいサービスごとに systemctl --user enable service を実行してください。

D-Bus

プログラムによっては D-Bus ユーザーメッセージバスを必要とすることがあります。D-Bus は伝統的に dbus-launch によってデスクトップ環境の起動時に実行されていましたが、バージョン226から、systemd がユーザーのメッセージバスを管理するようになりました [3]dbus.socketdbus.service のユーザーユニットによって全てのセッションでユーザーごとに dbus-daemon が起動します。

ノート: /etc/systemd/user/~/.config/systemd/user/ に手動でユニットを作成していた場合は、削除してもかまいません。

環境変数

systemd のユーザーインスタンスは .bashrc などに設定された環境変数を全く継承しません。systemd インスタンスに環境変数を設定する方法は複数存在します:

  1. $HOME ディレクトリが存在するユーザーの場合、~/.config/environment.d/ ディレクトリに NAME=VAL という形式で環境変数を記述した .conf ファイルを作成する。ユーザーのユニットファイルにのみ影響します。詳しくは environment.d(5) を見てください。
  2. /etc/systemd/user.confDefaultEnvironment オプションを使う。全てのユーザーユニットに影響します。
  3. /etc/systemd/system/user@.service.d/ に設定ファイルを追加する。全てのユーザーユニットに影響します。#サービス例を参照。
  4. 適宜、systemctl --user set-environmentsystemctl --user import-environment を使う。環境変数を設定した後に起動したユーザーユニットには影響しますが、既に起動しているユニットには影響しません。
  5. D-Busdbus-update-activation-environment --systemd --all コマンドを使う。systemctl --user import-environment と同じ効果があり、D-Bus セッションに適用されます。コマンドはシェルの初期化ファイルの末尾に追加できます。
  6. ユーザー環境全体の環境変数は systemd のジェネレータによって読み込まれる environment.d ディレクトリを使用できます。詳しくは environment.d(5) を参照。
  7. 環境生成スクリプトを記述することでユーザーごとに環境変数を生成することもできます。ユーザーごとに環境変数を設定する必要は役に立つでしょう (XDG_RUNTIME_DIR, DBUS_SESSION_BUS_ADDRESS など)。systemd.environment-generator(7) を見てください。

設定するべき変数としては DISPLAYPATH などが考えられます。

サービス例

ドロップインディレクトリ /etc/systemd/system/user@.service.d/ を作成して、その中に拡張子が .conf のファイルを作成します (例: local.conf):

/etc/systemd/system/user@.service.d/local.conf
[Service]
Environment="PATH=/usr/lib/ccache/bin:/usr/local/bin:/usr/bin:/bin"
Environment="EDITOR=nano -c"
Environment="BROWSER=firefox"
Environment="NO_AT_BRIDGE=1"

DISPLAY と XAUTHORITY

DISPLAY は X アプリケーションがどのディスプレイを使えばいいのか知るために使用されます。XAUTHORITY はユーザーの .Xauthority ファイルのパスと、X サーバーにアクセスするのに必要な cookie を指定します。systemd ユニットから X アプリケーションを起動する場合、これらの変数を設定する必要があります。バージョン 219 から、セッションが開始したときに DISPLAYXAUTHORITYsystemd --user デーモンの環境にアップロードする X11 セッションアプレット /etc/X11/xinit/xinitrc.d/50-systemd-user.sh が systemd に付属するようになりました。これによって、X を標準の方法で起動しているかぎり、ユーザーサービスは DISPLAYXAUTHORITY を使用することができるようになっています。

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

pam_environment

pam_env.so モジュールを利用することで環境変数を設定できます。~/.pam_environment ファイルを以下のように作成してください:

~/.pam_environment
XDG_CONFIG_HOME DEFAULT=@{HOME}/.local/config
XDG_DATA_HOME   DEFAULT=@{HOME}/.local/data

.pam_environment ファイルの構文に関する詳細は環境変数#pam_env を使うを見てください。systemctl --user show-environment コマンドを実行することで設定が上手くいっているか確認できます:

$ systemctl --user show-environment
...
XDG_CONFIG_HOME=/home/user/.local/config
XDG_DATA_HOME=/home/user/.local/data
...

systemd のユーザーインスタンスを自動起動

systemd のユーザーインスタンスはデフォルトでユーザーの最初のログイン時に実行され、ユーザーのセッションが閉じられた時に終了します。しかしながら、ブートした直後にインスタンスを起動して、セッションが閉じられてもユーザーインスタンスを実行し続ける方が、例えばセッションが開いてない時もユーザープロセスを実行したいときなどには便利です。linger を利用してこれを行います。特定のユーザーで linger を有効にするには以下のコマンドを使用:

# loginctl enable-linger username
警告: systemd のサービスはセッションではありません。サービスは logind の外で動作します。linger を利用して自動ログインを有効にするとセッションが破壊されるので注意してください。

ユーザーユニットを書く

普通の systemd ユニットファイルの書き方は 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 と XAUTHORITY を見て下さい。

ジャーナルを読み込む

ユーザーのジャーナルも同じようなコマンドで読みことができます:

$ journalctl --user

ユニットを指定する場合:

$ journalctl --user -u myunit.service

ユーザーユニットを指定する場合:

$ journalctl --user --user-unit myunit.service

ときどきユーザーサービスからの出力がサービスユニットに割り当てられないというバグが存在します。-u を使って出力をフィルタリングするとサービスユニットからの出力が見れなくなる可能性があります。

一時ファイル

systemd-tmpfiles を使うことでシステム全体と同じように一時ファイル・ディレクトリを管理することができます (systemd#一時ファイルを参照)。ユーザー個別の設定ファイルは ~/.config/user-tmpfiles.d/~/.local/share/user-tmpfiles.d/ からこの順番で読み込まれます。設定ファイルを使うには、必要な systemd ユーザーユニットを使用しているユーザーで有効にする必要があります:

$ systemctl --user enable systemd-tmpfiles-setup.service systemd-tmpfiles-clean.timer

設定ファイルの構文はシステムユニットと同じです。詳しくは man ページの systemd-tmpfiles(8)tmpfiles.d(5) を見てください。

Xorg と systemd

systemd ユニットの中で Xorg を実行する方法は複数存在します。以下の2つは、xorg プロセスで新しいユーザーセッションを起動するというのと、systemd のユーザーサービスから xorg を起動するという方法です。

ディスプレイマネージャを使わずに Xorg に自動ログイン

こちらを選択した場合、xorg サーバーでユーザーセッションを起動してその後ウィンドウマネージャなどを起動するために通常の ~/.xinitrc を実行するシステムユニットを起動します。

D-Bus を適切に設定して xlogin-gitAUR をインストールする必要があります。

雛形のファイルから xinitrc を設定して、/etc/X11/xinit/xinitrc.d/ のファイルが読み込まれるようにしてください。~/.xinitrc は実行したときに戻ってこないようにする必要があるため、最後のコマンドとして wait を記述するか、(ウィンドウマネージャなど) exec を追加して戻ってこないようにしてください。

セッションは自らの dbus デーモンを使用しますが、systemd ユーティリティは dbus.service インスタンスに自動的に接続します。

最後に、(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-gitAUR が不要に。

残念ながら、非特権モードで xorg を実行できるようにするには、セッションの中で xorg を実行する必要があります。そのため、今のところユーザーサービスとして xorg を実行するのには (1.16 以前と同じように) root 権限で実行する必要があるというハンディキャップがあり、1.16 で導入された非特権モードを活用することはできません。

ノート: 上記の制約は logind によるものではなく、xorg にどのセッションを引き継ぐか知らせる必要があるのが理由です。現在の実装では自己の pid を引数として logindGetSessionByPID を呼び出すことで情報を取得しています。このスレッドxorg のソース を参照してください。アタッチする tty からセッションを取得するように xorg を修正すれば、セッションの外でもユーザーサービスから非特権で実行することができます。
警告: xorg 1.18 ではソケットアクティベーションが壊れているようです。クライアントからアクティベーションが実行されるとデッドロックが発生します。上流のバグレポート [4] を参照してください。回避策としては、ソケットアクティベーションを使わないで xorg サーバーを起動することで、サーバーが完全に起動するまでクライアントの接続を待機させることができます。X サーバーの起動を通知する機構は存在しません。

以下がユーザーサービスから 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
ノート: xorg はユーザーがログインしたのと同じ仮想ターミナルで起動する必要があります。そうでないと logind はセッションがアクティブになっていないと認識します。

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 ユニットとして起動することが可能です。

警告: 現在、ユーザーサービスとしてウィンドウマネージャを実行するとセッションの外でウィンドウマネージャが実行されることになり次の問題が引き起こされます: セッションの破壊。ただし、systemd の開発者はウィンドウマネージャの実行を可能にする何かを作る予定があるようです。[5][6] を見て下さい。

ユースケース

永続的なターミナルマルチプレクサ

ウィンドウマネージャのセッションにログインする代わりに、ユーザーセッションでデフォルトで GNU ScreenTmux などのターミナルマルチプレクサをバックグラウンドで実行したいということもあるでしょう。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

上記の mystuff.target と同じように、cruft.target は tmux や screen が起動する前に実行する必要があるサービス (もしくは起動時に即座に起動させたいサービス)、例えば GnuPG デーモンのセッションなどを起動します。

次にマルチプレクサセッションのサービスを作成してください。以下は tmux を使用して /tmp/gpg-agent-info に情報を書き込む gpg-agent セッションを読み込むサービスの例です。また、DISPLAY を設定することで X を起動したときに X プログラムが実行できるようにしています。

[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

上記の設定が完了したら、systemctl --user enabletmux.service, multiplexer.targetcruft.target で実行させるサービスを有効化してください。後は同じように user-session@.service を有効化しますが、ユーザーセッションは TTY を引き継がないので user-session@.service から Conflicts=getty@tty1.service は削除してください。これで、起動時にターミナルマルチプレクサなどのプログラムを実行できるようになります。

ウィンドウマネージャ

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
ノート: [Install] セクションに WantedBy を記述することで、systemctl --user enable を使用した際に ~/.config/systemd/user/wm.target.wants/window_manager.service としてリンクが作成され、ログイン時に起動できるようになります。リンクは手動で作成するのではなく、サービスを有効化することを推奨します。

ログアウト時にユーザープロセスを終了

systemd パッケージのデフォルトは KillUserProcesses=no となっており、ユーザーが完全にログアウトしたときでもユーザープロセスは終了しません。ユーザーがログアウトしたときに全てのユーザープロセスが終了するようにしたい場合、/etc/systemd/logind.confKillUserProcesses=yes と設定してください。

ただし、この設定を変更すると tmuxscreen などのターミナルマルチプレクサが動作しなくなります。以下のように systemd-run を使ってターミナルマルチプレクサを利用してください:

$ systemd-run --scope --user command args

例えば、screen を実行する場合:

$ systemd-run --scope --user screen -S foo

参照