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

Ric*_*rri 82 ubuntu systemd cloud-init

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?
Run Code Online (Sandbox Code Playgroud)

我需要禁用这个自动化的 APT 任务,直到 Ansible 完成机器设置(通常涉及安装包);有关更多信息和上下文,请参阅https://github.com/gc3-uzh-ch/elasticluster/issues/304

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

1.禁用systemd任务

systemd 任务apt-daily.serviceapt-daily.timer. 我尝试使用以下命令的各种组合来禁用一个或另一个,或同时禁用两者;仍然,在apt-daily.serviceVM 准备好接受 SSH 连接后不久就启动了:

    #!/bin/bash

    systemctl stop apt-daily.timer
    systemctl disable apt-daily.timer
    systemctl mask apt-daily.service
    systemctl daemon-reload
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

然而,尽管APT::Periodic::Enable0来自命令行的值(见下文),该unattended-upgrades程序仍在运行......

    ubuntu@test:~$ apt-config shell AutoAptEnable APT::Periodic::Enable
    AutoAptEnable='0'
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

ubuntu@test:~$ ls /usr/lib/apt/apt.systemd.daily
ls: cannot access '/usr/lib/apt/apt.systemd.daily': No such file or directory
Run Code Online (Sandbox Code Playgroud)

看起来cloud-init脚本(连同 SSH 命令行)和 root systemd 进程在单独的文件系统和进程空间中执行......

问题

有什么明显的我遗漏了吗?或者是否有一些我不知道的命名空间魔法?

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

Ric*_*rri 50

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

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
Run Code Online (Sandbox Code Playgroud)

仍然有一个时间窗口,在此期间 SSH 登录是可能的apt-get ,但不会运行,但我无法想象另一个可以在 Ubuntu 16.04 云映像上运行的解决方案。


Ano*_*non 20

注意:不幸的是,下面的部分解决方案不适用于 Ubuntu 16.04 系统(例如提问者的系统),因为建议的systemd-run调用仅适用于Ubuntu 18.04 及更高版本有关详细信息,请参阅评论)。我会在这里留下答案,因为无论您使用的是哪个 Ubuntu 版本,这个问题仍然很受欢迎……

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

systemd-run --property="After=apt-daily.service apt-daily-upgrade.service" --wait /bin/true
Run Code Online (Sandbox Code Playgroud)

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

systemctl mask apt-daily.service apt-daily-upgrade.service
Run Code Online (Sandbox Code Playgroud)

或者,您可以systemctl disable同时使用服务及其相关计时器(即apt-daily.timerapt-daily-upgrade.timer)。

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

  • 很好的答案,谢谢!虽然,请注意 Ubuntu 16.04 上的 `systemd-run` 太旧,无法支持 `--wait` 选项,但对于手头的目的来说,它真的不是必需的。(根据手册页,`--wait` 等待单元的*终止*,但它足以等待它的启动,这是 `systemd-run` 的默认行为。) (2认同)

Kar*_*ett 6

您可以通过“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
Run Code Online (Sandbox Code Playgroud)

一旦您通过 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
Run Code Online (Sandbox Code Playgroud)

这也有助于了解 bootcmd 运行的时间:

# Show microseconds in systemd journal
journalctl -r -o short-precise
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式验证这是否有效:

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
Run Code Online (Sandbox Code Playgroud)