Khắc phục lỗi 'Could not get lock /var/lib/dpkg/lock-frontend' trong Ansible

beginner🔧 Ansible2026-04-18| Ubuntu 18.04/20.04/22.04/24.04, Debian 10/11/12, Ansible 2.9+

Error Message

E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)
#ansible#apt#ubuntu#debian#devops#khắc phục sự cố

Vấn đề

Bạn chạy một Ansible playbook trên một instance Ubuntu hoặc Debian mới, nhưng nó bị lỗi ngay lập tức. Thông thường, lỗi sẽ trông như thế này:

FAILED! => {
    "msg": "'/usr/bin/apt-get dist-upgrade' failed: E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)",
    "rc": 100
}

Điều gì đang xảy ra?

Trình quản lý gói apt sử dụng các tệp khóa (lock files) như /var/lib/dpkg/lock-frontend để ngăn nhiều tiến trình thay đổi cơ sở dữ liệu cùng lúc. Nếu một công cụ khác đang bận cài đặt phần mềm, Ansible sẽ bị chặn.

Các nguyên nhân phổ biến bao gồm:

- **Cập nhật tự động (Unattended Upgrades):** Các phiên bản Ubuntu hiện đại thường chạy `apt update` tự động trong vòng 60 giây sau khi khởi động.
- **Các tác vụ chồng chéo:** Bạn có thể đang chạy nhiều playbook hoặc số lượng fork cao nhắm vào cùng một node.
- **Tiến trình treo (Zombies):** Một lần thử cài đặt trước đó bị sập, để lại tệp khóa cũ.

Giải pháp 1: Tham số "Kiên nhẫn" (Cách tiếp cận tốt nhất)

Bắt đầu từ Ansible 2.8, module apt tích hợp sẵn cách để chờ khóa. Thay vì báo lỗi, Ansible sẽ đợi trong số giây được chỉ định để tệp khóa biến mất.

- name: Cài đặt Nginx với thời gian chờ khóa (lock timeout)
  apt:
    name: nginx
    state: present
    lock_timeout: 300

Điều này yêu cầu Ansible chờ tối đa 5 phút. Đây là giải pháp sạch nhất vì nó xử lý các bản cập nhật chạy ngầm mà không cần logic bổ sung hay các câu lệnh shell phức tạp.

Giải pháp 2: Logic thử lại thủ công

Nếu bạn đang sử dụng phiên bản Ansible cũ hơn hoặc muốn kiểm soát nhiều hơn, hãy sử dụng until. Cách này sẽ thử lại tác vụ 10 lần với khoảng cách 10 giây, giúp các tiến trình ngầm có 100 giây để hoàn tất.

- name: Cài đặt Nginx với cơ chế thử lại
  apt:
    name: nginx
    state: present
    update_cache: yes
  register: apt_result
  until: apt_result is success
  retries: 10
  delay: 10

Giải pháp 3: Kiểm tra trước khi chạy (Pre-Flight Check)

Đôi khi bạn muốn dọn đường trước khi thực hiện bất kỳ tác vụ gói nào. Bạn có thể thêm một tác vụ ở ngay đầu playbook để đợi cho đến khi tiến trình apt rảnh.

- name: Đợi cho đến khi apt lock được giải phóng
  shell: fuser /var/lib/dpkg/lock-frontend
  register: lock_check
  until: lock_check.rc != 0
  retries: 20
  delay: 10
  failed_when: false
  changed_when: false

Trong đoạn mã này, fuser trả về mã thoát khác không khi không có tiến trình nào đang sử dụng tệp. Ansible sẽ lặp lại cho đến khi điều đó xảy ra.

Giải pháp 4: Vô hiệu hóa cập nhật tự động

Trên các trình chạy CI/CD hoặc hạ tầng bất biến (immutable infrastructure), bạn có thể muốn dừng hoàn toàn việc hệ điều hành tự cập nhật. Điều này đảm bảo Ansible là thực thể duy nhất quản lý các gói phần mềm.

- name: Dừng và vô hiệu hóa unattended-upgrades
  systemd:
    name: unattended-upgrades
    state: stopped
    enabled: no

- name: Vô hiệu hóa các timer apt hàng ngày
  systemd:
    name: "{{ item }}"
    state: stopped
    enabled: no
  loop:
    - apt-daily.timer
    - apt-daily-upgrade.timer

Biện pháp cuối cùng: Dùng vũ lực (Brute Force)

Nếu tệp khóa thực sự bị kẹt—có lẽ do một phiên SSH bị ngắt kết nối—bạn có thể xóa nó thủ công. Cảnh báo: Chỉ sử dụng cách này nếu bạn chắc chắn không có bản cập nhật thực sự nào đang chạy. Việc xóa các tệp này trong khi đang cập nhật có thể làm hỏng cơ sở dữ liệu dpkg của bạn.

- name: Cưỡng ép xóa các tệp khóa cũ
  file:
    path: "{{ item }}"
    state: absent
  loop:
    - /var/lib/dpkg/lock
    - /var/lib/dpkg/lock-frontend
    - /var/lib/apt/lists/lock

Cách kiểm tra

Để xem tiến trình nào đang chiếm giữ playbook của bạn, hãy đăng nhập vào máy chủ và chạy:

sudo lsof /var/lib/dpkg/lock-frontend

Nếu nó trả về một PID (Process ID), đó chính là thủ phạm. Nếu không trả về gì, khóa đang trống. Khi chạy Ansible, hãy sử dụng -vvv để xem chính xác số lần các tác vụ của bạn đang thử lại trước khi thành công.

Related Error Notes