「Systemd/ユーザー」の版間の差分
Kusanaginoturugi (トーク | 投稿記録) (→systemd のユーザーサービスとしての Xorg: 仮想ターミナルを仮想コンソールに修正) |
Kusanaginoturugi (トーク | 投稿記録) (→ログアウト時にユーザープロセスを終了: 飜訳) |
||
(同じ利用者による、間の1版が非表示) | |||
329行目: | 329行目: | ||
$ systemd-run --scope --user screen -S ''foo'' |
$ systemd-run --scope --user screen -S ''foo'' |
||
+ | |||
+ | {{ic|systemd-run}} を使うと、ログアウト後も、ユーザがシステム内のどこかで少なくとも 1 回はログインしていて、{{ic|user@.service}} がまだ実行されている間だけ、プロセスが実行され続けます。 |
||
+ | |||
+ | ユーザがすべてのセッションからログアウトした後、{{ic|user@.service}} は、そのユーザが「lingering」を有効にしていない限り、デフォルトで終了します [https://github.com/systemd/systemd/blob/76153ad45f09b6ae45464f2e03d3afefbb4b2afe/NEWS#L274]。ユーザーが完全にログアウトしていても、長時間のタスクを効果的に実行できるようにするには、そのユーザーに対してリンガリングを有効にする必要があります。詳しくは [[#Automatic start-up of systemd user instances]] と {{man|1|loginctl}} を参照してください。 |
||
== トラブルシューティング == |
== トラブルシューティング == |
2023年7月3日 (月) 14:30時点における最新版
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 のユーザーインスタンスを制御できるようになります。
基本設定
Systemd のユーザーインスタンスはログイン時に自動で起動します。正しく起動していることを確認するには、次のコマンドを使います: systemctl --user status
。
ユーザーサービスは全て ~/.config/systemd/user/
に配置してください。ログイン時にサービスを実行したい場合は、自動実行したいサービスごとに systemctl --user enable service
を実行してください。
D-Bus
プログラムによっては D-Bus ユーザーメッセージバスを必要とすることがあります。D-Bus は伝統的に dbus-launch
によってデスクトップ環境の起動時に実行されていましたが、バージョン226から、systemd がユーザーのメッセージバスを管理するようになりました [3]。dbus.socket
や dbus.service
のユーザーユニットによって全てのセッションでユーザーごとに dbus-daemon が起動します。
環境変数
systemd のユーザーインスタンスは .bashrc
などに設定された環境変数を全く継承しません。systemd インスタンスに環境変数を設定する方法は複数存在します:
$HOME
ディレクトリが存在するユーザーの場合、~/.config/environment.d/
ディレクトリにNAME=VAL
という形式で環境変数を記述した .conf ファイルを作成する。ユーザーのユニットファイルにのみ影響します。詳しくは environment.d(5) を見てください。/etc/systemd/user.conf
でDefaultEnvironment
オプションを使う。全てのユーザーユニットに影響します。/etc/systemd/system/user@.service.d/
に設定ファイルを追加する。全てのユーザーユニットに影響します。#サービス例を参照。- 適宜、
systemctl --user set-environment
やsystemctl --user import-environment
を使う。環境変数を設定した後に起動したユーザーユニットには影響しますが、既に起動しているユニットには影響しません。 - D-Bus の
dbus-update-activation-environment --systemd --all
コマンドを使う。systemctl --user import-environment
と同じ効果があり、D-Bus セッションに適用されます。コマンドはシェルの初期化ファイルの末尾に追加できます。 - ユーザー環境全体の環境変数は systemd のジェネレータによって読み込まれる
environment.d
ディレクトリを使用できます。詳しくは environment.d(5) を参照。 - 環境生成スクリプトを記述することでユーザーごとに環境変数を生成することもできます。ユーザーごとに環境変数を設定する必要は役に立つでしょう (XDG_RUNTIME_DIR, DBUS_SESSION_BUS_ADDRESS など)。systemd.environment-generator(7) を見てください。
設定するべき変数としては DISPLAY
や PATH
などが考えられます。
サービス例
ドロップインディレクトリ /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 から、セッションが開始したときに DISPLAY
と XAUTHORITY
を systemd --user
デーモンの環境にアップロードする X11 セッションアプレット /etc/X11/xinit/xinitrc.d/50-systemd-user.sh
が systemd に付属するようになりました。これによって、X を標準の方法で起動しているかぎり、ユーザーサービスは DISPLAY
や XAUTHORITY
を使用することができるようになっています。
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 ユニットファイルの書き方は 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 で導入された非特権モードを活用することはできません。
以下がユーザーサービスから 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 ユニットとして起動することが可能です。
ユースケース
永続的なターミナルマルチプレクサ
ウィンドウマネージャのセッションにログインする代わりに、ユーザーセッションでデフォルトで 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
上記の 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 enable
で tmux.service
, multiplexer.target
と cruft.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
ログアウト時にユーザープロセスを終了
systemd パッケージのデフォルトは KillUserProcesses=no
となっており、ユーザーが完全にログアウトしたときでもユーザープロセスは終了しません。ユーザーがログアウトしたときに全てのユーザープロセスが終了するようにしたい場合、/etc/systemd/logind.conf
に KillUserProcesses=yes
と設定してください。
ただし、この設定を変更すると tmux や screen などのターミナルマルチプレクサが動作しなくなります。以下のように systemd-run
を使ってターミナルマルチプレクサを利用してください:
$ systemd-run --scope --user command args
例えば、screen
を実行する場合:
$ systemd-run --scope --user screen -S foo
systemd-run
を使うと、ログアウト後も、ユーザがシステム内のどこかで少なくとも 1 回はログインしていて、user@.service
がまだ実行されている間だけ、プロセスが実行され続けます。
ユーザがすべてのセッションからログアウトした後、user@.service
は、そのユーザが「lingering」を有効にしていない限り、デフォルトで終了します [7]。ユーザーが完全にログアウトしていても、長時間のタスクを効果的に実行できるようにするには、そのユーザーに対してリンガリングを有効にする必要があります。詳しくは #Automatic start-up of systemd user instances と loginctl(1) を参照してください。
トラブルシューティング
ランタイムディレクトリ '/run/user/1000' は、UID1000 によって所有されていません
systemd[1867]: pam_systemd(systemd-user:session): Runtime directory '/run/user/1000' is not owned by UID 1000, as it should. systemd[1867]: Trying to run as user instance, but $XDG_RUNTIME_DIR is not set
このようなエラーが表示され、ログインセッションが壊れている場合、システム上の別のシステム(ユーザーではない)サービスがこのフォルダを作成している可能性があります。例えば、/run/user/1000
にバインドマウントしている docker コンテナを使用している場合、このようなことが起こる可能性があります。これを解決するには、マウントを削除することでコンテナを修正するか、ドッカーサービスを無効化/遅延させるかのいずれかです。