概要
今回はLinux Containers(LXC)の記事です。
LXCは、意外と古くからあるLinux上のコンテナ機能です。コンテナというとしばらくはDockerのイメージが強かったと思いますが、原則コンテナ1個につきアプリケーション1個という単位で使われるDockerと違い、LXCはより低レイヤかつOS丸ごと仮想化して1つのコンテナを動かすような仕組みであり、VMに近い使い方ができます。ネストを許可すればLXCの中でDockerを動かすようなことも可能です。
ここ最近はClineやCursorをはじめとしたOS上で好き勝手にコマンドを実行してくるタイプのAIコーディングエージェントが一気に普及し始めており、それらを安全に動かすための隔離した環境としてもコンテナは注目されているようです。
ということでこの記事では、LXC上でLinux Mintをできるだけ「普通に」動かすことを目標にしています。具体的にはMATEデスクトップ環境を入れて、GUIログインを付けて、VNCでアクセスできるようにして、日本語化して、パッケージマネージャ(ソフトウェアアップデート)のような特権絡みのソフトウェアがまともに使える状態にします。
詳細な動作環境・バージョンとしては、ホスト側がLinux Mint 22.1 Xiaで、コンテナではLinux Mint 21.3 Virginiaを動かしました。また、せっかくLXCには非特権(rootless)コンテナ機能があるので、こちらをメインでやってみました。
もちろん結局はコンテナなので低レイヤの動作は色々と使っているうちに不便を感じることもあるかもしれませんが、Dockerじゃ足りないからVM入れようかな?っていう場合の7割くらいはLXCでカバーできるんじゃないかなっていうくらいの使い勝手だと感じます。
一番苦労したのがGUIログインの部分(セッション管理まわり)で、そこがちゃんとできていればMATE自体は結構すんなり動くので、MATE以外のデスクトップ環境(あるいは別のディストリビューション)を使いたい場合でも参考になると思います。
LXCのマネージャとしてLXD(あるいは最近はIncus)もありますが、今回はとりあえずよりベーシック(?)なlxc-utils由来のコマンドをメインで使っています。と言いつつIncusでもやってみたのでそれも最後の方に書きました。
非特権LXCを動かす準備
特権LXCと比べたときの非特権LXCの大きな特徴は、コンテナ内とホスト側のUIDが一致せず、ずらした形でマッピングされています。つまり、特権LXCではコンテナ内のUID0, 1, ...がそのままホストの0, 1, ...になる(コンテナ内のrootはホストのroot)のに対して、非特権LXCではコンテナ内のUID0, 1, ...がホストの100000, 100001, ....に対応するようになります。
これはLinuxのサブIDという機能を用いて実現されます。
例えばホストのUID1000のユーザー「user」に、サブIDとして100000-165535を割り当てます。その上でさきほどのマッピングを使うことで、非特権コンテナ内部の(root含む)全てのユーザーがホスト側の「user」と関連付けられる(?)ような感じになります。
では、具体的な設定をします。こことその次の2つのセクションあたりは大体第17回 LXCの構築・活用 [4] ― 一般ユーザによるLXCコンテナの利用 | gihyo.を参照しています。
まず今回の環境ではtestuserというUID 1001(ホスト側)のユーザーを使います。ちなみにこのユーザーはsudoersには入っていません。
/etc/subuidや/etc/subgidを見てみると
testuser:165536:65536
と書かれていました。つまり165536-231071までがtestuserのサブIDです。
これを確認のうえで、~/.config/lxc/default.confを以下のように編集します。
lxc.idmap = u 0 165536 65536
lxc.idmap = g 0 165536 65536
lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up
lxc.apparmor.profile = unconfined
lxc.apparmor.allow_nesting = 1
idmapは説明した通りです。その下の3つはネットワーク関連で、/etc/lxc/default.confのデフォルトまんまです。基本的にはこのままでいい気がします。最後2つはセキュリティ(apparmor)関連です。lxc.apparmor.profileは/etc/lxc/default.confだと"generated"になっているんですが、これだと自分が試した限りでは動かなかった(エラーは後述)ので、unconfinedにします。一応セキュリティを弱める方向の変更になりますが、そもそもapparmorが使われる目的は特権コンテナのrootからホストを保護するため(多分)なので、非特権コンテナではapparmorのことをあまり気にしなくても大丈夫そうです(多分)。下のallow_nestingは/etc/lxc/default.confにあわせて1のままにしましたが0でも起動はできそうです。
コンテナを作成
コンテナの作成は
lxc-create -t download -n container
と、特権ありのときと全く同様です。今回は
Distribution:
mint
Release:
virginia
Architecture:
amd64
と選んでいくことになります。
NICの設定
コンテナとホストマシンでネットワーク通信するには、ホストマシン側のネットワークにも手を加える必要があります。従ってこの部分はroot(あるいはsudo)で作業します。
具体的には、/etc/lxc/lxc-usernetというファイルに
testuser veth lxcbr0 10
という行を追加します。これで、testuserが、lxcbr0(LXCのブリッジ)(名前はデフォルトのまま)に接続するvethを10個まで作成できるようになります。
コンテナの起動
コンテナの起動は、特権コンテナならlxc-startというコマンドを使いますが、非特権の場合はそれに対応したlxc-unpriv-startというコマンドがあって、これを使います。
ちなみにlxc-startで起動しようとすると以下のようなエラーが出ます。
$ lxc-start -F -n t0
Failed to mount cgroup at /sys/fs/cgroup/systemd: Operation not permitted
[!!!!!!] Failed to mount API filesystems.
Exiting PID 1...
しかし、Alpine Linuxの場合はlxc-startでも普通に起動できてしまったので、ディストリビューションにもよるようです。
ちなみに-Fというオプションはフォアグラウンドで実行するもので、普段はつけないのですが、起動がうまくいかないときには有用です。
また、cgroupfs-mountというコマンドを(他の用途で)使っていたのですが(過去記事でも扱いました)、cgroupfs-mountを実行した後の状態だと上と全く同じエラーが出ます。
$ lxc-unpriv-start -F -n t6
Running as unit: run-rf4e320bc69754ce5ae6368ea659c7167.scope; invocation ID: aeeec9b7f65b462caf4fe4b390470896
Failed to mount cgroup at /sys/fs/cgroup/systemd: Operation not permitted
[!!!!!!] Failed to mount API filesystems.
Exiting PID 1...
(Running as unitの行があるところだけさっきと違う)
なので、lxc-unpriv-startでもダメだというときはcgroupfs-umountをしてみるといいかもしれません。ちなみにIncusを使っているときも同様に「Failed to create cgroup at_mnt」「Failed to mount "/sys/fs/cgroup"」のようなエラーが出ます。どうやらcgroupfs-mountはcgroup v1の機能を使うので、cgroup v2を使うLXCと併用するのはマズいようです(参考)。
先ほど、準備のところでlxc.apparmor.profileをunconfinedとしていましたが、これをgeneratedにした場合、lxc-createまでは問題なくいけますがlxc-unpriv-startでは以下のようなエラーが出ました。
$ lxc-unpriv-start -F -n t4
Running as unit: run-rd18ddc27a62243e7b8ee91988fbd341b.scope; invocation ID: 367d3bcb83464fe2b72f42bd6469a089
lxc-start: t4: ../src/lxc/lsm/apparmor.c: make_apparmor_namespace: 869 Permission denied - Error creating AppArmor namespace: /sys/kernel/security/apparmor/policy/namespaces/lxc-t4_<-home-testuser-.local-share-lxc>
lxc-start: t4: ../src/lxc/lsm/apparmor.c: apparmor_prepare: 1088 Failed to load generated AppArmor profile
lxc-start: t4: ../src/lxc/start.c: lxc_init: 876 Failed to initialize LSM
lxc-start: t4: ../src/lxc/start.c: __lxc_start: 2027 Failed to initialize container "t4"
lxc-start: t4: ../src/lxc/tools/lxc_start.c: main: 306 The container failed to start
lxc-start: t4: ../src/lxc/tools/lxc_start.c: main: 311 Additional information can be obtained by setting the --logfile and --logpriority options
最初の2行で明らかにapparmor関連のエラーが出ているのが分かります。
NICの設定ができていないと以下のようになります。
$ lxc-unpriv-start -F -n t0
Running as unit: run-ra75d7218097146c989e4d1bcab6b907f.scope; invocation ID: 35e2cf50abd74099849fad3c881fa1ee
lxc-start: t0: ../src/lxc/cgroups/cgfsng.c: __cgfsng_delegate_controllers: 3341 Device or resource busy - Could not enable "+cpu +memory +pids" controllers in the unified cgroup 8
lxc-start: t0: ../src/lxc/network.c: lxc_create_network_unpriv_exec: 2990 lxc-user-nic failed to configure requested network: ../src/lxc/cmd/lxc_user_nic.c: 1211: main: Quota reached
lxc-start: t0: ../src/lxc/start.c: lxc_spawn: 1840 Failed to create the network
lxc-start: t0: ../src/lxc/start.c: __lxc_start: 2107 Failed to spawn container "t0"
lxc-start: t0: ../src/lxc/tools/lxc_start.c: main: 306 The container failed to start
lxc-start: t0: ../src/lxc/tools/lxc_start.c: main: 311 Additional information can be obtained by setting the --logfile and --logpriority options
2行目がNICのエラーです。1行目はcgroupのなんかの権限が足りないというエラーですが、実はこれは正常に起動できたときも出ていたのでとりあえず無視で良さそうです。
-Fを付けない場合に起動に失敗すると
lxc-start: t4: ../src/lxc/lxccontainer.c: wait_on_daemonized_start: 870 No such file or directory - Failed to receive the container state
というような行が出ることがありますが、これ自体はあまり情報量がないのでとりあえず-Fを付けるのが良さそうです。
また、sudoなどでtestuserに切り替えた状態で実行すると以下のようなエラーが出ることがあります。
$ lxc-unpriv-start -n t6
Can't start an unprivileged container on a pure CGroups v2 host without a systemd user session running.
If you are trying to get a non-interactive user to have unprivileged containers running, you need to
enable lingering sessions for that user, via loginctl enable-linger testuser as root.
実際、以下のように、testuserのユーザーセッションが存在しないことがわかります。
$ loginctl show-user testuser
Failed to get user: User ID 1001 is not logged in or lingering
解決策としては、sudoで切り替えるのではなく、sshで直接testuserとしてログインするとユーザーセッションが作成されます(他にも方法があるかもしれません)。sshの中でlxc-unpriv-startを実行しなければいけないわけではなく、別の場所からログインするだけでも構いません。
以上の点に気をつければとりあえず起動するはずです。
コンテナを停止するときは
lxc-stop -n t0
です。lxc-unpriv-stopというコマンドはありません。
初期設定、パッケージのインストール
まずIPが割り当てられておらずインターネットが使えないので、
ip a a 10.0.3.2/24 dev eth0
ip r a default via 10.0.3.1 dev eth0
echo nameserver 8.8.8.8 > /etc/resolv.conf
などとすると使えるようになります(10.0.3.1のあたりはlxcbr0がどうなっているかによりますがデフォルトはこれ)。たまになんかの拍子にIPが無くなっていることがあるのでなんかおかしいと思ったらこの3行を突っ込みましょう。
aptが使えるようになるので、パッケージを入れます。
apt update
apt install xvfb x11vnc mate-desktop-environment-core mate-applet-appmenu mintmenu mate-screensaver mintupdate fonts-takao
MATEはケチってcoreだけ入れるとなるとちょいちょい手動でいくつか追加したいものが出てくるので入れています。もうちょい詳しくいうと、たしかmate-applet-appmenuとmintmenuは入れとかないとスタートメニューの表示がバグります(じゃあ依存関係に追加してくれ)。Ubuntuの場合はmintmenuではなくmate-menuにします。mate-screensaverはロック画面を提供します。mintupdateは別にaptでいいなら無くていいんですがいかにもmintらしい機能で個人的に好きなので入れます。fonts-takaoは日本語フォントです。
dpkg-reconfigure locales
dpkg-reconfigure tzdata
これでロケール($LANGとか)とタイムゾーンを日本語・日本時間にできます。あと今のうちにubuntuユーザー(最初から追加されている一般ユーザー)のパスワードを設定しておきましょう。
ネタバレになりますがこの後も結局色々とパッケージを入れることになるので必要になるものを全部入れたコマンドもここに貼っておきます。(違うディストリビューション・バージョンを使う人にはあまり意味がないかも)
apt install xvfb x11vnc mate-desktop-environment-core mate-applet-appmenu mintmenu mate-screensaver mintupdate fonts-takao\
git cargo libpam0g-dev \
meson pkg-config libgtk-3-dev libjson-c-dev libpam-systemd
greetd・gtkgreetのインストール
GUIログイン抜きでMATEを起動してVNCでアクセスするだけならここまででもできるのですが、それだと諸々があまり綺麗に動かないので、GUIログインを準備します。
いきなりですが今回はgreetdを使います。なぜかというと試した限り一番まともに動いたのがgreetdだったからです。他のものについては後述します。
greetdは残念ながらaptでは入れられないようなので(追記: 最近のDebian trixieには両方あります)、cargo(Rust)でビルドします。cargoはapt install cargoでとりあえずOKです。
git clone https://git.sr.ht/~kennylevinsen/greetd
cd greetd/
cargo build --release
こんな感じでビルドします。
/usr/bin/ld: cannot find -lpam: No such file or directory
こんなエラーが出るので、aptでlibpam0g-devを入れます。するとビルドが通ります。
"greetd"バイナリができたら適当にパスを通すか通ってる場所にシンボリックリンク置くかしておきます。
次に、greetd対応でGUIログインを提供するgtkgreet(greetdと同じ人が作っているっぽい)をインストールします。(他にもGUIログインができるものがあるかもしれませんが試していません)
こちらもaptにはないのでビルドします。mesonはaptで入れます。
git clone https://git.sr.ht/~kennylevinsen/gtkgreet
cd gtkgreet/
meson build
cd build/
ninja
meson buildが通るためにpkg-config libgtk-3-dev libjson-c-devの3つが要ると思います。まだCMakeがないとかgtk-layer-shell-0(←Wayland関連らしい)がないとかエラーが出ていますが、もうninjaは動くようになっているので大丈夫です。ninjaしてG_APPLICATION_DEFAULT_FLAGSなんて無いよというエラーが出たらG_APPLICATION_FLAGS_NONEに変えます(これはChatGPTに聞きました)。
gtkgreetもパスを通します。
greetdの設定
greetdの設定ファイルを作ります。デフォルトの設定ファイルパスである/etc/greetd/config.tomlを作成して以下の内容を書きます。
[terminal]
vt = "none"
[default_session]
command = "/etc/greetd/my-command"
my-commandというファイル名は適当です(今から作ります)。
次に/etc/greetd/my-commandです。以下のようにします。実行権限を付けるのを忘れずに。
#!/bin/sh
DISPLAY=:0 exec gtkgreet --command 'sh -c "DISPLAY=:0 mate-session"'
execがないとこのシェルスクリプトが終了しないので変な感じになると思います。sh -cも非常に美しくない感じですがとりあえずこれでいけます。ちなみにmate-sessionの部分は多分startxを使うときに.xinitrcに書くのと同じものを書いておけば良さそうです。つまりCinnamonならcinnamon-session、LXQtならstartlxqtなどです。ものによってはdbus-run-sessionやdbus-launch --exit-with-sessionなどを付けるとうまくいくかもしれません。ちなみに初回の自動ログイン(initial_session)を設定するときのcommandの引数にも、このmate-sessionにあたるものを書きます。
さらに、greetdはデフォルトではgreeterというユーザーを使って起動されるのですが、今回はパッケージ(ユーザーの追加も自動でやってくれる)を使わずバイナリをビルドしたので、このユーザーも手動で追加しておきます。
useradd --system --no-create-home --shell /usr/sbin/nologin greeter
あわせて/etc/greetd以下の所有権も変更しろとArchWikiに書いてありましたが読み取りアクセスがあればroot所有のままでも動くようです。また/home/greeterがないとunable to set working directory: No such file or directory (os error 2)と言われますが、別にそのままで問題無さそうです。
PAM関連の設定
ここまでで一旦greetdと打って起動してみると
error: PAM 'greetd' service missing
と言われます。PAM関連の設定が必要なようです。詳しくないのでlightdmなどの設定も参考にしつつChatGPTに聞きながらでしたが、/etc/pam.d/greetdを作成して内容をこんな感じにすると多分いいんじゃないかと思います。lightdmのを参考に不要っぽいものを削りました。とりあえず動いているので(ry
session required pam_limits.so
session required pam_env.so readenv=1
session required pam_env.so readenv=1 user_readenv=1 envfile=/etc/default/locale
-session optional pam_gnome_keyring.so auto_start
-session optional pam_kwallet.so auto_start
@include common-account
@include common-session
locale云々と書いてある行がありますが、これによってシステムデフォルトのロケールがユーザーに反映されるようです。
基本的にはこの部分を多少変えても動作にはあまり影響がない(ログインが成功するようになったり失敗するようになったりはしない)という印象です。
- aptでインストールしたものだと以下のようになっていました。でもこれだとリモートセッション扱い(後述)になってしまっている気がします。また、/etc/pam.d/greetd-greeterというのもインストールされますが、これも無い方がうまく動作することがある気がします。気のせいかも
#%PAM-1.0
@include login
-auth optional pam_gnome_keyring.so
-auth optional pam_kwallet5.so
-session optional pam_gnome_keyring.so auto_start
-session optional pam_kwallet5.so auto_start
Xvfb・x11vnc
これでまたgreetdと打ってみると、 Cannot open displayと言われます。Xvfbをまだ立てていなかったので当然です。さっきのファイルにあわせて、ディスプレイ番号0でXvfbを立てて、x11vncも起動しておきます。
Xvfb :0 -screen 0 1920x1080x24 &
x11vnc -display :0 -forever -nopw -loop &
VNCクライアントも当然必要です。筆者はWindowsのUltraVNCってやつを使ってみました。ここは好きなもので大丈夫です。ポートは5900なのでホストからは10.0.3.2:5900で見えています。greetdを起動していなくてもx11vncが動いていればとりあえず接続された状態(真っ暗画面)にはなります。何回か接続するとうまくいくこともあります。
で、greetdを起動します。数秒のラグがありますが、ここまでがうまくいっていればちゃんとログイン画面が表示されるはずです。さっき設定したコマンドが表示されています。

なんか余白ができていますが、とりあえず動いて(ry
そして、ユーザー名とパスワードを入れれば、ちゃんとログインできてデスクトップが表示されるはずです。pam_envまわりの設定ができていれば表示も日本語になっていると思います。x11vncに-loopを付けたので、ログアウトしてもまた(数秒のラグののちに)上記のログイン画面が出るはずです。
ログイン時にLogin failedと言われてgreetdでエラー(error: authentication error: pam_authenticate: AUTH_ERR)が出ていたらlibpam-systemdがないかもしれないので入れてください。
ALSAのエラーを抑制
greetd(というかMATE)がこんな感じのALSA(サウンド関連)のエラーを大量に吐き続けています。
ALSA lib confmisc.c:855:(parse_card) cannot find card '0'
ALSA lib conf.c:5178:(_snd_config_evaluate) function snd_func_card_inum returned error: No such file or directory
ALSA lib confmisc.c:422:(snd_func_concat) error evaluating strings
ALSA lib conf.c:5178:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1334:(snd_func_refer) error evaluating name
ALSA lib conf.c:5178:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5701:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib control.c:1528:(snd_ctl_open_noupdate) Invalid CTL default
とりあえずサウンドは使わない(ことにします)ので、以下のような~/.asoundrcを作るとエラーは出なくなります。
pcm.!default {
type hw
card 0
}
ctl.!default {
type hw
card 0
}
その他エラー
こんなエラーも出ていますが、まあとりあえず動(ry
(mate-session:16806): dbind-WARNING **: 01:38:55.631: Couldn't connect to accessibility bus: Failed to connect to socket /root/.cache/at-spi/bus_0: Permission denied
(mate-session-check-accelerated:16827): dbind-WARNING **: 01:38:55.674: Couldn't connect to accessibility bus: Failed to connect to socket /root/.cache/at-spi/bus_0: Permission denied
mintupdate向けに/etc/apt/以下を修正
ログインするとmintupdateが勝手に立ち上がると思いますが、「別のLinux Mintミラーに切り替えてください APT設定が破損しています(Please switch to another Linux Mint mirror. Your APT configuration is corrupt.)」というエラーが出ています。
原因がよくわからなかったんですが、他のLinux Mint(ホスト)と見比べたりmintUpdate.pyを読んだりした結果、/etc/apt/preferences.d/official-package-repositories.prefというファイルを作成して、
Package: *
Pin: release o=linuxmint,c=upstream
Pin-Priority: 700
(ホストの内容がこれでした)と書いておくと解決するということがわかりました。
また、ミラーを変更するなどしてキャッシュが一度更新されると、
/etc/apt/sources.list.d/official-package-repositories.list
というファイルが作成され、このファイルの内容がもとからあった/etc/apt/sources.listと重複しているため警告が出ます。一応このまま使っても壊れることはないと思いますが、sources.listのほうは全てコメントアウトしておくとmintupdateにとっては理想的な状態になりそうです。
UbuntuではなくLinux Mintのコンテナイメージであるからにはもうちょいデフォルトでmintupdateとかが普通に動く状態にしておいて欲しい気持ちになりました。aptが動けばとりあえずOKくらいの基準で作られている気がします。
ちなみにMintのバージョン22(Wilma)のコンテナを使ってみたらsources.listになぜかnoble(Mint 22のベースであるUbuntu 24.04)ではなくjammy(Ubuntu 22.04)と書いてあってaptが動かなかった(直せば動きますが)ので、結構人手不足でろくにテストされていないのかもしれません。
まあコンテナでわざわざMintなんて普通使わないですかね…
ソフトウェアソース(mintsources)の動作確認
ここまでの設定がちゃんとできていれば大丈夫だと思いますが、ソフトウェアソース(mintsources)も動作確認をしておいてください。セッションまわりがうまくいっていないとLinux Mintでxrdp経由で一部のGUIアプリケーション(mintsources)などを実行しようとするとError executing command as another user: Not authorizedと言われる - turgenev’s blog(過去記事)のようなエラーが出ます。
aptキャッシュの更新でThe name org.freedesktop.PackageKit was not provided by any .service filesというエラーが出たときは、packagekitというのをaptで入れましょう。
Incusの場合
高レベルなLXC(やVM)のマネージャーであるIncusを使ってここまでと同様の設定をやってみました。
前半部分の設定はかなり飛ばせます。UIDやNICの設定は不要で、apparmorも勝手にunconfinedにあたる設定をしてくれているようです。非特権ユーザー・非特権コンテナの場合、rootのサブID(自分の環境では1000000-1000000000)がUIDとして使われるようです。起動にあたって直接sshログインをしておく必要もなさそうです。さらに勝手にDHCPまで立ててくれているのでコンテナを起動すると何もしなくてもインターネットが使えます。
その後ももちろん基本的には同様なのですが、一か所だけハマりポイントがありました。
greetdを起動するところまではすんなり行くのですが、パスワードを打ってEnterすると、正しいパスワードを入れているのにまるでパスワードが間違っているかのようなエラーが出ます。
greetdが直接吐くエラーとしては前述のerror: authentication error: pam_authenticate: AUTH_ERRで、journalctlでPAM側を見てもpam_unix(greetd:auth): authentication failure; logname= uid=0 euid=0 tty= ruser= rhost= user=ubuntuぐらいしか書いていないので原因がよくわからなかったんですが、straceを使って正常動作している例と見比べてみた結果、
[pid 246] 06:30:09.464536 mmap(NULL, 16801856, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 EAGAIN (Resource temporarily unavailable)
このようにmmapでEAGAINになっている部分が怪しそうだということがわかり、ulimit -aで見てみると、max locked memoryが8192KB(8MB)になっていて、これよりも大きい16MB程度のメモリをmmapで確保しようとして落ちていることがわかりました。そこで、Incusのプロファイル(あるいはインスタンスごとの設定でも可)のconfigに
limits.kernel.memlock: "4294967296"
(この例では4GB)などと書き加えて再起動したところulimitの値も変わり、正しくgreetdが動作しました。
- 追記: コマンドとしてはincus config set my_container limits.kernel.memlock=4294967296などでできます。また、pamのAUTH_ERRすら出ないときもある気がします。
IncusについてはIncus(≒LXD)の"User restricted project"の設定方法について - turgenev’s blogも適宜参照してください。
他のログインマネージャ・ディスプレイマネージャについて
この記事ではGUIログイン部分にgreetdを使いましたが、他にもいろいろなディスプレイマネージャがあります。
今回はlightdm, gdm3, xdmの3つを試しました。lightdmはLinux Mintのデフォルト、gdm3はUbuntuのGnome 3で主に使われるやつ、xdmはXorgの一部として設計された化石のようなソフトウェアです。
動作状況としてはxdm>lightdm>gdm3という感じになりました。主に、VT(/dev/tty0など)が無いのが動かない原因のようです。とはいえ細かいところは理解していないので何かしら動かす方法はあるのかもしれません。ホスト側で何かの許可を出すというのは本末転倒なので(というかそもそもgreetdはそれがなくても動いている)一切しないという条件で試しています。
以下いちいち書いていませんが切り替えのときはdpkg-reconfigure lightdmみたいなやつをしましょう。
まず一番ひどいgdm3については、journalctlにGdm: GdmSessionWorker: couldn't set up terminal, aborting...というようなエラーが出ていて、x11vncでGUIログイン画面を見るところまで行けませんでした。
次にlightdmです。まず設定方法を書きます。/etc/lightdm/lightdm.conf.d/70-linuxmint.confに
[Seat:*]
xserver-command=/my/Xvfb-lightdm.sh
と書きます。そして/my/Xvfb-lightdm.shには
#!/bin/sh
x11vnc -display :0 -forever -shared -nopw -auth /var/run/lightdm/root/:0 > /dev/null &
exec /usr/bin/Xvfb :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp -screen 0 1920x1080x24
と書きます。実行権限も付けます。これは大体How can I run lightdm on Xvfb on a Raspberry Pi? - Super Userに書いてあるような内容と同じで、要はXorg向けのオプションがまるっと渡されてくるのですが、その中に「vt7 -novtswitch」みたいなのが混ざっていて、Xvfbはこれに対応していないので、上記のような自前のシェルスクリプトでラップしてやって無駄な引数を捨てるとうまくいくということです。
これでsystemctl startすればGUIログインはとりあえず出ます。でもログインしてみると「Could not update ICEauthority file /run/user/1000/ICEauthority」と言われます。「閉じる」を押すととりあえずデスクトップ環境が出ます。
しかしpkexec(GUI環境でsudoのように使われるコマンドで、mintsourcesのところで載せた過去記事にもあります)が動きません。例えばターミナルでpkexec lsを実行すると
==== AUTHENTICATING FOR org.freedesktop.policykit.exec ===
Authentication is needed to run `/usr/bin/ls' as the super user
Authenticating as: ubuntu
Password:
と出てしまって使い物になりません(本来はターミナルには何も出ずパスワード入力ダイアログが出るはず)。
最後にxdmです。
xdmもlightdmと同様に設定します。まず、/etc/X11/xdm/Xserversに
:0 local /my/Xvfb-xdm.sh
と書きます。そして/my/Xvfb-xdm.shには
#!/bin/sh
nohup x11vnc -display :0 -forever -shared -nopw "$@" > /dev/null &
exec /usr/bin/Xvfb :0 -screen 0 1920x1080x24 -nolisten tcp "$@"
と書いて実行権限を付けます($@には-auth foobarみたいなのが渡されてきます)。
これでsystemctl startすればGUIログインが出ます。
ちなみに見た目はこれです。完全に20世紀。

ログインすると、すんなりデスクトップ環境が出ます。一見割と問題なく動いているように見えます。これは、lightdmとちがってログインセッションが作られてXDG_SESSION_IDがセットされているのが理由のようです。loginctlを実行してみると以下のようになります。
root@my2:/# loginctl
SESSION UID USER SEAT TTY
77 1000 ubuntu
c13 1000 ubuntu
このうち77が初回ログインで作られたもの、c13が2回目にログインしたときに作られたものです。なぜか2回目以降(というかcで始まらないものがあるとき)はcで始まるものになるようです。
ただしSEATの部分が空欄になっています。greetdでは以下のようにちゃんとseat0と表示されています。まあそれが具体的に何を意味するかは理解していませんが…
# loginctl
SESSION UID USER SEAT TTY
1760 998 greeter seat0
1 sessions listed.
おそらくこの部分の違いが影響しているのか、xdmでmintsourcesを動かそうとすると、Linux Mintでxrdp経由で一部のGUIアプリケーション(mintsources)などを実行しようとするとError executing command as another user: Not authorizedと言われる - turgenev’s blogと同じ状況(pkexec lsとかはOK)になります。
ちなみに、xdmでこのようなセッションが作成された状態でlightdmに切り替えてログインしてみると「Could not update ICEauthority file /run/user/1000/ICEauthority」は出なくなりました。しかしそれ以外の動作は変わっていないようです。
Waylandについて
今回はすべてXorgを使ってGUIを整備していて新興のWaylandは一切使っていません。しかし今回使ったgtkgreetなんかはむしろWaylandを主に想定して作られているものなので、Waylandでも同じようなことはできそうです。というかXorgでも問題なく動くのはありがたいことです。