「Linux コンテナ」の版間の差分
Kusanaginoturugi (トーク | 投稿記録) (Linux コンテナに変更) |
Kusanaginoturugi (トーク | 投稿記録) (関連記事を追加) |
||
6行目: | 6行目: | ||
{{Related|Cgroups}} |
{{Related|Cgroups}} |
||
{{Related|Docker}} |
{{Related|Docker}} |
||
+ | {{Related|Incus}} |
||
{{Related|Linux コンテナ/VPN の使用}} |
{{Related|Linux コンテナ/VPN の使用}} |
||
{{Related|LXD}} |
{{Related|LXD}} |
2024年5月11日 (土) 14:40時点における版
LinuX Containers (LXC) はオペレーティングシステムレベルの仮想化手法であり、一つのコントロールホスト (LXC ホスト) で独立した Linux システム (コンテナ) を複数動作させることができます。仮想マシンではありませんが、CPU やメモリ、ブロック I/O、ネットワークなどが個別に用意された仮想環境として使えます。LXC は LXC ホストの Linux カーネルによる cgroups 機能によって賄われています。chroot に似ていますが、より強力な分離を実現します。
LXD は LXC のマネージャーとして使用できます。このページでは、LXC を直接使用する方法について説明します
LXC の代わりとして systemd-nspawn や docker でもコンテナを使うことができます。
目次
特権コンテナと非特権コンテナ
LXC は特権または非特権で動作するように設定することができます。
一般的に、非特権コンテナは特権コンテナよりも安全だとされています [1]。非特権コンテナでは分離の程度が原理上増すからです。非特権コンテナではコンテナの root の UID をホストの root 以外の UID にマッピングすることで、コンテナの中からホスト環境に影響を及ぼすことを難しくします。たとえ攻撃者がコンテナから脱獄しても、ホスト側では攻撃者に権限がありません。
現在 Arch のパッケージでは特権コンテナは最初からサポートしています。非特権コンテナはカーネル設定を行わないと利用できません。Arch の linux カーネルでは通常ユーザーでユーザー名前空間が無効になっているためです。この記事では特権・非特権両方のコンテナの情報を載せていますが、非特権を使うには設定が必要です。
非特権コンテナの例
UID マッピングの能力を説明するために、非特権コンテナで以下のコマンドを実行したときの出力を考えてみましょう。ps
の出力でコンテナ化されたプロセスの所有者が同じくコンテナ化された root ユーザーとなっていることが確認できます:
[root@unprivileged_container /]# ps -ef | head -n 5 UID PID PPID C STIME TTY TIME CMD root 1 0 0 17:49 ? 00:00:00 /sbin/init root 14 1 0 17:49 ? 00:00:00 /usr/lib/systemd/systemd-journald dbus 25 1 0 17:49 ? 00:00:00 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation systemd+ 26 1 0 17:49 ? 00:00:00 /usr/lib/systemd/systemd-networkd
ホスト側では、コンテナ化された root プロセスはマッピングされたユーザー (ID>100000) で動作します。ホストの root ユーザーではありません:
[root@host /]# lxc-info -Ssip --name sandbox State: RUNNING PID: 26204 CPU use: 10.51 seconds BlkIO use: 244.00 KiB Memory use: 13.09 MiB KMem use: 7.21 MiB
[root@host /]# ps -ef | grep 26204 | head -n 5 UID PID PPID C STIME TTY TIME CMD 100000 26204 26200 0 12:49 ? 00:00:00 /sbin/init 100000 26256 26204 0 12:49 ? 00:00:00 /usr/lib/systemd/systemd-journald 100081 26282 26204 0 12:49 ? 00:00:00 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation 100000 26284 26204 0 12:49 ? 00:00:00 /usr/lib/systemd/systemd-logind
セットアップ
必要なソフトウェア
lxc と arch-install-scripts パッケージをインストールしてください。
非特権コンテナのサポートを有効化 (任意)
/etc/lxc/default.conf
を変更して次の行を含めます:
lxc.idmap = u 0 100000 65536 lxc.idmap = g 0 100000 65536
言い換えると、65536 個の連続した uid の範囲をマップします。コンテナ側の uid 0 (ホストの観点からは uid 100000 になります) から、ホストが uid 165535 として認識するコンテナ側の uid 65535 までです。同じマッピングを gid に適用します。
/etc/subuid
と /etc/subgid
の両方を作成して、コンテナを実行できる各ユーザーのコンテナ化された uid/gid ペアへのマッピングを含めます。以下の例は、単純に root ユーザー (および systemd システムユニット) を対象としています:
/etc/subuid
root:100000:65536
/etc/subgid
root:100000:65536
さらに、非特権ユーザーとして非特権コンテナを実行することは、事前に cgroup を委任した場合にのみ機能します (この制限は、liblxc ではなく cgroup2 委任モデルによって強制されます) 次の systemd コマンドを使用して cgroup を委任します (LXC - Getting started: Creating unprivileged containers as a user):
$ systemd-run --unit=myshell --user --scope -p "Delegate=yes" lxc-start container_name
これは他の lxc コマンドでも同様に機能します。
/etc/systemd/system/user@.service.d/delegate.conf
[Service] Delegate=cpu cpuset io memory pids
linux-hardened などカスタムカーネル上の特権のないコンテナ
linux-hardened またはカスタム カーネル上で 非特権 コンテナを実行したいユーザーは、いくつかの追加のセットアップ手順を完了する必要があります。
まず、ユーザー名前空間をサポートするカーネル (CONFIG_USER_NS
を備えたカーネル) が必要です。すべての Arch Linux カーネルは CONFIG_USER_NS
をサポートしています。ただし、より一般的なセキュリティ上の懸念により、linux-hardened カーネルは、root ユーザーに対してのみ有効になったユーザー名前空間とともに出荷されます。そこに 非特権 コンテナを作成するには 2 つのオプションがあります:
- 特権のないコンテナは root としてのみ起動してください。また、現在の値が
0
の場合、sysctl 設定user.max_user_namespaces
に環境に合わせて正の値を指定します (これにより、lxc info --show-log container_name
で見られるFailed to clone process in new user namespace
というエラーが修正されます) - linux-hardened および
lxd 5.0.0
では、root:1000000:65536
の範囲を使用するように/etc/subuid
および/etc/subgid
を設定する必要がある場合があります。最初 のコンテナを特権付きで起動する必要がある場合もあります。これにより、newuidmap failed to write mapping "newuidmap: uid range [0-1000000000) -> [1000000-1001000000) not allowed" エラーが修正されます。
- sysctl 設定
kernel.unprivileged_userns_clone
を有効にして、通常のユーザーが特権のないコンテナを実行できるようにします。これは、root としてsysctl kernel.unprivileged_userns_clone=1
を実行することで現在のセッションに対して行うことができ、また、sysctl.d(5) を使用して永続化することもできます。
ホストネットワーク設定
LXC は、さまざまな仮想ネットワークタイプとデバイスをサポートします (lxc.container.conf(5) を参照) ホスト上のブリッジデバイスは、このセクションで説明するほとんどのタイプの仮想ネットワークに必要です。
考慮すべき主な設定がいくつかあります。
- ホストブリッジ
- NAT ブリッジ
ホストブリッジでは、ホストのネットワークマネージャーが共有ブリッジインターフェイスを管理する必要があります。ホストとすべての lxc には、同じネットワーク内の IP アドレスが割り当てられます (たとえば、192.168.1.x) Web サーバーや VPN サーバーなど、ネットワークに公開されたサービスをコンテナ化することが目的の場合、これはより単純になる可能性があります。ユーザーは、lxc を物理 LAN 上の単なる別の PC と考えることができ、それに応じてルーター内の必要なポートを転送できます。追加されたシンプルさは、追加の脅威ベクトルと考えることもできます。WAN トラフィックが lxc に転送される場合、別の範囲で lxc を実行すると、脅威の表面が小さくなります。
NAT ブリッジでは、ホストのネットワークマネージャーがブリッジを管理する必要はありません。lxc には、lxcbr0
という NAT ブリッジを作成する lxc-net
が同梱されています。NAT ブリッジは、ホストのイーサネット デバイスや物理ネットワークにブリッジされていないプライベート ネットワークを備えたスタンドアロンブリッジです。ホスト内にプライベートサブネットとして存在します。
ホストブリッジの使用
ネットワークブリッジ を参照してください。
NAT ブリッジの使用
dnsmasq、を インストール して下さい、これは lxc-net
の依存関係です。ブリッジを開始する前に、まずブリッジの設定ファイルを作成します:
/etc/default/lxc-net
# Leave USE_LXC_BRIDGE as "true" if you want to use lxcbr0 for your # containers. Set to "false" if you'll use virbr0 or another existing # bridge, or mavlan to your host's NIC. USE_LXC_BRIDGE="true" # If you change the LXC_BRIDGE to something other than lxcbr0, then # you will also need to update your /etc/lxc/default.conf as well as the # configuration (/var/lib/lxc/<container>/config) for any containers # already created using the default config to reflect the new bridge # name. # If you have the dnsmasq daemon installed, you'll also have to update # /etc/dnsmasq.d/lxc and restart the system wide dnsmasq daemon. LXC_BRIDGE="lxcbr0" LXC_ADDR="10.0.3.1" LXC_NETMASK="255.255.255.0" LXC_NETWORK="10.0.3.0/24" LXC_DHCP_RANGE="10.0.3.2,10.0.3.254" LXC_DHCP_MAX="253" # Uncomment the next line if you'd like to use a conf-file for the lxcbr0 # dnsmasq. For instance, you can use 'dhcp-host=mail1,10.0.3.100' to have # container 'mail1' always get ip address 10.0.3.100. #LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf # Uncomment the next line if you want lxcbr0's dnsmasq to resolve the .lxc # domain. You can then add "server=/lxc/10.0.3.1' (or your actual $LXC_ADDR) # to your system dnsmasq configuration file (normally /etc/dnsmasq.conf, # or /etc/NetworkManager/dnsmasq.d/lxc.conf on systems that use NetworkManager). # Once these changes are made, restart the lxc-net and network-manager services. # 'container1.lxc' will then resolve on your host. #LXC_DOMAIN="lxc"
次に、コンテナがブリッジを使用するように LXC コンテナテンプレートを変更する必要があります。
/etc/lxc/default.conf
lxc.net.0.type = veth lxc.net.0.link = lxcbr0 lxc.net.0.flags = up lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx
Optionally create a configuration file to manually define the IP address of any containers:
/etc/lxc/dnsmasq.conf
dhcp-host=playtime,10.0.3.100
lxc-net.service
を 起動/有効化 してブリッジ インターフェイスを作成します。
ファイアウォールの考慮事項
ホストマシンが実行しているファイアウォールによっては、lxcbr0
からホストへの受信パケットと、lxcbr0
からの送信パケットがホストを経由して他のネットワークに到達することを許可する必要がある場合があります。これをテストするには、IP 割り当てに DHCP を使用するように設定されたコンテナを起動して、lxc-net
がコンテナに IP アドレスを割り当てることができるかどうかを確認してください (lxc-ls -f
IP が割り当てられていない場合は、ホストのポリシーを調整する必要があります。
ufw のユーザーは、次の 2 行 を実行するだけです。これを有効にするには:
# ufw allow in on lxcbr0 # ufw route allow in on lxcbr0
あるいは、nftables のユーザーは、/etc/nftables.conf
を変更できます (そして、nft -f /etc/nftables.conf
で再ロードします。設定が正しいかどうかを確認してください) nft -cf /etc/nftables.conf
これでコンテナがインターネットにアクセスできるようになります ("eth0"
を、インターネットにアクセスできるシステム上のデバイスに置き換えます。 ip link
を使用して既存のデバイスをリストします):
/etc/nftables.conf
table inet filter { chain input { ... iifname "lxcbr0" accept comment "Allow lxc containers" pkttype host limit rate 5/second counter reject with icmpx type admin-prohibited counter } chain forward { ... iifname "lxcbr0" oifname "eth0" accept comment "Allow forwarding from lxcbr0 to eth0" iifname "eth0" oifname "lxcbr0" accept comment "Allow forwarding from eth0 to lxcbr0" } }
さらに、コンテナーは 10.0.3.x サブネット上で実行されているため、ssh、httpd などのサービスへの外部アクセスは lxc にアクティブに転送される必要があります。原則として、ホスト上のファイアウォールは、コンテナ上の予期されるポートで受信トラフィックを転送する必要があります。
iptables ルールの例
このルールの目的は、lxc への ssh トラフィックを許可することです:
# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 2221 -j DNAT --to-destination 10.0.3.100:22
このルールは、ポート 2221 から発信される tcp トラフィックをポート 22 の lxc の IP アドレスに転送します。
LAN 上の別の PC からコンテナーに ssh 接続するには、ポート 2221 でホストに ssh 接続する必要があります。その後、ホストはそのトラフィックをコンテナに転送します。
$ ssh -p 2221 host.lan
ufw ルールの例
ufw を使用する場合は、これを永続化するために、/etc/ufw/before.rules
の最後に次の行を追加します:
/etc/ufw/before.rules
*nat :PREROUTING ACCEPT [0:0] -A PREROUTING -i eth0 -p tcp --dport 2221 -j DNAT --to-destination 10.0.3.100:22 COMMIT
非 root ユーザーとしてコンテナを実行する
非 root ユーザーとしてコンテナーを作成して起動するには、追加の構成を適用する必要があります。
/etc/lxc/lxc-usernet
にユーザーネットファイルを作成します。lxc-usernet(5) によると、1 行あたりのエントリは次のとおりです。
user type bridge number
コンテナを作成する必要があるユーザーを使用してファイルを設定します。ブリッジは、/etc/default/lxc-net
で定義されているものと同じになります。
/etc/lxc/default.conf
のコピーが、非 root ユーザーのホームディレクトリに必要です。例: ~/.config/lxc/default.conf
(ディレクトリを作成します) 必要に応じて)
非 root ユーザーとしてコンテナを実行するには、~/.local/share/
に対する +x
権限が必要です。コンテナを起動する前に、chmod を使用して変更を加えます。
コンテナの作成
特権コンテナの場合、/usr/share/lxc/templates
からコンテナ化するディストロに合わせてテンプレートを選択してください。Arch 以外のディストロをコンテナに入れたい場合、ディストロによってホストにパッケージを追加でインストールする必要があります:
- Debian ベース: debootstrap。
- Fedora ベース: yumAUR。
lxc-create
を実行してコンテナを作成します。デフォルトでは LXC の root ファイルシステムは /var/lib/lxc/CONTAINER_NAME/rootfs
にインストールされます。例えば "playtime" という名前の Arch Linux LXC を作成:
# lxc-create -n playtime -t /usr/share/lxc/templates/lxc-archlinux
非特権コンテナを使いたい場合は -t download
を使用してイメージを選択してください。例:
# lxc-create -n playtime -t download
コンテナの設定
以下の例は特権コンテナと非特権コンテナどちらでも同じように使えます非特権コンテナの場合、lxc.idmap = u 0 100000 65536
and the lxc.idmap = g 0 100000 65536
values optionally defined in the #非特権コンテナのサポートを有効化 (任意)セクションで定義した lxc.idmap = u 0 100000 65536
や lxc.idmap = g 0 100000 65536
などの値がデフォルトで存在するはずです。
ネットワークの基本設定
プロセスが /var/lib/lxc/CONTAINER_NAME/config
に定義されたコンテナを使う場合、システムリソースは仮想化され分離されます。デフォルトでは、作成プロセスはネットワークサポートを省いた最小限のセットアップを作成します。以下はネットワークを設定する例です:
/var/lib/lxc/playtime/config
# Template used to create this container: /usr/share/lxc/templates/lxc-archlinux # Parameters passed to the template: # For additional config options, please look at lxc.container.conf(5) ## default values lxc.rootfs.path = /var/lib/lxc/playtime/rootfs lxc.uts.name = playtime lxc.arch = x86_64 lxc.include = /usr/share/lxc/config/archlinux.common.conf ## network lxc.net.0.type = veth lxc.net.0.link = br0 lxc.net.0.flags = up lxc.net.0.name = eth0 lxc.net.0.hwaddr = ee:ec:fa:e9:56:7d # uncomment the next two lines if static IP addresses are needed # leaving these commented will imply DHCP networking # #lxc.net.0.ipv4.address = 192.168.0.3/24 #lxc.net.0.ipv4.gateway = 192.168.0.1
コンテナの中でマウント
特権コンテナの場合、ホストでディレクトリを選択してコンテナにバインドマウントすることができます。同一アーキテクチャをコンテナ化している場合にホストとコンテナで pacman のパッケージを共有するなどの使用方法が考えられます。また、共有ディレクトリとして使用することもできます。構文は以下の通りです:
lxc.mount.entry = /var/cache/pacman/pkg var/cache/pacman/pkg none bind 0 0
Xorg プログラムの設定 (任意)
ホストのディスプレイでプログラムを動かしたい場合、コンテナ化されたプログラムがホストのリソースにアクセスできるようにバインドマウントを定義する必要があります。/var/lib/lxc/playtime/config
に以下のセクションを追加してください:
## for xorg lxc.mount.entry = /dev/dri dev/dri none bind,optional,create=dir lxc.mount.entry = /dev/snd dev/snd none bind,optional,create=dir lxc.mount.entry = /tmp/.X11-unix tmp/.X11-unix none bind,optional,create=dir,ro lxc.mount.entry = /dev/video0 dev/video0 none bind,optional,create=file
LXC のゲスト側に permission denied エラーが表示される場合、ホスト側で xhost +
を実行してゲストからホストのディスプレイサーバーに接続できるようにする必要があります。このようにディスプレイサーバーを開くことはセキュリティ上問題があるので注意してください。
OpenVPN の設定
コンテナで OpenVPN を実行したい場合は Linux コンテナ/VPN の使用の記事を読んで下さい。
コンテナの管理
基本的な使用方法
インストール済みの LXC コンテナを確認するには:
# lxc-ls -f
Systemd で lxc@CONTAINER_NAME.service
を使うことで LXC を起動したり停止することができます。lxc@CONTAINER_NAME.service
を有効化するとホストシステムの起動時に LXC が立ち上がるようになります。
systemd を使わずに LXC を起動・停止することも可能です。コンテナを起動:
# lxc-start -n CONTAINER_NAME
コンテナを停止:
# lxc-stop -n CONTAINER_NAME
コンテナにログインするには:
# lxc-console -n CONTAINER_NAME
ログイン時に pts/0 と lxc/tty1 が表示される場合:
# lxc-console -n CONTAINER_NAME -t 0
ログインしたら、他の linux システムと同じようにコンテナを扱って、root パスワードを設定し、ユーザーを作成、パッケージのインストールなどを行って下さい。
コンテナにアタッチ:
# lxc-attach -n CONTAINER_NAME --clear-env
lxc-console とほぼ同じですが、自動的にログインを通り越してコンテナの中の root プロンプトにアクセスします。 --clear-env
フラグを指定しなかった場合、ホストは環境変数をコンテナに渡します ($PATH
など、コンテナが他のディストリビューションの場合、一部のコマンドが機能しなくなる可能性があります)。
高度な使用方法
LXC の複製
同じコンテナを複数実行する必要があるときはスナップショットを使うことで管理を簡単にできます。最新状態にしておくベースコンテナをひとつだけセットアップして、それを必要に応じて複製 (スナップショットを作成) するという方法です。スナップショットは overlayfs を使用してデータの差異部分だけをディスクに書き込むためディスク容量を節約してオーバーヘッドをなくすことができます。ベースシステムは読み取り専用にしてスナップショットにのみ overlayfs で変更を加えられるようにします。
欠点としてスナップショットを作成しているときにベースの lxc を実行することはできません。
上に書いているようにコンテナをセットアップしたら "base" と名前を付けます。以下のコマンドで "base" コンテナのスナップショット ("snap1" と "snap2") を作成します:
# lxc-copy -n base -N snap1 -B overlayfs -s # lxc-copy -n base -N snap2 -B overlayfs -s
スナップショットは他のコンテナと同じように起動・停止できます。以下のコマンドでスナップショットを削除できます (ベースの lxc に変更は加えられません):
# lxc-destroy -n snap1 -f
pi-hole と OpenVPN のスナップショットを管理する systemd ユニットとラッパースクリプトが lxc-snapshotsAUR[リンク切れ: パッケージが存在しません] パッケージでインストールできます。
特権コンテナを非特権コンテナに変換
非特権コンテナを使うようにシステムを設定したら (#非特権コンテナのサポートを有効化 (任意) を参照), nsexec-bzrAUR に含まれている uidmapshift
という名前のユーティリティで既存の特権コンテナを非特権コンテナに変換できます。イメージの再ビルドは不要です。
以下のようにコマンドを実行することで変換できます:
# uidmapshift -b /var/lib/lxc/foo 0 100000 65536
利用可能なオプションは引数を付けずに uidmapshift
を実行することで確認可能です。
Xorg プログラムの実行
対象のコンテナにアタッチまたは SSH でログインしてホストの X セッションの DISPLAY ID をプログラムを呼び出すときに指定します。ほとんどの場合、ディスプレイは常時 0 です。
ホストのディスプレイでコンテナから Firefox を起動する例:
$ DISPLAY=:0 firefox
もしくは、直接コンテナにアタッチしたり接続する代わりに、以下のコマンドを使って自動的にホストにディスプレイを設定することもできます:
# lxc-attach -n playtime --clear-env -- sudo -u YOURUSER env DISPLAY=:0 firefox
トラブルシューティング
root ログインが失敗する
lxc-console を使ってログインしようとすると以下のエラーが表示される場合:
login: root Login incorrect
そしてコンテナの journalctl
で以下のように表示される場合:
pam_securetty(login:auth): access denied: tty 'pts/0' is not secure !
コンテナのファイルシステムにある /etc/securetty
のターミナル名のリストに pts/0
を追加してください。[2] を参照。コンテナの /etc/securetty
を削除することで常時 root ログインを許可することもできます。[3] を参照。
もしくは、lxc-attach に新しいユーザーを作成してシステムにログインするときに使うようにして、それから root に切り替えて下さい。
# lxc-attach -n playtime [root@playtime]# useradd -m -Gwheel newuser [root@playtime]# passwd newuser [root@playtime]# passwd root [root@playtime]# exit # lxc-console -n playtime [newuser@playtime]$ su
コンテナ設定の veth でネットワークに接続できない
/etc/lxc/containername/config
で設定した veth ネットワークインターフェイスで LAN や WAN に接続できないことがあります。仮想インターフェイスには IP が割り当てられてネットワークに接続できるようになっている場合:
ip addr show veth0 inet 192.168.1.111/24
固定 IP の設定を全て無効化して、起動したコンテナ OS の中から普通の方法で IP を設定してみてください。
container/config
の例:
...
lxc.net.0.type = veth
lxc.net.0.name = veth0
lxc.net.0.flags = up
lxc.net.0.link = bridge
...
コンテナの中から IP を割り当てる方法はネットワーク設定#IP アドレスの設定を参照。
Error: unknown command
ホスト環境とは異なる Linux ディストリビューションのコンテナ (例えば Arch Linux ホスト環境の Debian コンテナ) に接続して基本的なコマンド (ls, cat など) を入力する発生することがあるエラーです。接続時に --clear-env
引数を使ってください:
# lxc-attach -n container_name --clear-env
Error: Failed at step KEYRING spawning...
特権のないコンテナ内のサービスが失敗し、次のメッセージが表示される場合がある
some.service: Failed to change ownership of session keyring: Permission denied some.service: Failed to set up kernel keyring: Permission denied some.service: Failed at step KEYRING spawning ....: Permission denied
次の内容を含むファイル /etc/lxc/unpriv.seccomp
を作成します。
/etc/lxc/unpriv.seccomp
2 blacklist [all] keyctl errno 38
次に、次の行をコンテナ設定 lxc.idmap の後 に追加します。
lxc.seccomp.profile = /etc/lxc/unpriv.seccomp
既知の問題
lxc.init.static が欠落しているため lxc-execute が失敗する
lxc-execute
はエラーメッセージ lxc.init.static
を表示して失敗する場合。FS#63814 を参照してください。
lxc-start
を使用してコンテナを起動すると、正常に動作します。