تنتهي جولة الـ playbook باللون الأخضر، ووحدة WireGuard نشطة، والمصافحة تعمل، ومع ذلك لا يصل النظير الجديد إلى أي شيء. إن مشاهدة playbook يُبلّغ بالنجاح بينما يعمل الخادم بإعدادات الأمس إحباط من نوع خاص، لأن شيئًا في الخرج ليس خاطئًا. لقد نفّذ Ansible ما طُلب منه بالضبط: تأكد من أن الوحدة بدأت، وكانت الوحدة قد بدأت بالفعل. أما تطبيق ملف إعدادات مُعاد كتابته فهو مهمة أخرى، ولا يحدث إلا إذا طلب شيء من الخدمة إعادة قراءته.

راقب ما تُبلغ عنه جولة ثانية فعليًا

شغّل الـ playbook مرتين مع الإعدادات المُعدّلة في مكانها وقارن الملخص. يجب أن تُظهر الجولة الثانية مهمة الوحدة بحالة ok بدل changed، لأن الخدمة العاملة بالفعل تُترك كما هي بحكم التصميم. هذا هو التماثل الذاتي يعمل بشكل صحيح، وهو أيضًا سبب عدم وصول الملف الجديد إلى النواة أبدًا.

أضف جولة تحقق مع خرج diff لترى أي المهام ستلمس شيئًا على الإطلاق.

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

الطوابع الزمنية الثلاثة تحكي القصة قبل أن تقرأ سطر سجل واحدًا. إذا كان ملف الإعدادات أحدث من اللحظة التي أصبحت فيها الوحدة نشطة، فإن الواجهة العاملة بُنيت من ملف أقدم، وكل عرض لاحق ينبع من ذلك.

هذا ليس عيبًا في Ansible. يظهر السلوك نفسه مع أي أداة لإدارة الإعدادات تفصل بين «تأكد أنه يعمل» و«تأكد أنه يعمل بهذا». يبدو الفرق تنطعًا حتى يكلفك عصرًا كاملًا.

«started» حالة، وليست إعادة تحميل

state: started يؤكّد شرطًا يخص الوحدة. وهو لا يعِد بأن الخدمة أعادت قراءة مدخلاتها، ولا يمكنه أن يعرف أن ملفًا لم يفتحه قط قد تغيّر. في نشر wg-quick تشمل المدخلات إعدادات الواجهة والعناوين والمسارات ومدخلات DNS وأي خطافات post-up.

لهذا يمكن أن يحتوي ملف محدَّث على نظير جديد أو عنوان مختلف أو توجيه مسار متغيّر بينما تستمر الواجهة الحيّة في تقديم المجموعة القديمة. تنجح المصافحة لأن المفاتيح ونقاط النهاية المحمّلة ما زالت صالحة. وهذا بالضبط ما يجعل الفشل صعب الملاحظة، ولماذا يطارد الناس DNS ساعة قبل أن يفحصوا طابعًا زمنيًا.

هناك خياران آخران في الوحدة يُفهمان عادةً على أنهما حل. daemon_reload يجعل systemd يعيد قراءة ملفات الوحدات، وهذا لا علاقة له بملف إعدادات WireGuard. state: reloaded يطلب من الوحدة تنفيذ إجراء إعادة التحميل، وما إذا كان هذا الإجراء يفعل ما تحتاجه يعتمد كليًا على الوحدة. لا أي منهما بديل عن معرفة المدخلات التي قرأها العملية العاملة فعليًا.

ثبّت الملف ثم أبلِغ معالجًا

النمط الذي يحفظ التماثل الذاتي ويطبّق التغييرات معًا هو النمط العادي: المهمة التي تكتب الملف تُبلِغ معالجًا، ولا يعمل المعالج إلا عندما يتغير الملف فعليًا. الجولة الثانية دون تعديلات لا تفعل شيئًا على الإطلاق، وهذا ما تريده.

- 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

تعمل المعالجات في نهاية المسرحية، بعد المهام التي أبلغتها، لذا قد ترى مهمة لاحقة في المسرحية نفسها الواجهة القديمة. إذا كان الترتيب مهمًا، أفرِغ المعالجات صراحةً بواسطة meta: flush_handlers قبل المهمة التي تعتمد على الإعدادات الجديدة.

استخدم restart بدل reload ما لم تتحقق من إجراء إعادة التحميل في الوحدة. وحدة wg-quick المنبعية تدعم واحدًا فعلًا، وهي تزامن إعدادات WireGuard، لكنها لا تعيد تنفيذ إعداد العناوين أو المسارات أو DNS أو الخطافات. لذلك تبدو إعادة تحميل بعد إضافة توجيه مسار ناجحة ولا تغيّر شيئًا.

قارن الجهاز الحيّ بالملف

الفحص الذي يُغلق هذا الصنف من الأخطاء هو مقارنة بين ما تحتفظ به النواة وما يقوله الملف. أمران ينتجان خرجًا قابلًا للمقارنة، والفرق هو الانحراف.

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

wg showconf يطبع الجهاز الحيّ، بما في ذلك المفتاح الخاص، لذا تعامل مع ذلك الخرج كسرّ ولا تلصقه في تذكرة. wg-quick strip يطبع الملف بعد إزالة المفاتيح الخاصة بـ wg-quick، ولهذا يمكن مقارنة الاثنين أصلًا.

اختلاف في قائمة النظير يعني أن الملف لم يُطبَّق قط. اختلاف محصور في مفاتيح أو نقاط نهاية توقعت تغيّرها يعني أن شيئًا طبّقه جزئيًا. عدم وجود اختلاف يعني أن الإعدادات حالية والعطل في مكان آخر، وهذا بحد ذاته نتيجة مفيدة.

ادفع كلفة إعادة التشغيل بوعي

إعادة تشغيل الواجهة تُسقط النفق، وإذا كان ذلك النفق يحمل جلستك الإدارية، فإن إعادة التشغيل تنهي الجلسة التي طلبتها. ضع المعالج خلف نافذة تغيير، أو شغّل الـ playbook من مسار إدارة لا يعتمد على إعادة تشغيل الواجهة.

الكلفة هي سبب لجوء الناس إلى reload. هذا حدس معقول، ويصبح صحيحًا حين تعرف أي التغييرات يطبّقها reload فعلًا. لتغييرات النظير والمفاتيح على وحدة wg-quick المنبعية يكفي؛ أما للعناوين والمسارات والخطافات فلا. تسوية ذلك مرة واحدة أرخص من اكتشافه أثناء نافذة تغيير.

توثيق وحدة systemd_service يوضح الفرق بين started وrestarted وreloaded، ويستحق قراءة واحدة بدل استنتاجه من ملخص أخضر. كل شيء في هذا الشرح ينبع من ذلك الفرق الوحيد.

مقالات ذات صلة