(LXC 4.0.2に合わせて記事を更新した)
Fedra 31でCGroup V2 (Unified CGroup Hierarchy, カーネルオプションに systemd.unified_cgroup_hierarchy
が付けられて起動)がデフォルトになり、UbuntuならびにDebianでもCGroup V2をデフォルトにしようとしている。CGroup V2で起動されたLinuxホスト上でLXCを使うと
などの報告が寄せられているが、その対策を紹介する。後半では一般(非ルート)ユーザーからCGroup 2でLXCを使う手順を紹介する。LXC 3.0.4 以降、3.2.1以降なら以下の手順で概ね正常にLXCを使える。
CGroup V2でのLXCトラブルシューティング
Failed to setup limits for the "devices" controller
ERROR cgfsng - cgroups/cgfsng.c:cg_legacy_set_data:2415 - Failed to setup limits for the "devices" controller. The controller seems to be unused by "cgfsng" cgroup driver or not enabled on the cgroup hierarchy
ERROR start - start.c:lxc_spawn:1910 - Failed to setup legacy device cgroup controller limits
のようなメッセージがログファイルに残ってLXCコンテナがスタートしない場合、設定ファイルでCGroup V1のデバイスコントローラーを使う設定がされていて、そのようなコントローラーが使えずにエラーが起きている。
lxc.cgroup.devices.allow =
lxc.cgroup.devices.deny =
を追加するとCGroup V1のデバイスコントローラーを用いなくなるため、コンテナが起動するようになる。最新版ではlxc.cgroup2.devicesという設定項目が使える。上記の設定はLXC 4.0.2から不要となった。
Failed to mount cgroup at /sys/fs/cgroup/systemd: Operation not permitted
Failed to mount cgroup at /sys/fs/cgroup/systemd: Operation not permitted
[!!!!!!] Failed to mount API filesystems.
Exiting PID 1...
というエラーが出た場合、コンテナ内のsystemdがCGroupファイルシステムのマウントに失敗しているため
lxc.init.cmd = /sbin/init systemd.unified_cgroup_hierarchy=1
または
lxc.mount.auto = cgroup:rw:force
を追加するとよい。後者のcgroup:rw:force
はLXCのバージョンが3.0.4や3.2.1あたりだとこの設定をしても駄目で、3.0.5以降や3.2.2以降だとこれで動くようになる。Ubuntu/Debian の場合新しいバージョンのLXCが https://launchpad.net/~ubuntu-lxc/+archive/ubuntu/daily から入手できる。
libvirt lxc
libvirt 5.6 あたりだと virt-install --memory 2048 --connect lxc:/ --os-variant fedora31 --filesystem /var/lib/lxc/fedora31/rootfs,/ --network none --transient --import --name fedora31
とすると 内部エラー: 'devices' cgroup コントローラーのマウントを確認できません
というエラーが出て異常終了するので、libvirt を 5.10 以降に更新するとlibvirt lxcを使えるようになる。
ホストLinuxから見てコンテナのCGroupが変な位置に置かれる
CGroupのルートに勝手に階層を作るな という話があるが、コンテナのCGroupが/sys/fs/cgroup
直下に作られることがある。それが嫌なら
lxc.cgroup.relative = 1
とする。そのように設定した上で systemctl start lxc@コンテナ名
でLXC特権コンテナを起動するとsystemdが推奨するやり方に従うようになる。
LXD のCGroup 2対応
リリース3.18までは上記のlxc.mount.auto = cgroup:rw:force
に対応する設定がされておらずコンテナがまともに起動しなかった。それに対するイシューを上げてクローズされたがクローズされた後もまだ動作せず、それ以降はアホ臭くなったので見ていない。
LXD 4.0になったら普通に使えることを確認した。
CGroup 2 リソース制限
設定項目 lxc.cgroup2.memory.high
, lxc.cgroup2.pids.max
などで標準的なリソース制限を課すことができる。またlxc.cgroup.devices.*
と同じ機能が lxc.cgroup2.devices.*
で使える。またPSI (Pressure Stall Information)の情報を lxc-cgroup -n コンテナ名 cpu.pressure
などで得ることができる。
LXCによる非特権コンテナ
基本的には https://linuxcontainers.org/lxc/getting-started/ に書いてある通りですが、CGroup V2 を使うことによる変更点が少しあります。ユーザー名はtestuser
とします。CGroup V2を非特権コンテナで使いたい場合githubの2019年12月以降のLXCでないと**多量のトラブルが生じる(本記事最下部参照)**と思います。
ユーザーID置換の設定
newuidmap のインストール
which newuidmap
で /usr/bin/newuidmap
が表示されなければインストールする。ubuntu/debian ではuidmap
パッケージを入れる。このステップはrootでも必要。
/etc/subuid, /etc/subgid の設定
testuser:置き換えられるIDの最初の数字:IDの個数
という行を/etc/subuid
, /etc/subgid
に設定する。IDの個数は最低65536は必要。置き換えられるIDの最初の数字はすでに使われているIDと重ならないように65536以上にする。例えば「testuser:100000:65536」とする。このステップはrootでも必要。
kernel.unprivileged_userns_clone
sysctl kernel.unprivileged_userns_clone
を実行して結果が1では無い場合非ルートユーザーによるUID置換が出来ない。一時的にできるようにするためには sudo sysctl kernel.unprivileged_userns_clone=1
とする。永続的に設定する方法はディストリビューション依存。
lxc-usernsexec
による確認
lxc-usernsexec
を実行してエラーが出ないことを確認する。
LXCの設定
lxc-usernet
testuser veth lxcbr0 10
という行を追加する。これはrootでは不要。また /etc/default/lxc-net
のどこかで USE_LXC_BRIDGE="true"
がセットされていることを確認する。
default.conf
lxc.include = /etc/lxc/default.conf
lxc.idmap = u 0 置き換えられるIDの最初の数字 IDの個数
lxc.idmap = g 0 置き換えられるIDの最初の数字 IDの個数
# 以下はrootから非特権コンテナを開始する場合は不要
lxc.apparmor.profile = unconfined
# rootから(非)特権コンテナを開始するときは下記のようにAppArmorを使える
# lxc.apparmor.profile = generated
上記は/etc/subuid
, /etc/subgid
と合わせる。rootの場合は上記と同じものを /root/lxcidmap.conf
に置いておく。
コンテナイメージの取得
lxc-create
lxc-create -n コンテナ名 -t download
で非特権コンテナで動くように調整されたコンテナイメージを取得する。btrfs を使っているなら -B btrfs
を付けるのもよい。rootで非特権コンテナを取得する場合 -f /root/lxcidmap.conf
を追加すること。そうしないと特権コンテナのイメージを取得してしまうし、設定ファイルも特権コンテナと非特権コンテナで異なるものが初期設定される。
ディレクトリのパーミッション
chmod a+x ~/.local ~/.local/share ~/.local/share/lxc
を実行して誰でもLXCのディレクトリにアクセスできるようにする。それが嫌ならsetfacl
を適切に使う。rootから非特権コンテナを起動する場合は chmod a+x /var /var/lib /var/lib/lxc
とする。
コンテナrootパスワードの設定
lxc-execute -n コンテナ名 -- passwd
でコンテナ内のrootパスワードを設定する。
ホスト上のデバイスファイルへのアクセス
ホスト上のデバイスファイル(例えば /dev/nvidiactl
など)に非特権コンテナからアクセスするための設定は この記事 を参照。
unified CGroup階層を採用するホストLinuxでのLXCの起動
Fedora 31 以降や、起動オプションに systemd.unified_cgroup_hierarchy
を付けて起動されたホストLinuxでは普通にlxc-start
や lxc-execute
を起動するとそれらのコマンドのプロセスが所属するCGroupをlxc-start
などが操作できないため、そもそも起動しないとかコンテナがcgroup コントローラーを使用できないなどのトラブルが生じる。この問題への対処は libpam-cgfs
が伝統的に担ってきたが、unified cgroup hierarchy では原理的にlibpam-cgfs
が動作しない ( https://github.com/lxc/lxc/issues/3198 の議論を参照)。この問題への対応は systemd-run --user --scope -p "Delegate=yes" コマンド
などを使うことで、例えば
systemd-run --user --scope -p "Delegate=yes" lxc-start -F -n コンテナ名
などとする。rootが(非)特権コンテナを lxc.cgroup.relative = 1
を付けて起動する場合も同様。上記のコマンドはlxc-start
が変更してよいCGroupを割り当ててその中でlxc-start
を動作させるようにsystemd
に指示する。
LXCでCGroup V2 がサポートされているという主張は何だったのか…
- LXC 3.0.0から CGroup V2 対応が謳われ
- 開発者もブログ記事を書いて自慢(I’m excited to announce) していたのに
- LXC 3.0.4でもホストLinuxがCGroup V2 (systemd.unified_cgroup_hierarchy) だとrootがコンテナを起動できないとか
- 同じくLXC 3.0.4で一般ユーザー(非root)が別の要因でコンテナを起動できないとか
- LXC 3.2.1でも非特権コンテナまたはlxc.cgroup.relative=1を付けてsystemctlから起動する とコンテナがCGroup V2のリソース制限を何も利用できないとか
- lxc-checkpointが全く動作しないとか
- LXC 3.0.4でも3.2.1でもlibpam-cgfsが何も機能していないとか
- lxc-checkconfigがホストLinuxに何も問題ないのに赤字で警告するとか
いろいろあり過ぎで、いくらなんでもこれで「CGroup V2対応」を謳うのは滅茶苦茶だという印象を持った。かなりムカついたので開発者に英語で文句を直接ギットハブ上で言った