מחולל שירות systemd

ממלאים איך התוכנה שלכם רצה ומקבלים קובץ ‎.service ש-systemd קורא בדיוק כפי שנכתב, עם פקודות ההתקנה והסבר לכל שדה. הכול נכתב בדפדפן שלכם.

הקובץ יהיה ‎<name>.service ב-‎/etc/systemd/system.
נתיב מוחלט והארגומנטים שלו. ארגומנט עם רווחים שמים במירכאות; לא רץ shell, ולכן pipe ו-&& צריכים ‎/bin/sh -c '…'.
התוכנה נשארת בחזית; systemd מחשיב אותה כפעילה מיד.
ריק: רץ כ-root. משתמש ייעודי בטוח יותר.
נתיב מוחלט שבו התוכנה מתחילה. ריק: תיקיית הבית של המשתמש, או / ל-root.
שורה אחת לכל NAME=value. הערכים נכתבים כמו שהם: $ ו-% לא מורחבים.
קובץ של שורות NAME=value שנקרא בכל הפעלה, למשל סודות שנשארים מחוץ ל-unit.
units, מופרדים ברווח, שצריכים לעלות קודם. ‏network-online.target נכנס גם ל-Wants, כך שהרשת למעלה.
מופעל מחדש אחרי קריסה, יציאה עם קוד שאינו 0 או timeout, לא אחרי יציאה תקינה.
‏NoNewPrivileges, ‏PrivateTmp, ‏ProtectSystem=full (‏‎/usr, ‏‎/boot ו-‎/etc לקריאה בלבד) והגנה על הגדרות הקרנל. כבו אותו אם התוכנה כותבת תחת ‎/etc או ‎/usr.
מוסיף [Install] WantedBy=multi-user.target, כך ש-enable מפעיל אותו בכל אתחול.

ה-unit שלכם

myapp.service
# myapp.service: My app
# Generated by @anaroq/linux 1.0.0 (ANAROQ).
[Unit]
Description=My app
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/myapp --port 8080
Restart=on-failure
RestartSec=5
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictSUIDSGID=yes

[Install]
WantedBy=multi-user.target

העברה לסוכן

משימה ב-Markdown לסוכן קוד: הקבצים, הממצאים, המגבלות וגבולות בטיחות קבועים. ערכים שנראים כמו סודות ממוסכים. היא נבנית בעמוד הזה ולא נשלחת לשום מקום.

איך עובדת ההעברה לסוכן

התקנה והפעלה

מריצים את אלה בשרת, בתיקייה שבה שמרתם את הקובץ. ‏systemd-analyze verify בודק אותו לפני ש-systemd טוען אותו.

install-commands.txt
sudo install -m 0644 myapp.service /etc/systemd/system/myapp.service
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
systemctl status myapp.service
journalctl -u myapp.service -f

רץ לפי לוח זמנים? המירו שורת cron ל-timer של systemd

מה הכלי עושה

הכלי כותב unit של שירות systemd לתוכנה שהשרת צריך להשאיר רצה: אפליקציית web, ‏worker, סוכן או מנהרה. בוחרים את הפקודה, החשבון, התיקייה, הסביבה, מתי להפעיל מחדש ואחרי מה לעלות, והעמוד מציג את ה-unit ואת הפקודות שמתקינות אותו.

איך זה עובד

  1. ה-unit נכתב בדפדפן שלכם על ידי ‎@anaroq/linux, המנוע של שאר כלי ה-Linux שלנו. כל ערך נכתב כך ש-systemd קורא אותו כמו שהוא: % מוכפל, $ בפקודה מוכפל, וארגומנט עם רווחים או מירכאות מוקף במירכאות.
  2. שדה שהיה שובר את הקובץ, כמו ירידת שורה, פקודה בלי נתיב מוחלט או שם unit עם רווח, נדחה ליד השדה במקום להיכתב.
  3. אותם קבצי unit עוברים systemd-analyze verify בבדיקות שלנו, ב-Debian 12, ‏Ubuntu 22.04 ו-Ubuntu 24.04.

מה כל שורה עושה

Description=
השם ש-systemctl status והיומן מציגים.
Wants= ו-After=
‏After= קובע את סדר ההפעלה; ‏Wants= גם מושך את ה-unit. שניהם על network-online.target מחכים לרשת.
Type=
איך systemd יודע שהתוכנה עלתה: simple ו-exec מיד, ‏oneshot כשהיא יוצאת, ‏notify כשהיא מודיעה.
User= ו-Group=
החשבון שהתוכנה רצה תחתיו. בלעדיהם היא רצה כ-root.
WorkingDirectory=
התיקייה שבה התוכנה מתחילה.
Environment=
משתנה אחד בכל שורה, במירכאות כשיש בערך רווחים. ‏systemd לא מרחיב בו $ או ~.
EnvironmentFile=
קובץ משתנים שנקרא בכל הפעלה; הערכים שלו גוברים על Environment=. עם -, קובץ חסר מדולג.
ExecStart=
הפקודה, עם נתיב מוחלט. ‏systemd מפצל את המילים בעצמו ולא מריץ shell.
Restart= ו-RestartSec=
מתי systemd מפעיל את התוכנה שוב, וכמה זמן הוא מחכה לפני כן.
NoNewPrivileges= … RestrictSUIDSGID=
ה-sandbox הבסיסי: בלי השגת הרשאות, ‏‎/tmp פרטי, תיקיות מערכת והגדרות קרנל לקריאה בלבד, בלי קובצי setuid.
WantedBy=multi-user.target
סעיף [Install]: ‏systemctl enable מקשר את ה-unit לשם, והוא עולה בכל אתחול.

דוגמה

אפליקציית Node.js שרצה תחת משתמש משלה מ-‎/opt/myapp, עם שני משתנים ב-unit והסודות שלה בקובץ משתנים אופציונלי:

myapp.service
# myapp.service: My Node.js app
# Generated by @anaroq/linux 1.0.0 (ANAROQ).
[Unit]
Description=My Node.js app
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
Environment=NODE_ENV=production
Environment=PORT=3000
EnvironmentFile=-/etc/myapp/myapp.env
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictSUIDSGID=yes

[Install]
WantedBy=multi-user.target

הפקודות שמתקינות ומפעילות אותו

install-commands.txt
sudo install -m 0644 myapp.service /etc/systemd/system/myapp.service
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
systemctl status myapp.service
journalctl -u myapp.service -f

מגבלות

  • הכלי כותב units של המערכת ב-‎/etc/systemd/system. ‏units של משתמש (systemctl --user) ותבניות ([email protected]) לא נכללים.
  • ה-sandbox הוא בסיס שמרני. ‏systemd-analyze security myapp.service נותן ציון ל-unit ומפרט מה עוד אפשר להגביל.
  • ‏systemd-analyze verify בודק את הקובץ, לא את התוכנה: הוא לא יודע אם הפקודה עובדת או אם המשתמש קיים.
  • ‏socket activation, מגבלות משאבים ו-timeouts נשארים בברירות המחדל של systemd.

רץ לפי לוח זמנים? המירו שורת cron ל-timer של systemd

מקורות

  1. systemd.service(5)
  2. systemd.exec(5)
  3. systemd.unit(5)
  4. systemd.timer(5)
  5. systemd-analyze(1)

עודכן

הצעד הבא

ממיר cron ל-timer של systemd

כלי ציבורי חינמי של אנרוק, חברה שבונה תשתיות מחשוב. מה אנרוק בונה