7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

一般ユーザーからCGroup V2でLXCを使う

Last updated at Posted at 2019-12-02

(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のデバイスコントローラーを使う設定がされていて、そのようなコントローラーが使えずにエラーが起きている。

/var/lib/lxc/コンテナ名/configの末尾
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ファイルシステムのマウントに失敗しているため

/var/lib/lxc/コンテナ名/configの末尾
lxc.init.cmd = /sbin/init systemd.unified_cgroup_hierarchy=1

または

/var/lib/lxc/コンテナ名/configの末尾
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直下に作られることがある。それが嫌なら

/var/lib/lxc/コンテナ名/configの末尾
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 の設定

/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

/etc/lxc/lxc-usernet
testuser veth lxcbr0 10

という行を追加する。これはrootでは不要。また /etc/default/lxc-net のどこかで USE_LXC_BRIDGE="true" がセットされていることを確認する。

default.conf

~/.config/lxc/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-startlxc-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 がサポートされているという主張は何だったのか…

いろいろあり過ぎで、いくらなんでもこれで「CGroup V2対応」を謳うのは滅茶苦茶だという印象を持った。かなりムカついたので開発者に英語で文句を直接ギットハブ上で言った

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?