Systemd ، نصوص تفاعلية ومؤقتات

Systemd ، نصوص تفاعلية ومؤقتات

مقدمة

عند التطوير لنظام Linux، تنشأ مهمة إنشاء نصوص برمجية تفاعلية يتم تنفيذها عند تشغيل النظام أو إيقاف تشغيله. كان هذا الأمر سهلاً في النظام V، لكن مع systemd يمكن إجراء التعديلات. ولكن يمكن أن يكون لها توقيت خاص بها.

لماذا نحتاج إلى الأهداف؟

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

مثال على الهدف عند تمكينه (نظرة عامة على الميزات) مع تشغيل البرنامج النصي التفاعلي

وصف الهدف نفسه:

cat installer.target
[Unit]
Description=My installer
Requires=multi-user.target 
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target 
AllowIsolate=yes
Wants=installer.service

سيبدأ هذا الهدف عند تشغيل multi-user.target واستدعاء installer.service. ومع ذلك، قد يكون هناك العديد من هذه الخدمات.

cat installer.service
[Unit]
# описание
Description=installer interactive dialog

[Service]
# Запустить один раз, когда остальное будет запущенно
Type=idle
# Команда запуска - вызов скрипта
ExecStart=/usr/bin/installer.sh
# Интерактивное взаимодействие с пользователем через tty3
StandardInput=tty
TTYPath=/dev/tty3
TTYReset=yes
TTYVHangup=yes

[Install]
WantedBy=installer.target

وأخيرًا، مثال على البرنامج النصي الذي يتم تنفيذه:

#!/bin/bash
# Переходим в tty3
chvt 3
echo "Install, y/n ?"
read user_answer

أهم شيء هو تحديد Final.target - الهدف الذي يجب أن يصل إليه النظام عند بدء التشغيل. أثناء عملية بدء التشغيل، سيمر systemd عبر التبعيات وسيطلق كل ما يحتاج إليه.
هناك طرق مختلفة لتحديد Final.target، لقد استخدمت خيار المُحمل لهذا الغرض.

يبدو الإطلاق النهائي كما يلي:

  1. يبدأ محمل الإقلاع
  2. يبدأ برنامج تحميل التشغيل في تشغيل البرنامج الثابت عن طريق تمرير المعلمة Final.target
  3. يبدأ Systemd في بدء تشغيل النظام. ينتقل بشكل تسلسلي إلى installer.target أوwork.target من basic.target عبر تبعياتهما (على سبيل المثال، multi-user.target). هذا الأخير يجعل النظام يعمل في الوضع المطلوب

تحضير البرامج الثابتة للإطلاق

عند إنشاء البرامج الثابتة، تنشأ دائمًا مهمة استعادة حالة النظام عند بدء التشغيل وحفظها عند إيقاف التشغيل. الحالة تعني ملفات التكوين، وتفريغ قاعدة البيانات، وإعدادات الواجهة، وما إلى ذلك.

يقوم Systemd بتشغيل العمليات في نفس الهدف بالتوازي. هناك تبعيات تسمح لك بتحديد تسلسل بدء تشغيل البرامج النصية.

كيف يعمل في مشروعي ( https://habr.com/ru/post/477008/ https://github.com/skif-web/monitor)

  1. يبدأ النظام
  2. يتم تشغيل خدمة settings_restore.service، وهي تتحقق من وجود ملف settings.txt في قسم البيانات. إذا لم يكن هناك، فسيتم وضع ملف مرجعي في مكانه، وبعد ذلك تتم استعادة إعدادات النظام:
    • كلمة مرور المسؤول
    • اسم المضيف ،
    • وحدة زمنية
    • لغة
    • يحدد ما إذا كان يتم استخدام كافة الوسائط. بشكل افتراضي، يكون حجم الصورة صغيرًا - لسهولة النسخ والتسجيل على الوسائط. عند بدء التشغيل، فإنه يتحقق لمعرفة ما إذا كان لا يزال هناك مساحة غير مستخدمة. إذا كان هناك، تتم إعادة تقسيم القرص.
    • إنشاء معرف الجهاز من عنوان MAC. وهذا مهم للحصول على نفس العنوان عبر DHCP
    • إعدادات الشبكة
    • يحد من حجم السجلات
    • يتم تحضير محرك الأقراص الخارجي للعمل (إذا تم تمكين الخيار المقابل وكان محرك الأقراص جديدًا)
  3. ابدأ بـ postgresq
  4. تبدأ خدمة الاستعادة. هناك حاجة لإعداد zabbix نفسه وقاعدة البيانات الخاصة به:
    • التحقق مما إذا كانت هناك بالفعل قاعدة بيانات zabbix. إذا لم يكن الأمر كذلك، فسيتم إنشاؤه من مقالب التهيئة (المضمنة مع zabbix)
    • يتم إنشاء قائمة بالمناطق الزمنية (مطلوبة لعرضها في واجهة الويب)
    • تم العثور على عنوان IP الحالي، وتم عرضه في المشكلة (دعوة لتسجيل الدخول إلى وحدة التحكم)
  5. تتغير الدعوة - ​​تظهر العبارة جاهز للعمل
  6. البرامج الثابتة جاهزة للاستخدام

ملفات الخدمة مهمة، فهي التي تحدد تسلسل إطلاقها

[Unit]
Description=restore system settings
Before=network.service prepare.service postgresql.service systemd-networkd.service systemd-resolved.service

[Service]
Type=oneshot
ExecStart=/usr/bin/settings_restore.sh

[Install]
WantedBy=multi-user.target

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

والخدمة الثانية (تحضير الزابيكس)

#!/bin/sh
[Unit]
Description=monitor prepare system
After=postgresql.service settings_restore.service
Before=zabbix-server.service zabbix-agent.service

[Service]
Type=oneshot
ExecStart=/usr/bin/prepare.sh

[Install]
WantedBy=multi-user.target

الأمر أكثر تعقيدًا بعض الشيء هنا، حيث يتم الإطلاق أيضًا في multi-user.target، ولكن بعد بدء تشغيل Postgresql DBMS وsetting_restore. ولكن قبل بدء خدمات zabbix.

خدمة الموقت لlogrotate

يمكن لـ Systemd أن يحل محل CRON. بجد. علاوة على ذلك، فإن الدقة لا تصل إلى الدقيقة، بل تصل إلى الثانية (ماذا لو كانت هناك حاجة إليها). أو يمكنك إنشاء مؤقت رتيب، يتم استدعاؤه بواسطة مهلة من حدث ما.
لقد كان الموقت الرتيب هو الذي يحسب الوقت من بداية تشغيل الجهاز الذي قمت بإنشائه.
سيتطلب هذا ملفين
logrotateTimer.service - الوصف الفعلي للخدمة:

[Unit]
Description=run logrotate

[Service]
ExecStart=logrotate /etc/logrotate.conf
TimeoutSec=300

الأمر بسيط - وصف أمر الإطلاق.
الملف الثاني logrotateTimer.timer هو المكان الذي تعمل فيه المؤقتات:

[Unit]
Description=Run logrotate

[Timer]
OnBootSec=15min
OnUnitActiveSec=15min

[Install]
WantedBy=timers.target

ماذا هنا:

  • وصف الموقت
  • وقت البدء الأول، بدءًا من تمهيد النظام
  • فترة إطلاق أخرى
  • الاعتماد على خدمة المؤقت، في الواقع، هذه هي السلسلة التي تصنع المؤقت

برنامج نصي تفاعلي عند إيقاف التشغيل وهدف إيقاف التشغيل

في تطور آخر، كان علي أن أقوم بإصدار أكثر تعقيدًا لإيقاف تشغيل الجهاز - من خلال هدفي الخاص، من أجل تنفيذ العديد من الإجراءات. يوصى عادةً بإنشاء خدمة Oneshot باستخدام خيار RemainAfterExit، لكن هذا يمنعك من إنشاء برنامج نصي تفاعلي.

لكن الحقيقة هي أن الأوامر التي يطلقها خيار ExecOnStop يتم تنفيذها خارج جهاز TTY! من السهل التحقق - الصق الأمر tty واحفظ مخرجاته.

ولذلك، قمت بتنفيذ عملية الاغلاق من خلال هدفي. لا أدعي أنني على حق بنسبة 100٪، لكنه يعمل!
كيف تم ذلك (بعبارات عامة):
لقد قمت بإنشاء هدف my_shutdown.target، والذي لا يعتمد على أي شخص:
my_shutdown.target

[Unit]
Description=my shutdown
AllowIsolate=yes
Wants=my_shutdown.service 

عند الانتقال إلى هذا الهدف (عبر عزل systemctl my_shutdwn.target)، تم إطلاق خدمة my_shutdown.service، ومهمتها بسيطة - تنفيذ البرنامج النصي my_shutdown.sh:

[Unit]
Description=MY shutdown

[Service]
Type=oneshot
ExecStart=/usr/bin/my_shutdown.sh
StandardInput=tty
TTYPath=/dev/tty3
TTYReset=yes
TTYVHangup=yes

WantedBy=my_shutdown.target

  • داخل هذا البرنامج النصي أقوم بالإجراءات اللازمة. يمكنك إضافة العديد من البرامج النصية إلى الهدف لتحقيق المرونة والراحة:

my_shutdown.sh

#!/bin/bash --login
if [ -f /tmp/reboot ];then
    command="systemctl reboot"
elif [ -f /tmp/shutdown ]; then
    command="systemctl poweroff"
fi
#Вот здесь нужные команды
#Например, cp /home/user/data.txt /storage/user/
    $command

ملحوظة. استخدام الملفات /tmp/reboot و/tmp/shutdown. لا يمكنك استدعاء الهدف باستخدام المعلمات. الخدمة الوحيدة الممكنة.

لكنني أستخدم الهدف للحصول على المرونة في العمل وترتيب الإجراءات المضمون.

ومع ذلك، فإن الشيء الأكثر إثارة للاهتمام جاء في وقت لاحق. يحتاج الجهاز إلى إيقاف/إعادة التشغيل. وهناك خياران:

  • استبدل أوامر إعادة التشغيل وإيقاف التشغيل والأوامر الأخرى (التي لا تزال عبارة عن روابط رمزية لـ systemctl) بالنص البرمجي الخاص بك. داخل البرنامج النصي، انتقل إلى my_shutdown.target. وتقوم البرامج النصية الموجودة داخل الهدف باستدعاء systemctl مباشرة، على سبيل المثال، systemctl reboot
  • خيار أبسط، لكني لا أحبه. في جميع الواجهات، لا تستدعي Shutdown/reboot/other، بل اتصل مباشرةً بالهدف systemctl isolate my_shutdown.target

اخترت الخيار الأول. في systemd، تعتبر إعادة التشغيل (مثل poweroff) عبارة عن روابط رمزية لـ systemd.

ls -l /sbin/poweroff 
lrwxrwxrwx 1 root root 14 сен 30 18:23 /sbin/poweroff -> /bin/systemctl

لذلك، يمكنك استبدالها بالنصوص البرمجية الخاصة بك:
إعادة تشغيل

#!/bin/sh
    touch /tmp/reboot
    sudo systemctl isolate my_shutdown.target
fi

المصدر: www.habr.com

إضافة تعليق