چرخه عمر یک سرویس کاربری با systemd
در این درس قرارداد اجرا را به unit تبدیل میکنیم تا وضعیت، شکست و تلاش دوباره قابل مشاهده باشد. پیشنیاز، Ubuntu آزمایشی با systemd و نشست کاربر عادی است؛ فرمانهای مدیریتی با --user اجرا میشوند و sudo لازم نیست. اگر فرمان اول به bus کاربر وصل نشد، ادامه ندهید؛ از نشست واقعی روی VM دارای systemd استفاده کنید. تألیف: تحریریه درسآوند.
systemctl --user show-environment >/dev/null
systemctl --versionUnit یک توصیف اعلانی از نحوه اجرا و سیاست نظارت است، نه رونوشت تاریخچه فرمانهای ترمینال. Type=exec اجازه میدهد خطای آغاز اجرای باینری زودتر گزارش شود؛ اما active شدن آن تضمین آماده بودن منطق برنامه نیست. محیط سرویس نیز الزاماً متغیرها و مسیر کاری پوسته تعاملی شما را ندارد. مسیر کاری و مفسر را صریح مینویسیم. برنامه فقط پیام مینویسد و با یک نشانگر عمداً شکست میخورد.
labdir=$(mktemp -d "$HOME/darsavand-linux2.XXXXXXXX")
unit="darsavand-$(basename "$labdir").service"
printf 'project=%s\nunit=%s\n' "$labdir" "$unit"پوشه و نام unit یکتا هستند تا فایل موجودی بازنویسی نشود. نام چاپشده را نگه دارید و مراحل این درس و درس لاگ را در همین ترمینال ادامه دهید؛ labdir و unit متغیر همان پوستهاند. فرمان بعد فایل worker.sh را در پوشه پروژه میسازد. اجرای مستقیم با مفسر انجام میشود؛ بنابراین نیازی به تغییر مجوز اجرای فایل نیست. فایل fail را فعلاً ایجاد نکنید تا اجرای سالم دیده شود.
cat > "$labdir/worker.sh" <<'SH'
#!/bin/sh
printf '<6>worker started\n'
while :; do
if [ -e ./fail ]; then
printf '<3>planned failure: fail file exists\n' >&2
exit 7
fi
printf '<6>heartbeat\n'
sleep 5
done
SHهر heartbeat نشان میدهد حلقه هنوز اجرا میشود؛ این جای بررسی سلامت واقعی یک سامانه را نمیگیرد. کد خروج ۷ در این برنامه قرارداد شکست آزمایشی است. پیشوند <6> سطح اطلاعرسانی و <3> سطح خطا را برای journal مشخص میکند؛ نوشتن روی stderr بهتنهایی تضمین سطح err نیست. فایل unit زیر با مقادیر همین پروژه ساخته میشود. در فایل unit، ExecStart پوسته تعاملی نیست و نشانههایی مثل pipe خودکار تفسیر نمیشوند.
cat > "$labdir/$unit" <<EOF
[Unit]
Description=Darsavand user service lab
StartLimitIntervalSec=30
StartLimitBurst=3
[Service]
Type=exec
WorkingDirectory=$labdir
ExecStart=/bin/sh "$labdir/worker.sh"
Restart=on-failure
RestartSec=2
StandardOutput=journal
StandardError=journal
SyslogLevelPrefix=yes
[Install]
WantedBy=default.target
EOFRestart=on-failure برای شکست تلاش دوباره میکند؛ stop عمدی سرویس این سیاست را فعال نمیکند. فاصله دوثانیهای از حلقه بسیار سریع جلوگیری میکند. محدودیت سه آغاز در سی ثانیه برای مهار خطای تکرارشونده است؛ این شمارنده شروع دستی را هم دربرمیگیرد. اینها درمان علت خطا نیستند. بخش Install فقط رابطه پیشنهادی برای enable را تعریف میکند و وجودش بهخودیخود سرویس را اجرا یا فعالسازی دائمی نمیکند. اکنون unit را پیوند میدهیم و اجرای موقت را آغاز میکنیم.
systemd-analyze --user verify "$labdir/$unit"
systemctl --user link "$labdir/$unit"
systemctl --user daemon-reload
systemctl --user start "$unit"
systemctl --user status "$unit" --no-pagerدر خروجی، Loaded بارگذاری فایل و Active معمولاً active (running) را نشان میدهد. verify بررسی ایستای تعریف است و موفقیتش تضمین اجرای درست نیست. پس از ویرایش خود unit، daemon-reload لازم است؛ برای اعمال رفتار جدید روی فرایند جاری معمولاً restart نیز لازم میشود. reload برای بازخوانی تنظیمات داخلی برنامه است و این سرویس آن را پیاده نکرده است. enable از start مستقل است؛ این آزمایشگاه سرویس را enable نمیکند و ماندگاری پس از خروج کاربر یا بوت را وعده نمیدهد.
تمرین: فایل fail را بسازید و پیشبینی کنید آیا سرویس تا ابد هر دو ثانیه برمیگردد. پیش از اجرای فرمانها حدس خود را بنویسید. دوازده ثانیه برای مشاهده در نظر گرفته شده؛ زمانبندی دقیق به میزبان وابسته است. اگر هنوز در حالت auto-restart بود، چند لحظه بعد وضعیت را دوباره بخوانید. این آزمایش فقط فایل نشانگر داخل پروژه و سرویس یکتای خودتان را تغییر میدهد.
touch "$labdir/fail"
sleep 12
systemctl --user show "$unit" -p ActiveState -p SubState -p Result -p NRestartsپاسخ: وجود نشانگر، هر اجرای تازه را هم با خطا خارج میکند؛ سیاست محدودیت آغاز سرانجام ادامه تلاش را متوقف میکند. معمولاً ActiveState=failed و Result=start-limit-hit دیده میشود، اما مقدار لحظهای و شمار تلاشها را باید از همان ماشین خواند. حذف نشانگر علت آزمایشی را رفع میکند؛ پاککردن وضعیت failed علت را رفع نمیکند. پروژه را برای بررسی شواهد در درس بعد نگه دارید. اگر ادامه نمیدهید، بلوک پاکسازی زیر فقط فایلهای همین پروژه را حذف میکند؛ پیش از اجرا درست بودن متغیرها و مسیر چاپشده را بررسی کنید.
systemctl --user disable --now "$unit"
rm -- "$labdir/worker.sh" "$labdir/$unit"
rm -f -- "$labdir/fail"
rmdir -- "$labdir"
systemctl --user daemon-reload
unset labdir unitمنابع رسمی انگلیسی:
systemd service: https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
systemd unit and start limits: https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html
systemctl lifecycle: https://www.freedesktop.org/software/systemd/man/latest/systemctl.html
Execution environment: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html
متن درسهای عمومی را بدون ورود بخوانید.