schroot を使った軽量な隔離環境の構築

概要

schroot は、choot を使った隔離環境の一種で、docker とはまた違った使いやすさがあります。
本記事では、 Ubuntu 22.04 に Debian bullseye の schroot 環境を構築していきます。

schroot 環境構築

インストール

# apt install schroot debootstrap

Debian bullseye の root filesystem を取得

# mkdir -p /srv/chroot/bullseye
# debootstrap bullseye /srv/chroot/bullseye

schroot 設定ファイルの編集

filename: /etc/schroot/schroot.conf

[bullseye]
type=directory
description=Debian bullseye
directory=/srv/chroot/bullseye

基本的な使い方

-c で、設定ファイルに記述した chroot を指定します。

# schroot -c bullseye
(bullseye)root@ubuntu:~#

末尾にコマンドを指定すれば、それが実行されます。
以下では、-d でディレクトリを指定して、ls -la を実行しています。
コマンドの引数が schroot の option と混同することを避けるため、-- を付けています。

# schroot -c bullseye -d /root -- ls -la
total 20
drwx------  2 root root 4096 Dec 22 14:10 .
drwxr-xr-x 17 root root 4096 Dec 22 13:36 ..
-rw-------  1 root root  430 Dec 22 15:43 .bash_history
-rw-r--r--  1 root root  571 Apr 10  2021 .bashrc
-rw-r--r--  1 root root  161 Jul  9  2019 .profile

session の概念について

上記コマンドで schroot 環境に入っている間は、一時的な automatic session が作成されています。
本来は省略可能ですが、明示的に指定することもできます。

# schroot -c bullseye --automatic-session

session生成時には profile に基づいて、各種 directory の bind mount や file copy が行われています。
profile は schroot.conf にどれを使用するかを記述します。
特に指定しなかった場合は、default profile が使用されます。

本来は省略可能ですが、明示的に default profile を指定することもできます。

[bullseye]
type=directory
description=Debian bullseye
directory=/srv/chroot/bullseye
profile=default

profile の実態は /etc/schroot/ 配下にある directory となっています。
default profile の設定データは、/etc/schroot/default/ になります。

# ls /etc/schroot/default/
copyfiles  fstab  nssdatabases

bind mount が控えめな minimal profile というものもあります。

# ls /etc/schroot/default/minimal/
copyfiles  fstab  nssdatabases

df -a コマンドで、session により、bind mount が行われていることを確認できます。
default profile では、ホスト側 /home → ゲスト側 /home の bind mount も行われています。

# df -a | grep schroot
/dev/vda2      102109124 14293440  82582688  15% /run/schroot/mount/bullseye-eb4ee75d-202a-4164-8a30-5382cfcbb5a7
proc                   0        0         0    - /run/schroot/mount/bullseye-eb4ee75d-202a-4164-8a30-5382cfcbb5a7/proc
sysfs                  0        0         0    - /run/schroot/mount/bullseye-eb4ee75d-202a-4164-8a30-5382cfcbb5a7/sys
udev             4013052        0   4013052   0% /run/schroot/mount/bullseye-eb4ee75d-202a-4164-8a30-5382cfcbb5a7/dev
devpts                 0        0         0    - /run/schroot/mount/bullseye-eb4ee75d-202a-4164-8a30-5382cfcbb5a7/dev/pts
/dev/vda2      102109124 14293440  82582688  15% /run/schroot/mount/bullseye-eb4ee75d-202a-4164-8a30-5382cfcbb5a7/home
/dev/vda2      102109124 14293440  82582688  15% /run/schroot/mount/bullseye-eb4ee75d-202a-4164-8a30-5382cfcbb5a7/tmp

minimal profile を使った場合は、以下のようになります。

# df -a | grep schroot
/dev/vda2      102109124 14013132  82862996  15% /run/schroot/mount/bullseye-82588b75-f674-4a1f-8ccf-93deb8bbbfa2
proc                   0        0         0    - /run/schroot/mount/bullseye-82588b75-f674-4a1f-8ccf-93deb8bbbfa2/proc
sysfs                  0        0         0    - /run/schroot/mount/bullseye-82588b75-f674-4a1f-8ccf-93deb8bbbfa2/sys

default profile、minimal profile の fstab は、以下のようになっています。

filename: /etc/schroot/default/fstab

# <file system> <mount point>   <type>  <options>       <dump>  <pass>
/proc           /proc           none    rw,bind         0       0
/sys            /sys            none    rw,bind         0       0
/dev            /dev            none    rw,bind         0       0
/dev/pts        /dev/pts        none    rw,bind         0       0
/home           /home           none    rw,bind         0       0
/tmp            /tmp            none    rw,bind         0       0

filename: /etc/schroot/minimal/fstab

# <file system> <mount point>   <type>  <options>       <dump>  <pass>
/proc           /proc           none    rw,bind         0       0
/sys            /sys            none    rw,bind         0       0

session の動作について

schroot 環境から実行したプロセスは、schroot 環境を抜けて、session が閉じたときに、バックグラウンド動作のものも含めて、すべて終了されます。
ここが、純粋な chroot 環境と比較して、便利なところです。

一方で、コンソールを閉じると、session が閉じて、隔離環境内のすべてのプロセスが終了してしまうため、ssh server や cron を service として動かすためには、バックグランドで維持される session を作成する必要があります。(automatic session ではない session 生成が必要)

session や chroot 定義のリスト

schroot -l で、schroot.conf に記述した chroot 定義をリスト表示します。

# schroot -l
chroot:bullseye

schroot -l -a で、上記に加え、現在アクティブな session も表示します。

# schroot -l -a
chroot:bullseye
session:bullseye-7290732f-e30d-48e0-85f1-d6dba8c9ccec

# schroot --list --all
chroot:bullseye
session:bullseye-7290732f-e30d-48e0-85f1-d6dba8c9ccec

chroot 定義の情報表示

schroot -i -c で、schroot.conf に記述した特定のchroot 定義の情報を表示します。

# schroot -i -c bullseye
  --- Chroot ---
  Name                   bullseye
  Description            Debian bullseye
  Type                   directory
  Message Verbosity      normal
  Users                  
  Groups                 
  Root Users             
  Root Groups            
  Aliases                
  Preserve Environment   false
  Default Shell          
  Environment Filter     ^(BASH_ENV|CDPATH|ENV|HOSTALIASES|IFS|KRB5_CONFIG|KRBCONFDIR|KRBTKFILE|KRB_CONF|LD_.*|LOCALDOMAIN|NLSPATH|PATH_LOCALE|RES_OPTIONS|TERMINFO|TERMINFO_DIRS|TERMPATH)$
  Run Setup Scripts      true
  Configuration Profile  minimal
  Script Configuration   
  Session Managed        true
  Session Cloned         false
  Session Purged         false
  Directory              /srv/chroot/bullseye
  Personality            undefined
  User Modifiable Keys   
  Root Modifiable Keys   
  User Data              
    setup.config         minimal/config
    setup.copyfiles      minimal/copyfiles
    setup.fstab          minimal/fstab
    setup.nssdatabases   minimal/nssdatabases
  Filesystem Union Type  none

ユーザ権限で実行

schroot.conf に users=[user name] を追加すると、そのユーザ権限で schroot 環境に入れます。

filename: /etc/schroot/schroot.conf

  [bullseye]
  type=directory
  description=Debian bullseye
  directory=/srv/chroot/bullseye
+ users=test1

これで test1 ユーザが、schroot で bullseye に入れるようになりました。

$ schroot -c bullseye -d /
(bullseye)test1@ubuntu:/$

schroot.conf に root-users=[user name] を追加すると、そのユーザが root 権限で schroot に入れるようになります。

filename: /etc/schroot/schroot.conf

  [bullseye]
  type=directory
  description=Debian bullseye
  directory=/srv/chroot/bullseye
+ root-users=test1

これで test1 ユーザが、root 権限で bullseye に入れるようになりました。
-u で root を指定して実行します。

$ schroot -c bullseye -u root -d /root
(bullseye)root@ubuntu:~#

この root 権限は、docker の非特権コンテナとは異なり、ホストの root 権限そのものです。
kernel 内では、root (id = 0) として扱われます。
/usr/bin/schroot に SUID (Set User ID) を付けることで、これを実現しています。
セキュリティには十分配慮する必要があります。

chroot コマンドで環境に入る

schroot のように、bind mount や配下のプロセス管理はないですが、普通の chroot コマンドで環境に入ることもできます。
schroot 環境に入れず、どうしようもないときは、一旦これで入れます。
もっとも、ファイルが見えているため、大抵の設定ファイルはそのまま修正できますが・・

# cd /srv/chroot/bullseye
# chroot ./ /bin/bash

普通の chroot コマンドでは、proc、sys、dev を bind mount して chroot というパターンが一般的によく使われます。

# cd /srv/chroot/bullseye
# mount --bind /proc ./proc
# mount --bind /sys ./sys
# mount --bind /dev ./dev
# chroot ./ /bin/bash

chroot コマンドは、第一引数で chroot する場所を指定し、第二引数で起動するプログラムを指定します。上記の場合は、カレントディレクトリ ./ に chroot して、/bin/bash を実行するという意味になります。
chroot で ./ に入った後は、/srv/chroot/bullseye がルートファイルシステム (= / )として見えています。
この /bin/bash がホスト側のものと誤解されることがよくありますが、chroot した後の PATH の /bin/bash であるため、実行しているのは、/srv/chroot/bullseye/bin/bash です。