Jer*_*err 16 upstart init chroot
我有许多 LVM 分区,每个分区都包含一个 Ubuntu 安装。有时,我想做一个apt-get dist-upgrade
, 将安装更新到最新的软件包。我用 chroot 来做这件事——这个过程通常是这样的:
$ sudo mount /dev/local/chroot-0 /mnt/chroot-0
$ sudo chroot /mnt/chroot-0 sh -c 'apt-get update && apt-get dist-upgrade'
$ sudo umount /mnt/chroot-0
Run Code Online (Sandbox Code Playgroud)
[未显示:我还安装和卸载/mnt/chroot-0/{dev,sys,proc}
作为绑定安装到真实的/dev
,/sys
并且/proc
,因为 dist-upgrade 似乎期望这些存在]
但是,升级到精确后,此过程不再有效 - 最终卸载将失败,因为文件/mnt/chroot-0
系统上仍有打开的文件。lsof
确认 chroot 中有打开文件的进程。这些进程是在dist-upgrade 期间启动的,我假设这是因为chroot 中的某些服务需要service postgresql restart
在包升级后重新启动(例如,通过)。
所以,我想我需要告诉 upstart 停止在这个 chroot 中运行的所有服务。有没有办法可靠地做到这一点?
我试过了:
cat <<EOF | sudo chroot /mnt/chroot-0 /bin/sh
# stop 'initctl' services
initctl list | awk '/start\/running/ {print \$1}' | xargs -n1 -r initctl stop
EOF
Run Code Online (Sandbox Code Playgroud)
Whereinitctl list
似乎做正确的事情,并且只列出在这个特定根目录中启动的进程。我也试过添加这个,正如 Tuminoid 所建议的:
cat <<EOF | sudo chroot /mnt/chroot-0 /bin/sh
# stop 'service' services
service --status-all 2>/dev/null |
awk '/^ \[ \+ \]/ { print \$4}' |
while read s; do service \$s stop; done
EOF
Run Code Online (Sandbox Code Playgroud)
然而,这些似乎并没有抓住一切。已守护进程并重新父级为 PID 1 的进程不会停止。我也试过:
sudo chroot /mnt/chroot-0 telinit 0
Run Code Online (Sandbox Code Playgroud)
但是在这种情况下,init不区分单独的根并关闭整个机器。
那么,有没有办法告诉 init 停止特定 chroot 中的所有进程,以便我可以安全地卸载文件系统?新贵是否有任何设施可以在 chroot 中对所有子进程进行 SIGTERM/SIGKILL(就像在常规关闭期间所做的那样)?
inf*_*ity 16
除了内核之外,我不相信任何东西来保持这里的正常状态,所以我不(ab)使用 init 来完成这项工作,我也不指望自己真正知道什么是挂载或未挂载(某些软件包可以挂载额外的文件系统,如 binfmt_misc)。因此,对于过程屠宰,我使用:
PREFIX=/mnt/chroot-0
FOUND=0
for ROOT in /proc/*/root; do
LINK=$(readlink $ROOT)
if [ "x$LINK" != "x" ]; then
if [ "x${LINK:0:${#PREFIX}}" = "x$PREFIX" ]; then
# this process is in the chroot...
PID=$(basename $(dirname "$ROOT"))
kill -9 "$PID"
FOUND=1
fi
fi
done
if [ "x$FOUND" = "x1" ]; then
# repeat the above, the script I'm cargo-culting this from just re-execs itself
fi
Run Code Online (Sandbox Code Playgroud)
对于卸载 chroot,我使用:
PREFIX=/mnt/chroot-0
COUNT=0
while grep -q "$PREFIX" /proc/mounts; do
COUNT=$(($COUNT+1))
if [ $COUNT -ge 20 ]; then
echo "failed to umount $PREFIX"
if [ -x /usr/bin/lsof ]; then
/usr/bin/lsof "$PREFIX"
fi
exit 1
fi
grep "$PREFIX" /proc/mounts | \
cut -d\ -f2 | LANG=C sort -r | xargs -r -n 1 umount || sleep 1
done
Run Code Online (Sandbox Code Playgroud)
作为附录,我要指出,将这个作为 init 问题来处理可能是错误的看待它的方式,除非您实际上在 chroot 中有一个 init 和一个单独的进程空间(即:在 LXC 容器的情况下) . 使用单个 init(在 chroot 之外)和共享进程空间,这不再是“init 的问题”,而是由您来查找碰巧具有违规路径的进程,因此上面的 proc walk 。
从您最初的帖子中不清楚这些是您只是从外部升级的完全可启动系统(我是这么读的),或者它们是否是您用于诸如包构建之类的 chroot。如果是后者,您可能还需要一个 policy-rc.d(就像 mk-sbuild 引入的那个),它只是禁止从一开始就开始 init 作业。显然,如果这些也是可引导系统,那这不是一个明智的解决方案。
归档时间: |
|
查看次数: |
11732 次 |
最近记录: |