如何在 Ubuntu 云虚拟机映像上禁用“apt-daily.service”?

如何在 Ubuntu 云虚拟机映像上禁用“apt-daily.service”?

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

从虚拟机“快照”启动时,会触发该服务立即地,因为(我推测)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?

我需要禁用这个自动 APT 任务,直到 Ansible 完成机器设置(通常涉及安装软件包);看https://github.com/gc3-uzh-ch/elasticluster/issues/304了解更多信息和背景。

我尝试了各种选项来通过“用户数据”脚本禁用“无人值守升级”功能cloud-init,但到目前为止所有选项都失败了。

1.禁用systemd任务

systemd 任务apt-daily.service由 触发apt-daily.timer。我尝试使用以下命令的各种组合来禁用其中之一或两者;尽管如此,它还是apt-daily.service在虚拟机准备好接受 SSH 连接后立即启动:

    #!/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获得了值(见下文),该程序仍然运行......0unattended-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 命令行一起)和 root systemd 进程在单独的文件系统和进程空间中执行......

问题

我是否缺少一些明显的东西?或者是否有一些我不知道的命名空间魔法正在发生?

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

答案1

是的,我明显遗漏了一些东西。

Systemd 是关于服务的并发启动,因此cloud-init运行脚本同时apt-daily.service触发。当 cloud-init执行用户指定的有效负载时,apt-get update它已经在运行。因此,尝试 2. 和 3. 失败并不是因为某些名称空间魔法,而是因为它们对系统的更改太晚了,无法apt.systemd.daily接受更改。

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

这个“用户数据”脚本采用以下路线::

#!/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 云映像上运行的解决方案。

答案2

注意:不幸的是下面的解决方案的一部分不适用于 Ubuntu 16.04 系统(例如提问者的)因为建议的systemd-run调用仅适用于Ubuntu 18.04 及以上版本(参见评论了解详情)。我将把答案留在这里,因为无论你使用哪个 Ubuntu 版本,这个问题仍然很受欢迎......

在 Ubuntu 18.04(及更高版本)上,启动时 apt 更新/升级可能涉及最多两个服务。第一个apt-daily.service刷新包列表。然而,可能有第二个apt-daily-upgrade.service实际安装安全关键软件包。一个回答“命令返回之前终止并禁用/删除无人值守升级”问题给出了一个很好的例子,说明如何等待这两个任务完成(为了方便起见,在此处复制):

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)。

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

答案3

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

#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 的最后阶段完成,因为它会移动 apt 源/列表。

# 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

答案4

掩盖这个单位不是更容易吗

systemctl mask apt-daily.service

相关内容