25p*_*pwn 4 systemd systemd-nspawn
我有一个包含以下内容的脚本:
sudo machinectl start "$machinename"
sudo systemd-run -PM root@"$machinename" "$command"
Run Code Online (Sandbox Code Playgroud)
Failed to connect to bus: No such file or directory
Failed to start transient service unit: Transport endpoint is not connected
Run Code Online (Sandbox Code Playgroud)
这会失败,因为第一行仅开始启动容器;第二行在容器完成启动之前运行。目前,我有一个解决方案,可以不断轮询容器的状态并阻止直到它准备好:
while [ "$(sudo systemctl show "systemd-nspawn@$machinename" -P StatusText)" != "Container running: Ready." ]
do
true
done
Run Code Online (Sandbox Code Playgroud)
如何等待容器完成启动,而不需要不断轮询容器的状态?
取决于你想做什么。我将直接回答您的问题,然后回答一些替代方案。我假设您使用 systemd 作为容器中的 init 系统,如果您的容器操作系统基于 Debian / Arch / Ubuntu 或类似操作系统,则情况确实如此。
启动 nspawn 容器后执行命令
在.nspawn文件( /etc/systemd/nspawn/yourcontainer.nspawn)中添加:
[Exec]
NotifyReady=yes
Run Code Online (Sandbox Code Playgroud)
然后sudo machinectl start yourcontainer将等待容器完成启动后再退出。脚本的第二行现在可以工作,因为容器已准备就绪(除非您的容器无法启动,这将使您的轮询陷入无限循环)。
在底层,主机正在容器中systemd-nspawn设置一个 Unix 域套接字。/run/host/notify当容器的 systemd 准备就绪时(换句话说,当它到达multi-user.target目标时),它会READY=1向该套接字发送通知。主机的systemd-nspawn服务等待接收该消息。
这种方法的缺点是你不能再异步启动容器(除非使用&符号),如果你正在调试并且启动时间很长,这会很烦人。
其他一些方法(按复杂程度排列):
在 chroot 中运行命令
假设容器没有运行,
sudo chroot /var/lib/machines/yourcontainer /bin/bash -c "$command"
Run Code Online (Sandbox Code Playgroud)
如果您刚刚创建了一个容器并以编程方式初始化它多次,那么这非常有用。显然它没有从沙箱功能中受益。如果您之前使用 运行过相同的容器,它也将不起作用PrivateUsers=yes,因为这些文件将chown使用高 UID 进行编辑。如果容器已经在运行,它可能会给出未定义的结果。
直接使用systemd-nspawn
这种方法不需要上面的解释NotifyReady=yes|no。
systemd-nspawn -M yourcontainer -P /bin/bash -c "$command"
Run Code Online (Sandbox Code Playgroud)
这将在打开所有沙箱的情况下在容器内运行命令,但该命令将作为唯一的进程运行(并且PID=1) - 您的 init 服务将不会运行。例如,网络将不可用(除非您无论如何都使用主机网络)。
如果容器已经在运行,则此命令将不起作用。
套接字激活
如果您正在等待容器中的服务器准备就绪,则只需使用套接字激活(假设您的服务器兼容)。这在其他地方有更好的解释,总之 systemd 将等待与您的套接字的连接(例如 TCP 端口 80)。当客户端连接时,systemd 将启动您的容器,然后将流量转发给它。在古代inetd做同样的事情。
这需要像文件Service=systemd-nspawn@yourcontainer.service中那样的一行.socket。
| 归档时间: |
|
| 查看次数: |
1044 次 |
| 最近记录: |