仮想環境(6)

Date: 2021/02/13 (initial publish), 2023/12/25 (last update)

Source: jp/note-00033.md

Previous Post Top Next Post

TOC

Linux Namespaces の雰囲気が分かったところで、非特権ユーザー権限から立ち 上げられたLXC仮想環境を作ってみます。

NOTE: (2023-12-25) LXDを使い出したら、カス環境管理が便利なので以下のシェル操作ベースのコンテナ管理手法は休眠です。

非特権LXC実行環境整備

LXC (1:4.0.6-1) をBulleseye環境で/usr/share/doc/lxc/README.Debianの “Unprivileged containers"に従って設定していきます。(2021/02)

まずKERNELがunprivileged user namespacesを有効にしていることを確認します。

$ sudo uname -a
Linux **** 5.10.0-3-amd64 #1 SMP Debian 5.10.13-1 (2021-02-06) x86_64 GNU/Linux
$ sudo sysctl kernel.unprivileged_userns_clone
kernel.unprivileged_userns_clone = 1

ユーザーアカウント設定の/etc/subuid/etc/subgidはすでに設定されていました。 これらは親システムのUIDやGIDからLXCコンテナ内から見えるUIDやGIDへの対応関係定義 しています。

ネットワーク設定は以下を実行:

$ NAME=$(id -un)
$ sudo sh -c "echo $NAME veth lxcbr0 10 >> /etc/lxc/lxc-usernet

さらに、~/.config/lxc/default.confのユーザー設定を/etc/subuid/etc/subgidに合わせて以下でします。

$ mkdir -p ~/.config/lxc
$ cat >~/.config/lxc/default.conf << EOF
lxc.include = /etc/lxc/default.conf
lxc.idmap = u 0 100000 65536
lxc.idmap = g 0 100000 65536
lxc.mount.auto = proc:mixed sys:ro cgroup:mixed
lxc.apparmor.profile = unconfined
EOF

download templateだけが使えるので、これを使って実行します。

$ lxc-create -t download -n bullseye-user -- -d debian -r bullseye -a amd64
Setting up the GPG keyring
Downloading the image index
Downloading the rootfs
Downloading the metadata
The image cache is now ready
Unpacking the rootfs

---
You just created a Debian bullseye amd64 (20210203_05:24) container.

To enable SSH, run: apt install openssh-server
No default root or user password are set by LXC.
$ cd ~/.local/share/lxc
$ tree -L 2 .
.
└── bullseye-user
    ├── config
    └── rootfs
$ cd bullseye-user
$ ls -la rootfs
total 84
drwxr-xr-x 21 100000 100000 4096 Feb  3 14:29 .
drwxrwx---  3 100000 osamu  4096 Feb 13 18:20 ..
drwxr-xr-x  2 100000 100000 4096 Feb  3 14:27 bin
drwxr-xr-x  2 100000 100000 4096 Jul  9  2019 boot
drwxr-xr-x  3 100000 100000 4096 Feb 13 07:44 dev
drwxr-xr-x 41 100000 100000 4096 Feb 13 23:55 etc
drwxr-xr-x  2 100000 100000 4096 Jul  9  2019 home
drwxr-xr-x 10 100000 100000 4096 Feb  3 14:26 lib
drwxr-xr-x  2 100000 100000 4096 Feb  3 14:26 lib64
drwxr-xr-x  2 100000 100000 4096 Feb  3 14:26 media
drwxr-xr-x  2 100000 100000 4096 Feb  3 14:26 mnt
drwxr-xr-x  2 100000 100000 4096 Feb  3 14:26 opt
drwxr-xr-x  2 100000 100000 4096 Jul  9  2019 proc
drwx------  2 100000 100000 4096 Feb  3 14:26 root
drwxr-xr-x  2 100000 100000 4096 Feb  3 14:27 run
drwxr-xr-x  2 100000 100000 4096 Feb  3 14:27 sbin
drwxr-xr-x  2 100000 100000 4096 Feb  3 14:26 srv
drwxr-xr-x  2 100000 100000 4096 Jul  9  2019 sys
drwxrwxrwt  7 100000 100000 4096 Feb 13 23:59 tmp
drwxr-xr-x 11 100000 100000 4096 Feb  3 14:26 usr
drwxr-xr-x 11 100000 100000 4096 Feb  3 14:26 var

なるほど0(root)であるUIDやGIDが、LXCの外から見ると100000にマップされています。

ここで単純にsudoを使った特権ユーザーのようにlxc-startしてコンテナ環境を 立ち上げようとしてもこけます。ここ、要注意です!

ここは以下の様にlxcパッケージのREADME.Debianの指示どおりsystemd-run–property=Delegate=yes 等とともに用いて実行すればうまく立ち上がります。

$ systemd-run --scope --quiet --user --property=Delegate=yes lxc-start -n bullseye-user
$ lxc-ls -f
NAME          STATE   AUTOSTART GROUPS IPV4       IPV6 UNPRIVILEGED
bullseye-user RUNNING 0         -      10.0.3.224 -    true
$ lxc-attach -n bullseye-user
root@bullseye-user:/#

私はGNOME terminal からの実行なので、lxc-attach等の他のコマンドは systemd-run ...をつけなくても特権ユーザーによるLXCを使っての仮想環境 操作同様に動きました。

ちなみにこれをキーボードで毎回叩くのは大変なので、Bashの初期化ファイルで 以下を定義して使うことにしました。

alias cgdo="systemd-run --scope --quiet --user --property=Delegate=yes"

また、非特権LXC仮想環境でも、仮想環境の設定ファイルconfigを前記の特権LXC 仮想環境と同様にlxc.mount.entryの設定を追加設定することでデーター共有がで きました。

確かに、lxc-attachをしてファイルを操作すればコンテナ内のUIDやGIDと整合した ファイルが生成され問題ないのですが、コンテナ内でコマンド自身が提供されない 場合は意外と面倒です。そんな時に便利なのは、ホスト側に居るままで User Namespacesだけを非特権LXCコンテナ内に切り替えられるlxc-usernsexec(1) コマンドです。

例えば、上記のbullseye-userコンテナの例の続きで、 ~/.local/share/lxc/bullseye-userにいながらコンテナ内のUIDやGIDの 特権ユーザー(UID=0, GID=0)となりファイルリスティングするには単純に 以下とします。

$ lxc-usernsexec -- bash
$ ls -la rootfs
total 84
drwxr-xr-x 21 root root    4096 Feb  3 14:29 .
drwxrwx---  3 root nogroup 4096 Feb 13 18:20 ..
drwxr-xr-x  2 root root    4096 Feb  3 14:27 bin
drwxr-xr-x  2 root root    4096 Jul  9  2019 boot
drwxr-xr-x  3 root root    4096 Feb 13 07:44 dev
drwxr-xr-x 41 root root    4096 Feb 13 23:55 etc
drwxr-xr-x  2 root root    4096 Jul  9  2019 home
drwxr-xr-x 10 root root    4096 Feb  3 14:26 lib
drwxr-xr-x  2 root root    4096 Feb  3 14:26 lib64
drwxr-xr-x  2 root root    4096 Feb  3 14:26 media
drwxr-xr-x  2 root root    4096 Feb  3 14:26 mnt
drwxr-xr-x  2 root root    4096 Feb  3 14:26 opt
drwxr-xr-x  2 root root    4096 Jul  9  2019 proc
drwx------  2 root root    4096 Feb  3 14:26 root
drwxr-xr-x  2 root root    4096 Feb  3 14:27 run
drwxr-xr-x  2 root root    4096 Feb  3 14:27 sbin
drwxr-xr-x  2 root root    4096 Feb  3 14:26 srv
drwxr-xr-x  2 root root    4096 Jul  9  2019 sys
drwxrwxrwt  7 root root    4096 Feb 13 23:59 tmp
drwxr-xr-x 11 root root    4096 Feb  3 14:26 usr
drwxr-xr-x 11 root root    4096 Feb  3 14:26 var

コンテナ内の0(root)であるUIDやGIDが、LXCの外から見ると100000にマップ されていたのが、lxc-usernsexecを用いて立ち上げたコンテナ外のbash シェル環境からもコンテナ内のUIDやGIDになっています。

ちなみに非特権LXCのファイルの場所は以下です。

また、システムのCgroupの内容状況は、systemd-cglsコマンドでリストできます。

LXC仮想環境利用のTips

カーネルのLXCサポートの確認

現在のカーネルが lxc に必要な機能をサポートしているか確認は lxc-checkconfig(1)を実行します。

$ lxc-checkconfig
LXC version 4.0.6
Kernel configuration not found at /proc/config.gz; searching...
Kernel configuration found at /boot/config-5.10.0-3-amd64
--- Namespaces ---
Namespaces: enabled
Utsname namespace: enabled
Ipc namespace: enabled
Pid namespace: enabled
User namespace: enabled
Network namespace: enabled

--- Control groups ---
Cgroups: enabled

Cgroup v1 mount points:


Cgroup v2 mount points:
/sys/fs/cgroup

Cgroup v1 systemd controller: missing
Cgroup v1 freezer controller: missing
Cgroup namespace: required
Cgroup device: enabled
Cgroup sched: enabled
Cgroup cpu account: enabled
Cgroup memory controller: enabled
Cgroup cpuset: enabled

--- Misc ---
Veth pair device: enabled, loaded
Macvlan: enabled, not loaded
Vlan: enabled, not loaded
Bridges: enabled, loaded
Advanced netfilter: enabled, loaded
CONFIG_NF_NAT_IPV4: missing
CONFIG_NF_NAT_IPV6: missing
CONFIG_IP_NF_TARGET_MASQUERADE: enabled, not loaded
CONFIG_IP6_NF_TARGET_MASQUERADE: enabled, not loaded
CONFIG_NETFILTER_XT_TARGET_CHECKSUM: enabled, loaded
CONFIG_NETFILTER_XT_MATCH_COMMENT: enabled, not loaded
FUSE (for use with lxcfs): enabled, loaded

--- Checkpoint/Restore ---
checkpoint restore: enabled
CONFIG_FHANDLE: enabled
CONFIG_EVENTFD: enabled
CONFIG_EPOLL: enabled
CONFIG_UNIX_DIAG: enabled
CONFIG_INET_DIAG: enabled
CONFIG_PACKET_DIAG: enabled
CONFIG_NETLINK_DIAG: enabled
File capabilities:

Note : Before booting a new kernel, you can check its configuration
usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig

Debianパッケージ作成

Debianパッケージ作成に必要なパッケージは正確にはDebian Policyで規定されています。ただ実務的には、 LXCを以下の手順で使うと、ホストシステムをsid環境にして不安定にすることなく作業がはかどります。

まず、ベースとなるsidで作成されたLXC仮想環境に以下のパッケージを導入します。 (前述の手順です)

さらに、lxc-copyを使い、毎回使い捨てのLXC仮想環境を準備し、その中でホストシステムと 共有されたディレクトリー内に置かれたDebianソースのdebian/controlに基づき、パッケージビルドに 必要なパッケージを追加導入します。devscriptsパッケージに含まれるmk-build-depsコマンドが、 この追加導入操作に便利です。特に-iオプションを使うと便利です。この際、mk-build-deps 実行前に、最新システム環境を確保するapt update; apt full-upgradeを実行する のが好ましいでしょう。

これなら、pbuilder等の複雑なコマンドを覚えなくとも作業がはかどります。

Debianパッケージのデバグ

Debianパッケージのデバグの際には、毎回パッケージ依存関係確認のためにインストールするのは 無駄なので、使い捨てではなく必要な全パッケージがインストールされたLXC仮想環境を準備し、 それをベースにlxc-copyを使い、毎回使い捨てのLXC仮想環境を準備した方が効率的です。

PDFファイル作成にtexlive-full等の巨大パッケージが利用される際には、この配慮は重要です。

SSH接続

ホスト側から普通のリモートサーバー同様に操作するには、LXC仮想環境には以下のパッケージを 最低限導入するのがいい。

Python2 プログラムの実行

Debian bullseye 11 以降はPython3のみのサポートとなるので、古いPython2 プログラムを 実行しその動作を確認するには、buster環境で作成されたLXC仮想環境を準備すると便利です。

参考情報

Previous Post Top Next Post