如何在不启动相关服务的情况下安装软件包?

如何在不启动相关服务的情况下安装软件包?

您可能知道,默认情况下,当您在基于 Debian 或 Ubuntu 的系统上安装软件包时,如果软件包包含服务,则该服务通常会在您安装该软件包时自动启用并启动。

这对我来说是一个问题。

我发现自己需要管理用于构建 LXC 容器的模板。有多个容器,每个容器都对应一个 Debian 或 Ubuntu 版本。(还有基于 Red Hat 的容器,但它们与此无关。)

/var/lib/libvirt/filesystems/debian6_template
/var/lib/libvirt/filesystems/debian7_template
/var/lib/libvirt/filesystems/ubuntu1004_template
/var/lib/libvirt/filesystems/ubuntu1204_template

有时我会发现模板缺少包或需要进行其他更改,因此我会 chroot 到这些模板中安装包。不幸的是,当我这样做时,我最终会运行该包服务的多个副本!

举例来说,我发现模板没有 syslog 守护程序,因此我安装了一个:

for template in /var/lib/libvirt/filesystems/{debian,ubuntu}*_template; do
    chroot $template apt-get install rsyslog
done

很快就有四个 rsyslog 副本在运行。更不用说两个 exim4 副本了。糟糕!


我在某处读到过(虽然我现在找不到了)它不应该在 chroot 中运行时启动服务,但这显然没有发生在这里。

一个可能可行的恶意黑客要求暂时替换实际启动服务的各种命令,例如start-stop-daemoninitctl,尽管这比我真正想做的要多得多。如果我别无选择,那么……

理想的解决方案是让基于 Debian 的系统停止执行这种垃圾操作,但如果做不到,也许是一个模糊或未记录的命令行选项apt-get

如果不清楚的话,我真的想保留与管理模板相关的任何内容外部如果可能的话,模板。

答案1

对于 Debian 你可以这样做策略-rc.d. 这是一种解释

软件包的维护者脚本应该仅通过invoke-rc.d、update-rc.d和LSB init脚本头与init系统交互...invoke-rc.d在采取行动之前会检查/usr/sbin/policy-rc.d是否可执行,并在其命令行上使用相应的服务名称和当前运行级别号调用它,并根据其退出代码采取行动。例如,返回值101将阻止执行计划的操作。这包括在安装软件包时自动启动服务以及在删除软件包时停止服务,并将软件包升级期间的停止-升级-重启仪式减少到仅执行升级,这可能会使旧版本的服务继续运行

因为你不希望任何服务启动,所以你的 policy-rc.d 脚本可以简单

#!/bin/sh
exit 101

这是 pbuilder 和 Docker 等工具所使用的技术mkimage/debootstrap

不幸的是,这种技术不适用于 Ubuntuchroots。与 upstart init 系统集成的软件包在安装期间调用 /usr/sbin/initctl 而不是invoke-rc.d,并且 initctl 不会查阅 policy-rc.d。根据新贵的作者解决方法是将 /sbin/initctl 替换为 chroot 中指向 /bin/true 的符号链接。您也可以在 mkimage-debootstrap 中看到这一点,它们确实

dpkg-divert --local --rename --add /sbin/initctl
ln -sf /bin/true sbin/initctl

答案2

你可以做:

export RUNLEVEL=1
for template in /var/lib/libvirt/filesystems/{debian,ubuntu}*_template; do
    chroot $template apt-get install rsyslog
done
exit

我还没有用 chroot 测试过,但它应该可以工作。首先,它设置了 RUNLEVEL 环境变量,因此由 apt-get 启动的进程不会启动任何服务,因为它们会“认为”系统在单一模式下运行。由于环境的修改方式可能会影响未来的命令,因此当不再需要修改的环境时,需要退出 shell,这是通过以下方式实现的:出口命令末尾。或许一些(罕见?)软件包无法在单一模式下正确安装(但据我所知,在大多数情况下这应该不是问题)。

答案3

现在 Debian(和 Ubuntu)使用 Systemd 作为其初始化系统,在安装之前禁用单元的一个干净的方法是使用Systemd 的预设功能。这个用例甚至在示例部分

示例 1. 默认关闭

# /lib/systemd/system-preset/99-default.preset
disable *

这将禁用所有单元。由于文件名前缀为“99-”,它将被最后读取,因此很容易被 spin 或管理员预设策略覆盖。

相关内容