Lần chạy playbook kết thúc màu xanh, unit WireGuard đang hoạt động, handshake chạy được, và peer mới vẫn không kết nối được gì. Thấy playbook báo thành công trong khi máy chủ chạy cấu hình của hôm qua là điều đặc biệt bực bội, vì không có gì sai trong đầu ra. Ansible đã làm đúng những gì được yêu cầu: nó bảo đảm unit đã được khởi động, và unit vốn đã khởi động. Áp dụng một tệp cấu hình được viết lại là công việc khác, và chỉ xảy ra nếu có gì đó bảo dịch vụ đọc lại tệp.

Xem lần chạy thứ hai thực sự báo cáo gì

Chạy playbook hai lần với cấu hình đã thay đổi và so sánh bản tóm tắt. Lần chạy thứ hai phải hiển thị nhiệm vụ unit là ok, không phải changed, vì dịch vụ đang chạy được để yên theo thiết kế. Đó là idempotence hoạt động đúng, và cũng là lý do tệp mới không bao giờ đến được kernel.

Thêm một lần chạy kiểm tra với đầu ra diff để xem nhiệm vụ nào sẽ chạm vào thứ gì.

ansible-playbook -i inventory site.yml --check --diff
systemctl show wg-quick@wg0 -p ActiveEnterTimestamp -p NRestarts
stat -c '%y %n' /etc/wireguard/wg0.conf

Ba dấu thời gian kể câu chuyện trước khi bạn đọc một dòng log nào. Nếu tệp cấu hình mới hơn thời điểm unit trở nên hoạt động, giao diện đang chạy được dựng từ tệp cũ hơn, và mọi triệu chứng sau đó đều bắt nguồn từ đó.

Đây không phải lỗi của Ansible. Hành vi tương tự xuất hiện ở bất kỳ công cụ quản lý cấu hình nào tách «bảo đảm nó đang chạy» khỏi «bảo đảm nó đang chạy cái này». Sự khác biệt có vẻ câu nệ cho đến khi nó khiến bạn mất một buổi chiều.

Đã khởi động là một trạng thái, không phải tải lại

state: started khẳng định một điều kiện về unit. Nó không hứa rằng dịch vụ sẽ đọc lại các đầu vào của mình, và nó không thể biết rằng một tệp mà nó chưa bao giờ mở đã thay đổi. Trong triển khai wg-quick, đầu vào bao gồm cấu hình giao diện, địa chỉ, tuyến đường, bản ghi DNS và mọi hook post-up.

Vì vậy một tệp đã cập nhật có thể chứa peer mới, địa chỉ khác hoặc chỉ thị định tuyến đã thay đổi trong khi giao diện đang chạy vẫn phục vụ bộ cũ. Handshake vẫn thành công vì các khóa và điểm cuối đã nạp vẫn còn hiệu lực. Chính điều đó khiến sự cố khó thấy, và tại sao người ta đuổi theo DNS cả tiếng trước khi kiểm tra dấu thời gian.

Hai tùy chọn khác của module thường bị nhầm là giải pháp. daemon_reload khiến systemd đọc lại các tệp unit, điều này không liên quan đến tệp cấu hình WireGuard. state: reloaded yêu cầu unit thực hiện hành động tải lại của nó, và việc nó có làm đúng nhu cầu của bạn hay không phụ thuộc hoàn toàn vào unit. Không cái nào thay thế việc biết tiến trình đang chạy thực sự đã đọc những đầu vào nào.

Cài tệp, rồi thông báo cho handler

Mẫu giữ được idempotence mà vẫn áp dụng thay đổi là mẫu thông thường: nhiệm vụ ghi tệp thông báo cho handler, và handler chỉ chạy khi tệp thực sự đã thay đổi. Lần chạy thứ hai không có chỉnh sửa không làm gì cả, và đó là điều bạn muốn.

- name: write the interface configuration
  ansible.builtin.template:
    src: wg0.conf.j2
    dest: /etc/wireguard/wg0.conf
    owner: root
    mode: "0600"
  notify: apply wg0

- name: ensure the interface unit is enabled
  ansible.builtin.systemd_service:
    name: wg-quick@wg0
    enabled: true
    state: started

- name: apply wg0
  listen: apply wg0
  ansible.builtin.systemd_service:
    name: wg-quick@wg0
    state: restarted

Handler chạy ở cuối play, sau các nhiệm vụ đã thông báo cho chúng, nên một nhiệm vụ phía sau trong cùng play vẫn có thể thấy giao diện cũ. Nếu thứ tự quan trọng, hãy xả handler một cách rõ ràng bằng meta: flush_handlers trước nhiệm vụ phụ thuộc vào cấu hình mới.

Dùng restart thay vì reload trừ khi bạn đã kiểm chứng hành động tải lại của unit. Unit wg-quick thượng nguồn hỗ trợ một hành động như vậy và đồng bộ cấu hình WireGuard, nhưng nó không chạy lại việc thiết lập địa chỉ, tuyến đường, DNS hay hook. Vì vậy một reload sau khi thêm chỉ thị tuyến đường trông như thành công và không thay đổi gì.

So sánh thiết bị đang chạy với tệp

Kiểm tra khép lại nhóm lỗi này là so sánh giữa điều kernel đang giữ và điều tệp nói. Hai lệnh tạo ra đầu ra so sánh được, và khác biệt chính là độ lệch.

sudo wg showconf wg0
sudo wg-quick strip wg0
sudo diff <(sudo wg showconf wg0) <(sudo wg-quick strip wg0)

wg showconf in thiết bị đang chạy, kể cả khóa riêng, nên hãy coi đầu ra đó là bí mật và đừng dán vào phiếu. wg-quick strip in tệp mà không có các khóa riêng của wg-quick, và đó là lý do hai bên so sánh được với nhau.

Khác biệt trong danh sách peer nghĩa là tệp chưa bao giờ được áp dụng. Khác biệt chỉ ở khóa hoặc điểm cuối mà bạn mong đổi nghĩa là có gì đó đã áp dụng một phần. Không khác biệt nghĩa là cấu hình đang hiện hành và lỗi nằm ở nơi khác, bản thân điều đó đã là kết quả hữu ích.

Trả giá của việc khởi động lại một cách có chủ đích

Khởi động lại giao diện làm đứt đường hầm, và nếu đường hầm đó mang phiên quản trị của bạn, việc khởi động lại kết thúc phiên đã yêu cầu nó. Đặt handler sau một cửa sổ thay đổi, hoặc chạy playbook từ một đường quản trị không phụ thuộc vào việc khởi động lại giao diện.

Chi phí là lý do người ta chuyển sang reload. Đó là bản năng hợp lý, và trở nên đúng khi bạn biết reload thực sự áp dụng những thay đổi nào. Với thay đổi peer và khóa trên unit wg-quick thượng nguồn thì đủ; với địa chỉ hóa, định tuyến và hook thì không. Làm rõ điều này một lần rẻ hơn là phát hiện trong một cửa sổ thay đổi.

Tài liệu module systemd_service giải thích khác biệt giữa started, restarted và reloaded, và đáng đọc một lần thay vì suy đoán từ một bản tóm tắt xanh. Mọi thứ trong hướng dẫn này bắt nguồn từ một khác biệt đó.

Bài viết liên quan