Sửa lỗi Ansible apt Module Thất Bại với 'dpkg was interrupted' trên Ubuntu/Debian

intermediate🔧 Ansible2026-05-17| Ansible 2.9+, Ubuntu 20.04/22.04, Debian 10/11/12, apt module

Error Message

E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem.
#ansible#apt#dpkg#ubuntu#debian#package

Chuyện Gì Vừa Xảy Ra

Playbook Ansible của bạn đang cài đặt package bình thường, rồi có gì đó xảy ra sai — host khởi động lại giữa chừng khi đang cài, mất điện, hoặc một tiến trình apt/dpkg trước đó bị kill. Giờ mọi playbook nào đụng vào package trên host đó đều nổ với lỗi:

E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem.

Module apt thoát với mã lỗi khác 0, play thất bại, và nếu lỗi này đang xảy ra trên 20 server lúc 2 giờ sáng, bạn cần một cách fix không đòi hỏi phải SSH vào từng máy một.

Xác Nhận Trạng Thái Trên Host

Trước khi làm bất cứ điều gì, hãy xác nhận bạn đang thực sự đối mặt với trạng thái dpkg bị hỏng — chứ không phải một lỗi apt khác trông giống vậy. SSH vào và chạy:

sudo apt-get update

Nếu bạn thấy đúng lỗi đó, thì cơ sở dữ liệu dpkg đang mắc kẹt ở trạng thái cấu hình dở dang. Tiếp theo kiểm tra xem cái gì bị hỏng:

sudo dpkg --audit

Lệnh này liệt kê các package bị giải nén dở, cấu hình dở, hoặc script postinst chạy thất bại. Mã thoát 1 có nghĩa là có gì đó bị hỏng. Giữ kết quả đó lại — nó cho bạn biết cần mong đợi gì khi chạy lệnh fix.

Cách Fix Trực Tiếp (Một Host)

SSH vào và chạy:

sudo dpkg --configure -a

Theo dõi kết quả đầu ra cẩn thận. Lệnh này sẽ cố hoàn tất việc cấu hình các package bị gián đoạn. Khi nó chạy xong sạch sẽ, tiếp tục chạy:

sudo apt-get install -f

Lệnh này dọn sạch các chuỗi dependency bị hỏng còn sót lại. Sau đó kiểm tra nhanh:

sudo apt-get update && sudo apt-get upgrade --dry-run

Không có lỗi? Host đã sạch. Chạy lại playbook Ansible của bạn.

Cách Fix Bằng Ansible (Tất Cả Các Host Bị Ảnh Hưởng Cùng Lúc)

Cả một cluster rơi vào trạng thái này sau một lần rolling upgrade thất bại? Xử lý trực tiếp bằng Ansible — không cần SSH thủ công từng máy.

Tùy Chọn 1: Thêm Pre-task Vào Playbook Hiện Có

Thêm block này trước các task cài đặt package của bạn:

- name: Fix interrupted dpkg if present
  hosts: all
  become: yes
  pre_tasks:
    - name: Check if dpkg is in interrupted state
      command: dpkg --audit
      register: dpkg_audit
      changed_when: false
      failed_when: false

    - name: Run dpkg --configure -a if needed
      command: dpkg --configure -a
      when: dpkg_audit.stdout != ""

    - name: Fix broken apt dependencies
      apt:
        fix_broken: yes
      when: dpkg_audit.stdout != ""

An toàn khi chạy trên các host bình thường — fix chỉ thực thi khi dpkg --audit thực sự tìm thấy vấn đề.

Tùy Chọn 2: Playbook Khôi Phục Độc Lập

Cần một play khôi phục riêng có thể áp dụng cho bất kỳ nhóm host nào? Đây là một playbook bạn có thể giữ để dùng:

---
- name: Recover interrupted dpkg on Ubuntu/Debian hosts
  hosts: "{{ target_hosts | default('all') }}"
  become: yes
  gather_facts: yes

  tasks:
    - name: Skip non-Debian systems
      meta: end_host
      when: ansible_os_family != "Debian"

    - name: Audit dpkg state
      command: dpkg --audit
      register: dpkg_audit
      changed_when: false
      failed_when: false

    - name: Report audit findings
      debug:
        msg: "Broken packages detected: {{ dpkg_audit.stdout_lines }}"
      when: dpkg_audit.stdout != ""

    - name: Configure interrupted dpkg packages
      command: dpkg --configure -a
      environment:
        DEBIAN_FRONTEND: noninteractive
      when: dpkg_audit.stdout != ""
      register: dpkg_configure

    - name: Fix broken apt dependencies
      apt:
        fix_broken: yes
        update_cache: no
      when: dpkg_audit.stdout != ""

    - name: Verify apt is healthy
      apt:
        update_cache: yes
      when: dpkg_audit.stdout != ""

Chạy bằng lệnh:

ansible-playbook recover-dpkg.yml -e target_hosts=webservers

Tại Sao DEBIAN_FRONTEND Quan Trọng Ở Đây

Chú ý DEBIAN_FRONTEND: noninteractive trong task dpkg --configure -a. Nếu bỏ qua, các package có script postinst tương tác sẽ bị treo — chờ đầu vào từ bàn phím mà sẽ không bao giờ đến trong một phiên SSH của Ansible. Playbook của bạn sẽ bị treo vô thời hạn.

Module apt của Ansible tự động đặt biến này. Các task command hoặc shell thô gọi dpkg trực tiếp thì không. Hãy đặt nó một cách tường minh mỗi lần.

Tại Sao Lỗi Này Cứ Xảy Ra

Hai file lock bảo vệ các thao tác package: /var/lib/dpkg/lock/var/lib/dpkg/lock-frontend. Chúng đảm bảo chỉ có một tiến trình apt/dpkg chạy tại một thời điểm. Khi tiến trình đó bị kill giữa chừng — khởi động lại trong khi đang nâng cấp, SIGKILL, OOM killer, cloud instance bị dừng — dpkg để lại các file trạng thái được ghi dở dang.

Lần tiếp theo bất cứ thứ gì đụng vào apt, nó đọc các file đó, phát hiện sự không nhất quán, và từ chối tiếp tục. Không phải nó cứng đầu. Nó chỉ đang hỏi bạn có muốn hoàn tất những gì đã bị gián đoạn không.

Phòng Ngừa Về Sau

  • Không bao giờ khởi động lại giữa chừng khi đang cài. Thêm kiểm tra trước: nếu /var/run/reboot-required tồn tại, xử lý việc khởi động lại trước khi đụng vào package.
  • Xử lý xung đột với unattended-upgrades. Chạy unattended-upgrades song song với Ansible liên tục gây tranh chấp lock. Tắt nó trên các host do Ansible quản lý, hoặc giới hạn nó vào cửa sổ bảo trì không trùng với lịch chạy playbook của bạn.
  • Thêm logic retry cho các task apt. Lỗi lock tạm thời rất phổ biến trong pipeline CI/CD khi chạy song song:
- name: Install packages
  apt:
    name: nginx
    state: present
  register: apt_result
  until: apt_result is succeeded
  retries: 3
  delay: 10
  • Dọn sạch file lock cũ khi an toàn. Nếu một tiến trình chết mà không giải phóng lock, hãy xóa nó — nhưng chỉ khi bạn chắc chắn không có gì đang thực sự chạy:
- name: Remove stale dpkg locks if no apt process is running
  file:
    path: "{{ item }}"
    state: absent
  loop:
    - /var/lib/dpkg/lock
    - /var/lib/dpkg/lock-frontend
    - /var/cache/apt/archives/lock
  when: "'apt' not in ansible_facts.get('services', {})"

Xác Nhận Fix Đã Thành Công

Sau khi khôi phục, chạy các lệnh này trên host:

# Nên trả về mã thoát 0 và không có output
sudo dpkg --audit && echo "dpkg is clean"

# Nên hoàn tất không có lỗi
sudo apt-get update

# Chạy lại playbook gốc của bạn
ansible-playbook your-playbook.yml --limit affected_host

Playbook chạy hoàn tất, không có lỗi dpkg trong kết quả đầu ra — host đã được khôi phục.

Tóm Lại

dpkg was interrupted là dpkg đang báo cho bạn biết nó phát hiện sự không nhất quán và cần xác nhận trước khi tiếp tục. Cách fix luôn giống nhau: dpkg --configure -a, rồi apt-get install -f. Hai lệnh.

Phần khó hơn là xây dựng các Ansible playbook có khả năng tự phát hiện và khôi phục trạng thái này — để một host bị gián đoạn lúc 3 giờ sáng không làm tắc nghẽn toàn bộ pipeline triển khai trong khi mọi người đang ngủ.

Related Error Notes