当前位置: 首页>>技术教程>>正文


如何在Ubuntu云VM映像上禁用`apt-daily.service`?

, ,

问题描述

Ubuntu 16.04服务器VM映像显然每12小时左右启动”apt-daily.service”;此服务执行各种APT-related任务,例如刷新可用软件包的列表,在需要时执行无人值守的升级等。

从VM “snapshot”启动时,该服务会立即触发,因为(我想)systemd很快意识到计时器应该早就关闭了。

但是,正在运行的APT会阻止其他apt进程运行,因为它会锁定/var/lib/dpkg。指示此错误消息如下所示:

E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?

在Ansible完成机器设置(通常涉及安装软件包)之前,我需要禁用此自动APT任务。有关更多信息和上下文,请参见https://github.com/gc3-uzh-ch/elasticluster/issues/304

我已经尝试过各种选项,以通过针对cloud-init的”user data”脚本禁用”unattended upgrades”功能,但是到目前为止,所有这些选项均已失败。

1.禁用系统任务

系统任务apt-daily.serviceapt-daily.timer触发。我试图通过以下命令的各种组合来禁用一个或另一个,或者两者都禁用。仍然,在VM准备好接受SSH连接之后,立即启动apt-daily.service

    #!/bin/bash

    systemctl stop apt-daily.timer
    systemctl disable apt-daily.timer
    systemctl mask apt-daily.service
    systemctl daemon-reload

2.禁用配置选项APT::Periodic::Enable

脚本/usr/lib/apt/apt.systemd.daily读取一些APT配置变量。设置APT::Periodic::Enable会完全禁用该功能(第331–337行)。我尝试使用以下脚本禁用它:

    #!/bin/bash

    # cannot use /etc/apt/apt.conf.d/10periodic as suggested in
    # /usr/lib/apt/apt.systemd.daily, as Ubuntu distributes the
    # unattended upgrades stuff with priority 20 and 50 ...
    # so override everything with a 99xxx file
    cat > /etc/apt/apt.conf.d/99elasticluster <<__EOF
    APT::Periodic::Enable "0";
    // undo what's in 20auto-upgrade
    APT::Periodic::Update-Package-Lists "0";
    APT::Periodic::Unattended-Upgrade "0";
    __EOF

但是,尽管APT::Periodic::Enable在命令行中具有值0(请参见下文),但unattended-upgrades程序仍在运行…

    ubuntu@test:~$ apt-config shell AutoAptEnable APT::Periodic::Enable
    AutoAptEnable='0'

3.完全删除/usr/lib/apt/apt.systemd.daily

以下cloud-init脚本完全删除了无人参与的升级脚本::

    #!/bin/bash

    mv /usr/lib/apt/apt.systemd.daily /usr/lib/apt/apt.systemd.daily.DISABLED

任务仍然运行,我可以在进程表中看到它!尽管如果从命令行进行探测,则文件不存在:

ubuntu@test:~$ ls /usr/lib/apt/apt.systemd.daily
ls: cannot access '/usr/lib/apt/apt.systemd.daily': No such file or directory

似乎cloud-init脚本(与SSH 命令行一起)和根systemd进程在单独的文件系统和进程空间中执行…

Questions

有什么明显的我想念的东西吗?还是发生了一些我不知道的名称空间魔术?

最重要的是:如何通过cloud-init脚本禁用apt-daily.service

最佳方法

是的,我显然缺少了一些东西。

Systemd与服务的并发启动有关,因此,在触发apt-daily.service的同时运行cloud-init脚本。到cloud-init执行user-specified有效负载时,apt-get update已经在运行。因此,尝试2和尝试3失败的原因不是因为某些命名空间魔术,而是因为它们更改系统的时间太晚了,以至于apt.systemd.daily不能接受更改。

这也意味着,基本上没有办法阻止apt.systemd.daily运行-只有在启动后才能杀死它。

此”user data”脚本采用以下路线::

#!/bin/bash

systemctl stop apt-daily.service
systemctl kill --kill-who=all apt-daily.service

# wait until `apt-get updated` has been killed
while ! (systemctl list-units --all apt-daily.service | egrep -q '(dead|failed)')
do
  sleep 1;
done

# now proceed with own APT tasks
apt install -y python

还有一个时间窗,在此期间可以进行SSH登录,但apt-get无法运行,但是我无法想象可以在现有Ubuntu 16.04云映像上使用的其他解决方案。

次佳方法

注意:不幸的是,以下解决方案的一部分不适用于Ubuntu 16.04系统(例如发问者),因为建议的systemd-run调用仅适用于Ubuntu 18.04及更高版本(请参阅comments for details)。我将答案留在这里,因为无论您使用的是哪个Ubuntu版本,该问题仍然很受欢迎。

在Ubuntu 18.04(及更高版本)上,启动时间可能需要两项服务才能更新/升级。第一个apt-daily.service刷新软件包列表。但是,可能还有第二个apt-daily-upgrade.service实际上安装了安全关键软件包。一个answer to the “Terminate and disable/remove unattended upgrade before command returns”问题提供了一个很好的示例,说明如何等待它们都完成(为方便起见,在此处复制):

systemd-run --property="After=apt-daily.service apt-daily-upgrade.service" --wait /bin/true

(请注意,此操作必须以root用户身份运行)。如果要在以后的启动中禁用这些服务,则需要屏蔽以下两个服务:

systemctl mask apt-daily.service apt-daily-upgrade.service

另外,您也可以systemctl disable服务及其关联的计时器(即apt-daily.timerapt-daily-upgrade.timer)。

请注意,此答案中的屏蔽/禁用技术仅阻止将来启动时的更新/升级-如果它们已在当前启动中运行,则它们不会停止。

第三种方法

您可以通过”bootcmd” cloud-init模块禁用此功能。它在网络启动之前运行,这是在apt更新获得运行机会之前所必需的。

#cloud-config
bootcmd:
    - echo 'APT::Periodic::Enable "0";' > /etc/apt/apt.conf.d/10cloudinit-disable
    - apt-get -y purge update-notifier-common ubuntu-release-upgrader-core landscape-common unattended-upgrades
    - echo "Removed APT and Ubuntu 18.04 garbage early" | systemd-cat

一旦ssh进入实例,您还应该等待cloud-init的最后阶段完成,因为它会移动适当的源代码/列表。

# Wait for cloud-init to finish moving apt sources.list around... 
# a good source of random failures
# Note this is NOT a replacement for also disabling apt updates via bootcmd
while [ ! -f /var/lib/cloud/instance/boot-finished ]; do
    echo 'Waiting for cloud-init to finish...'
    sleep 3
done

这对于查看bootcmd多早运行也很有帮助:

# Show microseconds in systemd journal
journalctl -r -o short-precise

您可以按以下步骤验证此工作:

apt-config dump | grep Periodic

# Verify nothing was updated until we run apt update ourselves.
cd /var/lib/apt/lists
sudo du -sh .   # small size
ls -ltr         # old timestamps

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/8417.html,未经允许,请勿转载。