Ansible剧本无法锁定apt

12

我接手了一个使用 Ansible 进行服务器配置和管理的项目。虽然我对 Ansible 还比较陌生,但多亏了好的文档,我正在逐渐了解它。 但是我遇到了一个错误,输出如下:

failed: [build] (item=[u'software-properties-common', u'python-pycurl', u'openssh-server', u'ufw', u'unattended-upgrades', u'vim', u'curl', u'git', u'ntp']) => {"failed": true, "item": ["software-properties-common", "python-pycurl", "openssh-server", "ufw", "unattended-upgrades", "vim", "curl", "git", "ntp"], "msg": "Failed to lock apt for exclusive operation"}

这个 Playbook 是以 sudo: yes 的权限运行的,所以我不明白为什么会出现这个错误(看起来像是权限错误)。有没有办法追踪问题根源呢?

- name: "Install very important packages"
  apt: pkg={{ item }} update_cache=yes state=present
  with_items:
    - software-properties-common # for apt repository management
    - python-pycurl # for apt repository management (Ansible support)
    - openssh-server
    - ufw
    - unattended-upgrades
    - vim
    - curl
    - git
    - ntp

实战手册:

- hosts: build.url.com
  sudo: yes
  roles:
    - { role: postgresql, tags: postgresql }
    - { role: ruby, tags: ruby }
    - { role: build, tags: build }

你能否展示一下导致问题的playbook部分以及你正在执行的ansible命令? - Abhishek Balaji R
@AbhishekBalajiR 编辑过的内容 - supersize
1
你能在安装任务中添加 become: true 吗?如果这样不行,可能值得检查一下是否能够手动安装软件包,否则尝试重新启动服务器。这里有一些建议:链接 - Abhishek Balaji R
这是在配置Ubuntu(以及可能一些其他发行版)时非常常见的情况。你试图在自动更新后台运行时运行Ansible(这是在设置新机器之后发生的)。由于APT使用信号量,Ansible被踢出。请搜索AskUbuntu或Unix.SE以获取建议。Playbook没问题,稍后可以通过运行它来验证。 - techraf
4个回答

18

我在新的虚拟机上遇到了同样的问题。我尝试了许多方法,包括重试apt命令,但最终唯一的方法是删除未经审查的升级。

由于这时候VM没有安装Python,所以我使用raw命令,但我需要一个可靠的apt来安装它。

由于这是一个VM,并且我通过将其重置为快照来测试playbook,系统日期不正确,这迫使我使用date -s命令,以便在apt命令期间不会出现SSL证书问题。这个date -s触发了一个未经审查的升级。

因此,这个playbook片段基本上是有关在新系统中禁用未经审查的升级的部分。它们是我在新系统上发布的第一个命令。

- name: Disable timers for unattended upgrade, so that none will be triggered by the `date -s` call.
  raw: systemctl disable --now {{item}}
  with_items:
    - 'apt-daily.timer'
    - 'apt-daily-upgrade.timer'

- name: Reload systemctl daemon to apply the new changes
  raw: systemctl daemon-reload

# Syncing time is only relevant for testing, because of the VM's outdated date.
#- name: Sync time
#  raw: date -s "{{ lookup('pipe', 'date') }}"

- name: Wait for any possibly running unattended upgrade to finish
  raw: systemd-run --property="After=apt-daily.service apt-daily-upgrade.service" --wait /bin/true

- name: Purge unattended upgrades
  raw: apt-get -y purge unattended-upgrades    

- name: Update apt cache
  raw: apt-get -y update

- name: If needed, install Python
  raw: test -e /usr/bin/python || apt-get -y install python

任何其它的操作都会导致 apt 命令由于未经授权的升级导致锁定问题而随机失败。


嗨,我尝试了上面的代码,但是Ansible告诉我找不到systemctl、systemd-run或apt-get命令。 - Mark R

11

当安装Ubuntu(以及其他一些发行版)时,出现了一个非常常见的情况。你尝试在后台运行自动更新(这是在设置新机器后发生的情况)时运行Ansible。由于APT使用信号量,因此Ansible会被踢出。

Playbook没问题,最简单的验证方法是在自动更新完成后再运行它。

针对永久解决方案,您可以考虑以下方法:

  • 使用禁用自动更新的OS映像
  • 在Ansible playbook中添加明确的循环,以重复执行失败的任务直到成功为止

就是这样了! :) - supersize
3
还有一个技巧可以等待init脚本完成:https://serverfault.com/questions/855872/how-to-wait-for-user-data-script-to-run-when-starting-ec2-instances-with-ansible/855898#855898 - Konstantin Suvorov
@KonstantinSuvorov 你确定这是启动过程的一部分吗?APT自动更新会在后台循环运行,即使在没有重启的情况下也是如此。 - techraf
一般来说,apt 更新随时可能发生。但是当我们谈论服务器配置时,apt 锁定通常被 cloud-init 占用,这就是我的备注所指的。 - Konstantin Suvorov
有趣...所以如果我从快照中还原了一台机器,它会在boot-finished创建之前更新吗?我迫不及待要测试一下... :) - techraf

0
对于遇到相同问题的任何人,这对我有效。
- name: wait until apt lock is released
  shell: lsof -w /var/lib/apt/lists/lock | wc -l
  register: lock
  until: lock.stdout == "0"
  retries: 10
  delay: 10

- name: wait until apt lock_frontend is released
  shell: lsof -w /var/lib/dpkg/lock-frontend | wc -l
  register: lock_frontend
  until: lock_frontend.stdout == "0"
  retries: 10
  delay: 10

0
我也遇到了这个错误,以下是解决方法。
name: update apt package
  become: yes
  apt:
    name: '*'
    state: latest
    update_cache: true
  register: apt_get_status    <<<<<<<<<<<<<<
  until: apt_get_status is success  <<<<<<<<
  retries: 60
  delay: 10

根据目前的写法,你的回答不够清晰。请编辑以添加更多细节,帮助其他人理解这如何回答所提出的问题。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接