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 và /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-requiredtồ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ủ.

