系统喷泉容器的旋风巡演
在上一年的更新中,我谈到隔离我自办的LLMs
在 Ollama 中运行,并在 Open WebUI 中运行
并答应在博客上发表关于此事的文章。 然而,虽然
写博客文章
不小心变成了一个完整的博客文章。 这是真实的
(原始内容存档于2018-09-30). Point on systemd-nspawn.
基本上,systemd-nspawn是一个轻量级的Linux命名空间
容器技术,与Docker不异。 区别在于
主要是图像管理——而不是描述如何用
Docker 文件并分发预建的、只读的图像
正在运行的软件,系统d-nspawn通常使用可写字根
文件系统,功能更类似于虚拟机。 为了你们
记得使用chroot在不同的 Linux 运行软件
distro,也可以描述为类固醇上的chroot.
我认为在以下情况下,系统喷发特别有用:
- 当您想要运行一些软件,并在一定程度上与VPS隔离时,您无法创建完整的虚拟机,因为嵌入式虚拟化无法使用1;
- 当你需要共享硬件,例如GPU(这就是我运行的原因)
系统d-nspawn中的LLMs;
- 当你不希望虚拟化的间接费用时;
- 当您想要直接访问主机系统上的一些文件时,不需要
诉诸于virtiofs;
- 当你通常使用 Docker 时,详情请见脚注转文。
我将在这篇文章中
(a) 集装箱及其在某些常见情况下如何使用。
更新(2025-05-19):添加了更安全的阿尔卑斯山集装箱制造指令和一些关于设置阿尔卑斯Linux集装箱的更多指导。
从头开始
同所有容器一样,Systemd-nspawn需要一个单独的根f
目录。 因为没有图像管理器来为您构建图像
您需要使用传统的 Unix 方法来创建芯片。 没错
毕竟
在类固醇上。
对于系统喷发,典型的公约是将这些根置于
/var/lib/机器/[hostname],其中主机名是容器的。 对于
我将使用操作系统的名称作为主机名。
每个Linux distro都有自己创造新根的方法,我用Debian测试这些,但是你没有理由不能通过替换等效的软件包来做这些事情。 我可能会更深入地了解Debian
德比安家族的圈套
debootstrap在博客上多次出现
做一些疯狂的事情,比如从救援系统手动安装Debian.
对于基于Debian的Ditros,如Ubuntu或Debian本身,这是使用的工具
以创建根。
在基于Debian的OS上,用sudo apt安装debootstrap安装。 也许
或者你可以从Debian那里下载
仓库:
美元卷曲-L https://salsa.debian.org/installer-team/debootstrap/-/archive/master/debootstrap-master.tar.gz 焦油 xz 号
...
cd 脱钩主机/
./ 拆解陷阱
一:用法:[选择]. " 套装 " " 目标 " [ " 印象 " [ " 说明 " ]
...
不论您如何安装脱落陷阱,让我们在其中创建根
/var/lib/机器/设备:
sudo debootstrap - 包含=系统化、dbus、当地、bash-完成、curl书虫/var/lib/机器/debian
一:可以执行目标架构
一:获取释放
...
一:基地系统成功安装。
在这里,我们已经安装了书虫,但可以随意用这个代替
最新的Debian发行。 为了避免愚蠢的问题,我确保系统化
安装了dbus 和 locals 以避免奇怪的警告
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}这样我就不会讨厌我的生活 {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}用手打命令
卷起来,以后再下载其中一些需要一点
我们一旦进入容器
安装带有 dnf 的 RHEL 衍生工具
首先,如果您在另一个Destro上,例如Debian上安装 dnf 和 rpm:
$ sudo apt 安装 dnf rpm
...
设置dnf(4.14.0-3+deb12u1).
设置 rpm( 4.1.8. 0+dfsg-1+deb12u1)...
...
美元 sudo mkdir -p/var/lib/rpm
$ sudo rpm --initdb
然后,我们做了一个费多拉41chroot作为一个例子:
美元 sudo mkdir -p/var/lib/机器/fedora/etc/dnf
美元 sudo tee/var/lib/机器/fedora/etc/dnf/dnf.conf >/dev/null
[菲多拉]
名称=Fedora $leaver - $basech
metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch (中文(中国大陆) ).
gpgkey=https://getfedora.org/static/fedora.gpg 页面存档备份,存于互联网档案馆。
[更新]
名称=Fedora $relever - $basearch - 更新
metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-发布-f$releaserver&arch=$basearch (中文(中国大陆) ).
gpgkey=https://getfedora.org/static/fedora.gpg 页面存档备份,存于互联网档案馆。
$ sudo dnf -- releasever=41 -- best -- setopt=install weak deps=False --repo=fedora --repo=updates --installroot=/var/lib/机器/fedora 安装 dnf Fedora-release glibc glibc-langpack-en Produtect iputils 较少 ncurses passwd systemwd system-networkd system-solved util-linuxvim-default-editor
...
交易摘要
================================================================================
安装137套软件包
下载总数:62 M
安装大小:206 M
这样可以吗 [y/N]: y
...
完毕!
安装高山 Linux 与高山- nspawn- install
阿尔卑斯 Linux因其轻量级而常见于Docker图像中,因此I.
我想我还是试着创造一个高山Linux芯片常规工具
这种事情是高山青蛙公司但它的默认行为
对我们来说很可怕例如:
- 如果当前目录在/home内部,它将它绑在芯片中
基于“兼容性原因”的配置,无需任何警告。 我差点
运行 rm -rf 时不慎删除了整个主目录
鸡。..
- 它把/dev,/proc,和/sys也挂进芯片。 就/dev而言,任何随后试图将容器磨成一团以利用
UID 隔离也会将主机系统上的所有设备都磨掉
导致一场灾难,幸运的是,它可以通过重启来修复。
之后可以运行一个疯狂的乌山命令来清理之后
阿尔卑斯-chroot-install,例如:
在读 -r 路径时挂载 grep / var/ lib/ 机器/ 阿尔卑斯语 {} cut - d' - f3\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
然而,我认为这是一个滴答的定时炸弹,等待着有人的脸上爆炸。
于是,我伪造了剧本并创建了阿尔卑斯-nspawn -install。
我的版本删除了所有疯狂的“地貌” 高山-chroot-install
系统化- nspawn 不合理,例如正在安装的 chroot 帮助脚本
qemu 支持等 2,同时安装一个更正常的列表
默认的软件包。 你可以像这样使用:
$get https://raw.githubusercontent.com/quantum5/alpine-nspawn-install/refs/heads/master/alpine-nspawn-install 互联网档案馆的存檔,存档日期2013-03-02.
...
2025-05-19 22:23:27(47.6 MB/s) - " 阿尔卑斯-nspawn-install " 省下 [15897/15897]
Sudo bashing alpine-nspawn-install - d/var/lib/机器/高山
...
---
阿尔卑斯山集装箱安装完成。
现在让我们看看阿尔卑斯山是否保持其声誉:
sudo du -sh/var/lib/机器/德比安
338M/var/lib/机器/设备
Sudo du -sh/var/lib/机器/食品
507M/var/lib/机器/粮食
Sudo du -sh/var/lib/机器/阿尔卑斯山
16M/var/lib/机器/高山
这的确令人印象深刻,阿尔卑斯山是一个较小的面积级
比其他两个,而费朵拉相当膨胀的包列表I
已经安装。 我不是Fedora的用户并且复制了软件包列表
因此我不确定是否是。
因为我已经安装了气泡,这是
肯定比Dnf所说的要大所以我看了一眼
在 /var/cache/dnf 下创建了260个米B。
也是为了让Debian更愉快地体验,消除“bloat”的结果为305 MiB,这个数目略小。
初始启动装置为系统化- nspawn
首先,安装系统d-nspawn与sudo apt安装系统化容器或
您的双份数。
然后,您可以通过运行以下命令在容器中获取根壳:
$ sudo systemd-nspawn - D /var/lib/机器/[名]-M [名]- 私人用户=选 - 私人用户-所有=chown
每一个论点都这样做:
- D( -- directory) 指定根的目录;
-M(-机器)指定机器名称,它也被设定为
容器内的主机名;
- -- 私人用户=选取范围
65536 UID和GID来自主机系统上一个未使用的块,从a开始
524288和18789826563之间的65536倍数。 备选案文
选项包括 " 是 ",选择从拥有的 UID 开始的区域
和 rootfs 的 GID( 必须是 65536 的倍数);否,它禁用 UID
命名间隔;整数,用于启动65536块的UID;或
格式 a:b 的字符串,其中 是开始的 UID 和数量
指定容器的UID;最后
- -- -- 私人用户 -- -- 所有权= -- -- 改变根茎的所有权。
未来靴子上 -- -- 私人用户=是
继续使用相同的UID和GID。
以Debian为例:
$ sudo systemd-nspawn - D/var/lib/机器/debian-M-debian - 私人用户=ick-私人用户-所有=chown
在/var/lib/机器/debian上注入容器。
按 ^] 1 以内3次杀死容器。
选定用户命名空间基础 17663262272 及范围 65536.
root@debian:~#
我们在新创建的Debian集装箱里。 注意,这只是一个
当然,没有
输入进程甚至。
Debian 特定设置提示
如果您要使用 root shell 大量的时间,想要自动完成以避免输入整个命令:
root@debian:~# cp /etc/skel/.bashrc .
root@debian:~# . ~/.bashrc
如果你只是使用容器运行一个应用程序,它可以得到
非常乏味地管理你自己的用户然后Sudo,所以我选择做
管理作为根,并有功能的.bashrc 工作令人惊奇。 这是
技术上不是最好的做法,但我基本上从来没有运行命令单
不需要根的应用程序容器,所以没有真实性
差别。
debootstrap还将主机主机名复制到/etc/hostname. 让我们决定
说明:
root@debian: ~# 主机名 >/etc/hostname
回到集装箱里
如果您出于某种原因离开了根壳,您可以回去做:
Sudo系统d-nspawn - D/var/lib/机器/debian-M-私人用户=是
在/var/lib/机器/debian上注入容器。
按 ^] 1 以内3次杀死容器。
选定用户命名空间基础 17663262272 及范围 65536.
root@debian:~#
准备容器
这样运行容器不是长期的解决办法。 你可能想设置它在背景中正常运行。 然而,这就留下了如何进入集装箱的问题。 如果您使用基于系统的Dentro,您有一些选项:
- 如果你想从主机进入容器,你不需要
当您看到如何直接使用外壳时
马特克特尔您也可:
- 设置一个带有 passwd 的根密码,这样您可以从终端登录:root@ debian: QQ passwd
新密码:
重新输入新密码:
passwd:密码成功更新
- 安装 Opensh- server 并设置 SSH 密钥以远程连接( 您也会使用)
需要建立网络联系
连接:root@debian:\\\ pt 安装 opensh- server
...
创建了符号链接/etc/systemd/sshd.service/lib/systemd/system/ssh.service.
创建了符号链接/etc/systemd/system/multi-user.goal.wants/sh.service/lib/systemd/system/ssh.service.
处理触发器
本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。
A whirlwind tour of systemd-nspawn containers
In the last yearly update, I talked about isolating my self-hosted LLMs
running in Ollama as well as Open WebUI in
systemd-nspawn containers and promised a blog post about it. However, while
writing that blog post, a footnote on why I am using it instead of Docker
accidentally turned into a full blog post on its own. Here’s the actual
post on systemd-nspawn.
Fundamentally, systemd-nspawn is a lightweight Linux namespaces-based
container technology, not dissimilar to Docker. The difference is
mostly in image management—instead of describing how to build images with
Dockerfiles and distributing prebuilt, read-only images containing
ready-to-run software, systemd-nspawn is typically used with a writable root
filesystem, functioning more similarly to a virtual machine. For those of you
who remember using chroot to run software on a different Linux
distro, it can also be described as chroot on steroids.
I find systemd-nspawn especially useful in the following scenarios:
- When you want to run some software with some degree of isolation on a VPS, where you can’t create a full virtual machine due to nested virtualization not being available1;
- When you need to share access to hardware, such as a GPU (which is why I run
LLMs in systemd-nspawn);
- When you don’t want the overhead of virtualization;
- When you want to directly access some files on the host system without
resorting to virtiofs; and
- When you would normally use Docker but can’t or don’t want to. For reasons, please see the footnote-turned-blog post.
In this post, I’ll describe the process of setting up systemd-nspawn
containers and how to use them in some common scenarios.
Update (2025-05-19): added safer Alpine container creation instructions and some more guidance on setting up Alpine Linux containers.
Start with a chroot
systemd-nspawn, like all containers, requires a separate rootfs in a
directory. Since it doesn’t come with an image manager to build images for you,
you’ll need to use the traditional Unix approach of creating a chroot. It is,
after all,
chroot on steroids.
For systemd-nspawn, the typical convention is to put these rootfses under
/var/lib/machines/[hostname], where the hostname is that of the container. For
this exercise, I’ll just use the name of the OS as the hostname.
Each Linux distro has its own way of creating a new rootfs, so we’ll go through some of the more common ones. I am testing all this on Debian, but there’s no reason why you wouldn’t be able to do any of this on another distro by substituting the equivalent packages. Still, I’ll probably go deeper into Debian because I am more familiar with it.
debootstrap on the Debian family
debootstrap has featured on this blog many times, mostly when
doing crazy things like installing Debian by hand from rescue systems.
For Debian-based distros like Ubuntu or Debian itself, this is the tool to use
to create a rootfs.
On a Debian-based OS, install it with sudo apt install debootstrap. It may
also be packaged on other distros, or you can just download it from Debian’s
repositories:
$ curl -L https://salsa.debian.org/installer-team/debootstrap/-/archive/master/debootstrap-master.tar.gz | tar xz
...
$ cd debootstrap-master/
$ ./debootstrap
I: usage: [OPTION]... <suite> <target> [<mirror> [<script>]]
...
Either way you installed debootstrap, let’s create the rootfs in
/var/lib/machines/debian:
$ sudo debootstrap --include=systemd,dbus,locales,bash-completion,curl bookworm /var/lib/machines/debian
I: Target architecture can be executed
I: Retrieving InRelease
...
I: Base system installed successfully.
Here, we’ve installed bookworm, but feel free to substitute this for the
latest Debian release. To avoid silly issues, I ensured that systemd and
dbus are installed, along with locales to avoid weird warnings in apt,
bash-completion so I don’t hate my life when typing in commands by hand, and
curl so you can download stuff later. Some of these require a bit of
additional configuration later, which we’ll do once we boot into the container.
Installing RHEL-derivatives with dnf
First, install dnf and rpm if you are on another distro, e.g. on Debian:
$ sudo apt install dnf rpm
...
Setting up dnf (4.14.0-3+deb12u1) ...
Setting up rpm (4.18.0+dfsg-1+deb12u1) ...
...
$ sudo mkdir -p /var/lib/rpm
$ sudo rpm --initdb
Then, we make a Fedora 41 chroot as an example:
$ sudo mkdir -p /var/lib/machines/fedora/etc/dnf
$ sudo tee /var/lib/machines/fedora/etc/dnf/dnf.conf > /dev/null
[fedora]
name=Fedora $releasever - $basearch
metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch
gpgkey=https://getfedora.org/static/fedora.gpg
[updates]
name=Fedora $releasever - $basearch - Updates
metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-f$releasever&arch=$basearch
gpgkey=https://getfedora.org/static/fedora.gpg
$ sudo dnf --releasever=41 --best --setopt=install_weak_deps=False --repo=fedora --repo=updates --installroot=/var/lib/machines/fedora install dnf fedora-release glibc glibc-langpack-en iproute iputils less ncurses passwd systemd systemd-networkd systemd-resolved util-linux vim-default-editor
...
Transaction Summary
================================================================================
Install 137 Packages
Total download size: 62 M
Installed size: 206 M
Is this ok [y/N]: y
...
Complete!
Installing Alpine Linux with alpine-nspawn-install
Alpine Linux is commonly used in Docker images due to its lightweight size, so I
thought I might as well try creating an Alpine Linux chroot. The usual tool for
this sort of thing is alpine-chroot-install, but its default behaviour
is horrifying for our use case. For example:
- If the current directory is inside /home, it binds it into the chroot it
configures for “compatibility reasons,” without any warning. I almost
accidentally deleted my entire home directory when running rm -rf on
the chroot…
- It mounts /dev, /proc, and /sys into the chroot as well. In the case of /dev, any subsequent attempt to chown the container to take advantage of
UID isolation would chown all the devices on the host system as well,
leading to a disaster that fortunately could be fixed by rebooting.
It is possible to run a crazy umount command afterward to clean up after
alpine-chroot-install, such as:
mount | grep /var/lib/machines/alpine | cut -d' ' -f3 | sort -r | while read -r path; do sudo umount "$path"; done
However, I deem this a ticking time-bomb waiting to explode in someone’s face,
so instead, I forked the script and created alpine-nspawn-install.
My version removes all the crazy “features” of alpine-chroot-install that
don’t make sense for systemd-nspawn, e.g. the mounting, chroot helper scripts,
qemu support, etc.2, while installing a more sane list of
packages by default. You can use it like this:
$ wget https://raw.githubusercontent.com/quantum5/alpine-nspawn-install/refs/heads/master/alpine-nspawn-install
...
2025-05-19 22:23:27 (47.6 MB/s) - ‘alpine-nspawn-install’ saved [15897/15897]
$ sudo bash alpine-nspawn-install -d /var/lib/machines/alpine
...
---
Alpine container installation is complete.
Now let’s see if Alpine lives up to its reputation:
$ sudo du -sh /var/lib/machines/debian
338M /var/lib/machines/debian
$ sudo du -sh /var/lib/machines/fedora
507M /var/lib/machines/fedora
$ sudo du -sh /var/lib/machines/alpine
16M /var/lib/machines/alpine
Well, that’s certainly impressive… Alpine is an order of magnitude smaller
than the other two, while Fedora is quite bloated with the list of packages I
have installed. I am not a Fedora user and copied the package list from
the Arch Linux wiki guide on systemd-nspawn, so I am not sure if it’s
because I’ve installed bloat, but they all seem pretty necessary… It’s
certainly bigger than what dnf claimed to be, so I took a look, and dnf
created 260 MiB of stuff under /var/cache/dnf.
Also to be fair to Debian, I did install a bunch of “bloat” like locales for a more pleasant experience. Removing the “bloat” results in 305 MiB, which is slightly smaller.
Initial boot with systemd-nspawn
First, install systemd-nspawn with sudo apt install systemd-container or
your distro’s equivalent.
Then, you can get a root shell in a container by running the following command:
$ sudo systemd-nspawn -D /var/lib/machines/[name] -M [name] --private-users=pick --private-users-ownership=chown
And here is what each argument does:
- -D (--directory) specifies the directory of the rootfs;
- -M (--machine) specifies the machine name, which is also set as the
hostname inside the container;
- --private-users=pick enables UID and GID namespaces by picking a range of
65536 UIDs and GIDs from an unused block on the host system starting from a
multiple of 65536 in the range of 524288 and 18789826563. Alternative
options include yes, which selects the range starting from the owning UID
and GID of the rootfs (must be a multiple of 65536); no, which disables UID
namespacing; an integer, which serves as starting UID for a block of 65536; or
a string of the format a:b, where a is the starting UID and the number of
UIDs to assign to the container; and finally
- --private-users-ownership=chown changes the ownership of the rootfs to that
of the UID and GID chosen so that on future boots, --private-users=yes will
keep using the same UIDs and GIDs.
Let’s boot Debian as an example:
$ sudo systemd-nspawn -D /var/lib/machines/debian -M debian --private-users=pick --private-users-ownership=chown
Spawning container debian on /var/lib/machines/debian.
Press ^] three times within 1s to kill container.
Selected user namespace base 1766326272 and range 65536.
root@debian:~#
And we are in the newly created Debian container. Note that this is just a
root shell and isn’t a proper way to deploy the container long term. There is no
init process even.
Debian-specific setup tips
If you are going to be using a root shell for a significant amount of time and want autocomplete to avoid typing entire commands:
root@debian:~# cp /etc/skel/.bashrc .
root@debian:~# . ~/.bashrc
If you are just using the container to run a single application, it can get
really tedious to manage your own users and then sudo, so I just opt to do the
management as root and having a functioning .bashrc works wonders. This is
technically not best practice, but I basically never run commands in single
application containers that don’t require root anyway, so it makes no real
difference.
debootstrap also copied the host’s hostname into /etc/hostname. Let’s fix
that:
root@debian:~# hostname > /etc/hostname
Getting back into the container
If you exited the root shell for some reason, you can go back by doing:
$ sudo systemd-nspawn -D /var/lib/machines/debian -M debian --private-users=yes
Spawning container debian on /var/lib/machines/debian.
Press ^] three times within 1s to kill container.
Selected user namespace base 1766326272 and range 65536.
root@debian:~#
Preparing the container
Running the container like this isn’t a long-term solution. You probably want to set it up to run properly in the background. However, this leaves the question of how to access the container. If you are using a systemd-based distro, you have a few options:
- If you just want to access the container from the host machine, you don’t need
to do anything, as you’ll see how to get direct shell access with
machinectl. You can also:
- Set a root password with passwd so you can log in from a terminal: root@debian:~# passwd
New password:
Retype new password:
passwd: password updated successfully
- Install openssh-server and set up SSH keys to connect remotely (you’ll also
need to set up networking, as explained later, or you won’t be able to
connect): root@debian:~# apt install openssh-server
...
Created symlink /etc/systemd/system/sshd.service → /lib/systemd/system/ssh.service.
Created symlink /etc/systemd/system/multi-user.target.wants/ssh.service → /lib/systemd/system/ssh.service.
Processing triggers
Auto-fetched and translated by AI Atlas. All rights belong to the original author.