معرفی
هنگام توسعه برای لینوکس، وظیفه ایجاد اسکریپت های تعاملی که هنگام روشن یا خاموش شدن سیستم اجرا می شوند، مطرح می شود. در سیستم 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
این هدف زمانی شروع می شود که multiuser.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 وجود دارد، من برای این کار از گزینه loader استفاده کردم.
پرتاب نهایی به این صورت است:
- بوت لودر شروع می شود
- بوت لودر با عبور از پارامتر final.target شروع به راه اندازی سیستم عامل می کند
- Systemd شروع به راه اندازی سیستم می کند. بهطور متوالی به installer.target یا work.target از basic.target از طریق وابستگیهای آنها (مثلاً multi-user.target) میرود. دومی سیستم را در حالت دلخواه به کار می اندازد
آماده سازی سیستم عامل برای راه اندازی
هنگام ایجاد سیستم عامل، وظیفه همیشه بازیابی وضعیت سیستم در هنگام راه اندازی و ذخیره آن هنگام خاموش شدن است. State به معنی فایل های پیکربندی، تخلیه پایگاه داده، تنظیمات رابط و غیره است.
Systemd فرآیندها را در یک هدف به صورت موازی اجرا می کند. وابستگی هایی وجود دارد که به شما امکان می دهد دنباله راه اندازی اسکریپت ها را تعیین کنید.
چگونه در پروژه من کار می کند (
- سیستم شروع می شود
- سرویس settings_restore.service راه اندازی شد و وجود فایل settings.txt را در بخش داده بررسی می کند. اگر آنجا نباشد، یک فایل مرجع در جای خود قرار می گیرد. سپس تنظیمات سیستم بازیابی می شوند:
- رمز عبور مدیر
- نام میزبان،
- منطقه زمانی
- محل
- تعیین می کند که آیا از همه رسانه ها استفاده می شود. به طور پیش فرض، اندازه تصویر کوچک است - برای سهولت کپی و ضبط در رسانه. هنگام راه اندازی، بررسی می کند که آیا هنوز فضای بلااستفاده وجود دارد یا خیر. اگر وجود داشته باشد، دیسک دوباره پارتیشن بندی می شود.
- تولید ماشین شناسه از آدرس MAC. این برای بدست آوردن همان آدرس از طریق DHCP مهم است
- تنظیمات شبکه
- اندازه سیاههها را محدود می کند
- درایو خارجی برای کار آماده می شود (اگر گزینه مربوطه فعال باشد و درایو جدید باشد)
- postgresq را شروع کنید
- سرویس بازیابی شروع می شود. برای تهیه خود zabbix و پایگاه داده آن لازم است:
- بررسی می کند که آیا از قبل یک پایگاه داده zabbix وجود دارد یا خیر. در غیر این صورت، از تخلیه اولیه (شامل zabbix) ایجاد شده است.
- لیستی از مناطق زمانی ایجاد می شود (برای نمایش آنها در رابط وب لازم است)
- IP فعلی پیدا شد، در مشکل نمایش داده می شود (دعوت برای ورود به کنسول)
- دعوت تغییر می کند - عبارت Ready to work ظاهر می شود
- سیستم عامل آماده استفاده است
فایل های سرویس مهم هستند، آنها هستند که ترتیب راه اندازی آنها را تعیین می کنند
[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
همونطور که میبینید وابستگی ها رو نصب کردم که اول اسکریپم کار کنه و بعدش شبکه بالا بره و DBMS شروع بشه.
و سرویس دوم (تهیه زبیکس)
#!/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 شود. به طور جدی. علاوه بر این، دقت تا دقیقه نیست، بلکه تا ثانیه است (اگر لازم باشد چه میشود).
این تایمر یکنواخت بود که از شروع دستگاهی که من ایجاد کردم، زمان را می شمارد.
این به 2 فایل نیاز دارد
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
اینجا چیه:
- توضیحات تایمر
- اولین زمان شروع، شروع از بوت شدن سیستم
- دوره راه اندازی های بیشتر
- وابستگی به سرویس تایمر در واقع این رشته ای است که تایمر را می سازد
اسکریپت تعاملی هنگام خاموش شدن و هدف خاموش شدن شما
در توسعه دیگری، مجبور شدم نسخه پیچیده تری از خاموش کردن دستگاه را انجام دهم - از طریق هدف خودم، تا بتوانم اقدامات زیادی را انجام دهم. معمولاً توصیه می شود با گزینه RemainAfterExit یک سرویس oneshot ایجاد کنید، اما این مانع از ایجاد یک اسکریپت تعاملی می شود.
اما واقعیت این است که دستورات راه اندازی شده توسط گزینه ExecOnStop خارج از TTY اجرا می شوند! بررسی آن آسان است - دستور tty را چسبانده و خروجی آن را ذخیره کنید.
بنابراین، من خاموش شدن را از طریق هدف خود اجرا کردم. من ادعا نمی کنم که 100٪ درست است، اما کار می کند!
نحوه انجام آن (به طور کلی):
من یک هدف my_shutdown.target ایجاد کردم که به کسی بستگی نداشت:
my_shutdown.target
[Unit]
Description=my shutdown
AllowIsolate=yes
Wants=my_shutdown.service
هنگام رفتن به این هدف (از طریق systemctl isolate 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. شما نمی توانید هدف را با پارامترها فراخوانی کنید. فقط سرویس امکان پذیر است.
اما من از هدف استفاده میکنم تا انعطافپذیری در کار و ترتیب تضمین شده اعمال داشته باشم.
با این حال، جالب ترین چیز بعدا اتفاق افتاد. دستگاه باید خاموش/راه اندازی مجدد شود. و 2 گزینه وجود دارد:
- اسکریپت خود را جایگزین reboot، shutdown و سایر دستورات (آنها هنوز هم پیوند نمادین به systemctl هستند) داخل اسکریپت به my_shutdown.target بروید. و اسکریپت های داخل هدف، سپس systemctl را مستقیماً فراخوانی می کنند، به عنوان مثال، systemctl reboot
- یک گزینه ساده تر، اما من آن را دوست ندارم. در همه اینترفیس ها، shutdown/reboot/other را فراخوانی نکنید، بلکه مستقیماً سیستم هدف را فراخوانی کنیدctl 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