kWatanabe 記事一覧へ

kWatanabe の 技術帖

某企業でOSや仮想化の研究をやっているインフラ系エンジニア。オンプレとクラウドのコラボレーションなど、興味ある技術を綴る。

KVMホストをLXCコンテナの中に構築する

  • LXCコンテナの中に、KVM仮想マシンを動かせる環境を作り、ついでにProxmox VEも入れる
  • 検証は Nested KVM で試したので、実際は KVM on LXC on KVM だったりする

背景

我が家には、常時稼働の本番用のサーバと、必要な時に電源を入れる開発用のサーバがある。前者は Debian11 + LXC で、後者は Proxmox VE (KVM+LXC) で運用している。

ちょっとした検証等は常時稼働のサーバでやりたい*1が、本番環境に怪しいコンテナを作るのも嫌なので、KVMサンドボックス化したい。一方、本番環境では KVM を使っておらず、不必要なものでホストOSを汚したくない。

そこで、KVM を使える コンテナを構築して、その中に Proxmox VE を導入しようと考えた。

検証環境

なお、本番サーバへの適用前に、開発用サーバ上の VM で検証したので、実際には以下のような構成となった。

やりたいこと(左)と、実際に検証した構成(右)

KVM ホスト化

方針

大まかな方針としては、KVMの動作に必要なデバイスファイルを、LXC コンテナの中から扱えるようにする。以前、LXC コンテナ内で GPGPU するために採った策と基本的には同じ。

kwatanabe.hatenablog.jp

kwatanabe.hatenablog.jp

コンテナの作成と健全性確認

Proxmox VE 化は後からするとして、まずは普通の Debian 11 コンテナを作り。

$ sudo lxc-create -n kvm-in-container -t download -- -d debian -r bullseye -a amd64

起動する。

$ sudo lxc-start -n kvm-in-container

KVMやLXCをホストできるか検証してくれる virt-host-validate コマンドを導入する。

$ sudo lxc-attach -n kvm-in-container -- apt install libvirt-clients

何も対策していない素の状態だと以下の通り。

$ sudo lxc-attach -n kvm-in-container -- virt-host-validate 
setlocale: No such file or directory
  QEMU: Checking for hardware virtualization                                 : PASS
  QEMU: Checking if device /dev/kvm exists                                   : FAIL (Check that the 'kvm-intel' or 'kvm-amd' modules are loaded & the BIOS has enabled virtualization)
  QEMU: Checking if device /dev/vhost-net exists                             : WARN (Load the 'vhost_net' module to improve performance of virtio networking)
  QEMU: Checking if device /dev/net/tun exists                               : FAIL (Load the 'tun' module to enable networking for QEMU guests)
  QEMU: Checking for cgroup 'cpu' controller support                         : PASS
  QEMU: Checking for cgroup 'cpuacct' controller support                     : PASS
  QEMU: Checking for cgroup 'cpuset' controller support                      : PASS
  QEMU: Checking for cgroup 'memory' controller support                      : PASS
  QEMU: Checking for cgroup 'devices' controller support                     : PASS
  QEMU: Checking for cgroup 'blkio' controller support                       : PASS
  QEMU: Checking for device assignment IOMMU support                         : WARN (No ACPI IVRS table found, IOMMU either disabled in BIOS or not supported by this hardware platform)
  QEMU: Checking for secure guest support                                    : WARN (Unknown if this platform has Secure Guest support)
   LXC: Checking for Linux >= 2.6.26                                         : PASS
   LXC: Checking for namespace ipc                                           : PASS
   LXC: Checking for namespace mnt                                           : PASS
   LXC: Checking for namespace pid                                           : PASS
   LXC: Checking for namespace uts                                           : PASS
   LXC: Checking for namespace net                                           : PASS
   LXC: Checking for namespace user                                          : PASS
   LXC: Checking for cgroup 'cpu' controller support                         : PASS
   LXC: Checking for cgroup 'cpuacct' controller support                     : PASS
   LXC: Checking for cgroup 'cpuset' controller support                      : PASS
   LXC: Checking for cgroup 'memory' controller support                      : PASS
   LXC: Checking for cgroup 'devices' controller support                     : PASS
   LXC: Checking for cgroup 'freezer' controller support                     : FAIL (Enable 'freezer' in kernel Kconfig file or mount/enable cgroup controller in your system)
   LXC: Checking for cgroup 'blkio' controller support                       : PASS
   LXC: Checking if device /sys/fs/fuse/connections exists                   : PASS

対策すべきは以下の項目。

  • /dev/kvm が無い
  • /dev/vhost-net が無い
  • /dev/net/tun が無い

あと、/dev/fuse が無くて Proxmox VE 化する際に失敗するため、合わせて対応する。単なる KVM ホストとしての動作には必須では無いので、その場合はスルーでよい。

それぞれ、ホストでデバイス番号を調べておく。

$ ls -l /dev/kvm /dev/vhost-net /dev/net/tun /dev/fuse
crw-rw---- 1 root kvm  10, 232 10月 30 10:05 /dev/kvm
crw-rw-rw- 1 root root 10, 200 10月 30 10:05 /dev/net/tun
crw------- 1 root root 10, 238 10月 30 10:05 /dev/vhost-net
crw------- 1 root root 10, 229 10月 30 10:05 /dev/fuse

コンテナ定義ファイルの修正

一旦コンテナを終了させる。

$ sudo lxc-stop -n kvm-in-container

次に、コンテナの定義ファイル /var/lib/lxc/<コンテナ名>/config を編集する。

$ sudo vim /var/lib/lxc/kvm-in-container/config

LXCをネストさせるための設定。

lxc.include = /usr/share/lxc/config/common.conf
lxc.include = /usr/share/lxc/config/nesting.conf
lxc.apparmor.profile = unconfined
lxc.apparmor.allow_nesting = 1

必要なデバイスファイルへのアクセス権を与える設定。

lxc.cgroup.devices.allow = c 10:232 rwm
lxc.cgroup.devices.allow = c 10:200 rwm
lxc.cgroup.devices.allow = c 10:238 rwm
lxc.cgroup.devices.allow = c 10:229 rwm
lxc.cgroup2.devices.allow = c 10:232 rwm
lxc.cgroup2.devices.allow = c 10:200 rwm
lxc.cgroup2.devices.allow = c 10:238 rwm
lxc.cgroup2.devices.allow = c 10:229 rwm

ホストのデバイスファイルを bind mount する設定。なお、bind mount せずに、コンテナの中で mknod コマンドでデバイスファイルを作成するのでもよい。

lxc.mount.entry = /dev/kvm dev/kvm none bind,optional,create=file
lxc.mount.entry = /dev/net/tun dev/net/tun none bind,optional,create=file
lxc.mount.entry = /dev/vhost-net dev/vhost-net none bind,optional,create=file
lxc.mount.entry = /dev/fuse dev/fuse none bind,optional,create=file

コンテナの再起動と健全性再確認

コンテナを再起動する。

$ sudo lxc-start -n kvm-in-container

改めて virt-host-validate コマンドで確認する。

$ sudo lxc-attach -n kvm-in-container -- virt-host-validate 
setlocale: No such file or directory
  QEMU: Checking for hardware virtualization                                 : PASS
  QEMU: Checking if device /dev/kvm exists                                   : PASS
  QEMU: Checking if device /dev/kvm is accessible                            : PASS
  QEMU: Checking if device /dev/vhost-net exists                             : PASS
  QEMU: Checking if device /dev/net/tun exists                               : PASS
  QEMU: Checking for cgroup 'cpu' controller support                         : PASS
  QEMU: Checking for cgroup 'cpuacct' controller support                     : PASS
  QEMU: Checking for cgroup 'cpuset' controller support                      : PASS
  QEMU: Checking for cgroup 'memory' controller support                      : PASS
  QEMU: Checking for cgroup 'devices' controller support                     : PASS
  QEMU: Checking for cgroup 'blkio' controller support                       : PASS
  QEMU: Checking for device assignment IOMMU support                         : WARN (No ACPI IVRS table found, IOMMU either disabled in BIOS or not supported by this hardware platform)
  QEMU: Checking for secure guest support                                    : WARN (Unknown if this platform has Secure Guest support)
   LXC: Checking for Linux >= 2.6.26                                         : PASS
   LXC: Checking for namespace ipc                                           : PASS
   LXC: Checking for namespace mnt                                           : PASS
   LXC: Checking for namespace pid                                           : PASS
   LXC: Checking for namespace uts                                           : PASS
   LXC: Checking for namespace net                                           : PASS
   LXC: Checking for namespace user                                          : PASS
   LXC: Checking for cgroup 'cpu' controller support                         : PASS
   LXC: Checking for cgroup 'cpuacct' controller support                     : PASS
   LXC: Checking for cgroup 'cpuset' controller support                      : PASS
   LXC: Checking for cgroup 'memory' controller support                      : PASS
   LXC: Checking for cgroup 'devices' controller support                     : PASS
   LXC: Checking for cgroup 'freezer' controller support                     : FAIL (Enable 'freezer' in kernel Kconfig file or mount/enable cgroup controller in your system)
   LXC: Checking for cgroup 'blkio' controller support                       : PASS
   LXC: Checking if device /sys/fs/fuse/connections exists                   : PASS

問題なし。ここまできたら、後は qemu-kvmvirt-manager などを導入し、通常の KVM ホストと同じように扱える。

Proxmox VE 化(おまけ)

Debian 11 を Proxmox VE 化する際は以下のWebページが参考になる。

pve.proxmox.com

ただ、今回はコンテナなので、専用カーネルでの差し替えはできない。詳細は割愛するが、大まかな流れは以下となる。

$ sudo lxc-start -n kvm-in-container

$ sudo lxc-attach -n kvm-in-container -- systemctl disable systemd-networkd systemd-resolved

$ sudo lxc-stop -r -n kvm-in-container

$ sudo lxc-attach -n kvm-in-container -- rm /etc/resolv.conf

$ sudo lxc-attach -n kvm-in-container -- vim /etc/resolv.conf
nameserver <DNSサーバのIPアドレス>
search <検索ドメイン名>

$ sudo lxc-attach -n kvm-in-container -- vim /etc/hosts
<コンテナのIPアドレス> kvm-in-container

$ sudo lxc-attach -n kvm-in-container -- dpkg-reconfigure locales
<任意のロケールを選択>

$ sudo lxc-attach -n kvm-in-container -- apt install wget

$ sudo lxc-attach -n kvm-in-container -- vim /etc/apt/sources.list.d/pve-install-repo.list
deb [arch=amd64] http://download.proxmox.com/debian/pve bullseye pve-no-subscription

$ sudo lxc-attach -n kvm-in-container -- wget https://enterprise.proxmox.com/debian/proxmox-release-bullseye.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-bullseye.gpg 

$ sudo lxc-attach -n kvm-in-container -- apt update

$ sudo lxc-attach -n kvm-in-container -- apt full-upgrade

$ sudo lxc-attach -n kvm-in-container -- apt install proxmox-ve

結果

こんな感じに仕上がった。

まとめ

  • LXCコンテナにKVMホスト環境を構築し、Proxmox VE in LXC Container を実現した。
  • ホスト環境を汚さずに、サンドボックスを作れるので、結構使い道が多いかも知れない。

*1:目の前のマシンに Docker 入れればええやん、とか言わないで。禁止。