15%

Спести 15% на всички хостинг услуги

Тествай уменията си и получи Отстъпка за всеки хостинг план

Използвайте код:

Skills
За начало
10.11.2023

Как да активирате автоматично зареждане на скриптове в Ubuntu: Три метода, готови за производствена среда

Активирането на автоматично зареждане на скриптове в Ubuntu означава конфигуриране на операционната система да изпълнява автоматично един или повече shell скриптове или услуги при стартиране на системата, без никаква ръчна намеса. Това се постига чрез три основни механизма: наследената директория /etc/init.d/ базирана на SysVinit, съвместимостният слой /etc/rc.local и съвременната рамка за сервизни единици systemd — последната е авторитетният, препоръчан подход за всички версии на Ubuntu от 15.04 нататък.

За системни администратори, изпълняващи натоварвания в среда за VPS Хостинг, автоматизацията при стартиране не е удобство — тя е изискване за надеждност. Неправилно конфигуриран или липсващ запис за автоматично стартиране означава, че критични демони, агенти за мониторинг, скриптове за архивиране или персонализирани мрежови конфигурации тихо не успяват да се стартират след рестартиране, причинявайки прекъсвания на услугата, които са трудни за диагностициране след факта.

Защо автоматизацията на стартиращи скриптове е важна за Ubuntu сървъри

Всеки производствен Ubuntu сървър натрупва оперативни скриптове с течение на времето: рутини за предварително загряване на бази данни, тригери за ротация на логове, инициализатори на VPN тунели, зареждачи на правила за защитна стена и проверки на работоспособността на приложения. Без структуриран механизъм за автоматично зареждане тези скриптове зависят изцяло от ръчно изпълнение — една пропусната стъпка след актуализация на ядрото или спешно рестартиране може да доведе до престой.

Екосистемата за автоматизация при стартиране на Ubuntu се е развила значително:

  • SysVinit (преди Ubuntu 15.04): Последователен, бавен, базиран на скриптове. Всяка услуга блокираше следващата.
  • Upstart (Ubuntu 6.10–15.04): Управляван от събития, по-бърз, но вече остарял.
  • systemd (Ubuntu 15.04+): Паралелно активиране на услуги, графики на зависимости, активиране чрез сокети, контрол на ресурсите базиран на cgroup и структурирано логване чрез journald.

Разбирането на това с кой слой работите — и защо — ви предпазва от внедряване на работещо решение в тестова среда, което тихо се проваля в производство.

Метод 1: Използване на директорията /etc/init.d/ (SysVinit / LSB скриптове)

Как работи

Директорията /etc/init.d/ е традиционното място за Linux Standard Base (LSB) init скриптове. Всеки скрипт в тази директория е shell скрипт, който отговаря на стандартизирани команди: start, stop, restart, status и по избор reload. Помощната програма update-rc.d създава символни връзки в директориите за нива на изпълнение /etc/rcN.d/, определяйки кога и в какъв ред скриптът се изпълнява по време на последователностите за стартиране и изключване.

На съвременни Ubuntu системи, работещи с systemd, тези скриптове все още се поддържат чрез слой за съвместимост наречен systemd-sysv-generator, който автоматично преобразува LSB init скриптове в временни systemd единици. Това означава, че вашите скриптове /etc/init.d/ все още ще работят, но са обвити от systemd, а не изпълнявани директно от SysVinit.

Поетапно изпълнение

Стъпка 1: Създайте вашия скрипт

Напишете вашия скрипт и се уверете, че следва конвенцията за LSB заглавие. Минимален, безопасен за производство пример:

#!/bin/bash
### BEGIN INIT INFO
# Provides:          examplescript
# Required-Start:    $remote_fs $syslog $network
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Example autoload script
# Description:       Runs a custom initialization task at boot
### END INIT INFO

case "$1" in
  start)
    echo "Starting examplescript..."
    /usr/local/bin/examplescript.sh &
    ;;
  stop)
    echo "Stopping examplescript..."
    pkill -f examplescript.sh
    ;;
  restart)
    $0 stop
    $0 start
    ;;
  status)
    pgrep -f examplescript.sh > /dev/null && echo "Running" || echo "Stopped"
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|status}"
    exit 1
    ;;
esac
exit 0

Стъпка 2: Поставете скрипта в /etc/init.d/

sudo cp examplescript /etc/init.d/examplescript

Стъпка 3: Направете го изпълним

sudo chmod +x /etc/init.d/examplescript

Стъпка 4: Регистрирайте го в системата за нива на изпълнение

sudo update-rc.d examplescript defaults

Аргументът defaults регистрира скрипта да стартира на нива на изпълнение 2, 3, 4 и 5, и да спира на нива 0, 1 и 6 — стандартното поведение за повечето сървърни демони.

Стъпка 5: Проверете регистрацията

ls -la /etc/rc2.d/ | grep examplescript

Трябва да видите символна връзка като S01examplescript, сочеща обратно към /etc/init.d/examplescript.

Критичен проблем

Най-честата грешка при този метод е пропускането на блока с LSB заглавие. Без него update-rc.d не може да определи реда на зависимостите и systemd-sysv-generator може да присвои неправилен ред на изпълнение спрямо наличността на мрежата или монтирането на файловата система. Винаги дефинирайте зависимостите Required-Start изрично.

За да премахнете скрипта от автоматично стартиране, без да го изтривате:

sudo update-rc.d examplescript disable

За пълното му премахване:

sudo update-rc.d examplescript remove

Метод 2: Използване на /etc/rc.local (слой за съвместимост)

Как работи

/etc/rc.local е наследен механизъм, който изпълнява shell скрипт веднъж, след като всички стандартни услуги на многопотребителско ниво са стартирали. Това е най-простият възможен метод за автоматично стартиране — без управление на услуги, без декларации за зависимости, без логика за рестартиране. На Ubuntu 18.04 и по-нови версии, поддръжката на rc.local се осигурява от systemd единицата rc-local.service, която е деактивирана по подразбиране и трябва да бъде изрично активирана.

Кога да го използвате

Използвайте /etc/rc.local само за:

  • Еднократни инициализационни команди, които не трябва да се управляват като услуги
  • Бързо прототипиране или тестване преди формализиране на systemd единица
  • Прости експортирания на променливи на средата или настройки на параметри на ядрото

Не използвайте /etc/rc.local за дълготрайни демони. Тъй като работи по блокиращ, последователен начин без надзор на процесите, заседнала команда в rc.local ще забави или предотврати завършването на последователността за стартиране.

Поетапно изпълнение

Стъпка 1: Проверете дали /etc/rc.local съществува

ls -la /etc/rc.local

Ако не съществува, създайте го:

sudo bash -c 'cat > /etc/rc.local << EOF
#!/bin/bash
exit 0
EOF'
sudo chmod +x /etc/rc.local

Стъпка 2: Активирайте systemd единицата rc-local (Ubuntu 18.04+)

sudo systemctl enable rc-local
sudo systemctl start rc-local

Стъпка 3: Добавете вашата команда преди exit 0

sudo nano /etc/rc.local

Вмъкнете вашата команда над реда exit 0:

#!/bin/bash
/usr/local/bin/examplescript.sh >> /var/log/examplescript.log 2>&1 &
exit 0

& в края е от съществено значение за всяка дълготрайна команда — тя разклонява процеса на заден план, така че rc.local да не блокира.

Стъпка 4: Проверете изпълнението

sudo systemctl status rc-local

Критичен проблем

На Ubuntu 20.04 и 22.04, rc-local.service има твърдо кодиран таймаут от 30 секунди. Ако вашият скрипт отнема повече от 30 секунди за завършване, systemd ще маркира услугата като неуспешна и последващите команди в rc.local няма да се изпълнят. Пренасочвайте изхода и поставяйте дълготрайните процеси изрично на заден план.

Метод 3: Използване на systemd сервизни единици (препоръчано)

Защо systemd е правилният подход за производство

systemd не е просто заместител на SysVinit — той е пълен мениджър на системата и сесиите, който осигурява разрешаване на зависимости, паралелно стартиране, активиране чрез сокети и D-Bus, стартиране на услуги при поискване, надзор на процесите с автоматично рестартиране, изолация на ресурсите базирана на cgroup и структурирано агрегиране на логове чрез journald. За всяко натоварване, работещо на Dedicated сървър или производствен VPS, systemd единиците са единственият подходящ механизъм за управление на автоматично заредени скриптове.

Анатомия на systemd файл с единица

Файлът с единица .service е разделен на три задължителни секции:

  • [Unit]: Метаданни, описание за хора и декларации за зависимости (After=, Requires=, Wants=).
  • [Service]: Параметри за изпълнение — двоичният файл или скриптът за изпълнение, типът на услугата, политиката за рестартиране, променливите на средата и опциите за защитна изолация.
  • [Install]: Определя коя systemd цел активира тази единица (WantedBy=multi-user.target е стандартът за сървърни демони).

Поетапно изпълнение

Стъпка 1: Подгответе вашия скрипт

Уверете се, че вашият скрипт е изпълним и се намира на стабилен път:

sudo cp examplescript.sh /usr/local/bin/examplescript.sh
sudo chmod +x /usr/local/bin/examplescript.sh

Стъпка 2: Създайте файла с единица

sudo nano /etc/systemd/system/examplescript.service

Файл с единица от производствен клас със защитно втвърдяване:

[Unit]
Description=Example Autoload Script
Documentation=https://your-internal-wiki/examplescript
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/examplescript.sh
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=examplescript
User=nobody
Group=nogroup
NoNewPrivileges=true
ProtectSystem=strict
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Стъпка 3: Презаредете systemd демона

След създаване или промяна на файл с единица трябва да презаредите индекса на конфигурацията на демона:

sudo systemctl daemon-reload

Стъпка 4: Активирайте услугата за автоматично стартиране

sudo systemctl enable examplescript.service

Това създава символна връзка в /etc/systemd/system/multi-user.target.wants/, сочеща към вашия файл с единица.

Стъпка 5: Стартирайте услугата незабавно

sudo systemctl start examplescript.service

Стъпка 6: Проверете статуса и логовете

sudo systemctl status examplescript.service
sudo journalctl -u examplescript.service -f

Разбиране на типовете systemd услуги

Директивата Type= в секцията [Service] е един от най-неразбраните параметри. Изборът на грешен тип кара systemd да докладва неправилно готовността на услугата, което води до грешки в зависимостите.

ТипПоведениеСлучай на употреба
simpleПроцесът, стартиран от ExecStart, е основният процес. Systemd го счита за готов незабавно.Скриптове и прости демони, които не се разклоняват
forkingПроцесът се разклонява и родителят излиза. Systemd проследява дъщерния процес чрез PID файл.Традиционни Unix демони (напр. Apache с PidFile)
oneshotПроцесът се изпълнява до завършване и излиза. Systemd изчаква преди да стартира зависими единици.Еднократни инициализационни задачи, скриптове за настройка
notifyПроцесът сигнализира готовност чрез sd_notify().Демони с нативна интеграция с systemd
idleИзпълнението се забавя до изпращане на всички активни задачи.Фонови задачи с нисък приоритет

За скрипт, който се изпълнява веднъж при стартиране и излиза, използвайте Type=oneshot с RemainAfterExit=yes, за да поддържате единицата в „активно” състояние след завършване на скрипта.

Разширено: Наредба на зависимостите с After= и Wants=

Честа производствена грешка възниква, когато скрипт, изискващ мрежова свързаност, стартира преди мрежовият стек да е напълно инициализиран. Правилната верига от зависимости за скриптове, зависещи от мрежата, е:

After=network-online.target
Wants=network-online.target

Това се различава от After=network.target, което само гарантира, че мрежовите интерфейси са конфигурирани — не че са действително онлайн и достъпни. Зависимостта network-online.target изисква systemd-networkd-wait-online.service или еквивалент да потвърди свързаността.

Сравнение: И трите метода с един поглед

Функция/etc/init.d//etc/rc.localsystemd единица
Препоръчано за производствоНеНеДа
Поддръжка на паралелно стартиранеНеНеДа
Надзор на процесите / автоматично рестартиранеНеНеДа
Управление на зависимоститеОграничено (LSB заглавия)НямаПълно
Структурирано логванеНеНеДа (journald)
Защитна изолацияНеНеДа
СложностНискаМного нискаСредна
Поддържано на Ubuntu 22.04+Чрез слой за съвместимостЧрез rc-local.serviceНативно
Подходящо за дълготрайни демониЧастичноНеДа
Подходящо за еднократни инициализационни задачиДаДаДа (oneshot)

Чести грешки и как да ги избегнете

Изпълнение на скриптове като root без необходимост. Директивите User= и Group= в systemd файловете с единици ви позволяват да намалите привилегиите. Скрипт, който трябва само да записва в /var/log/myapp/, не се нуждае от root — създайте специален системен потребител и задайте собствеността на директорията съответно.

Непренасочване на изхода в rc.local. Без пренасочване на изхода, всеки echo или изход за грешки от командите rc.local отива на системната конзола и се губи. Винаги добавяйте >> /var/log/yourscript.log 2>&1.

Непоследователно използване на абсолютни пътища. systemd услугите работят в минимална среда без PATH на потребителя. Винаги използвайте абсолютни пътища за всеки двоичен файл, посочен в ExecStart, включително интерпретатори като /usr/bin/python3 или /bin/bash.

Забравяне на daemon-reload след редактиране на файлове с единици. systemd кешира съдържанието на файловете с единици. Ако редактирате файл .service и не изпълните sudo systemctl daemon-reload, systemd ще продължи да използва старата конфигурация.

Поставяне на файлове с единици в /lib/systemd/system/ за персонализирани скриптове. Директорията /lib/systemd/system/ се управлява от мениджъра на пакети. Персонализираните файлове с единици принадлежат в /etc/systemd/system/, което има приоритет и оцелява при надстройки на пакети.

Практическа матрица за решения: Кой метод да използвате

Използвайте тази рамка, за да изберете подходящия метод за вашия конкретен сценарий:

  • Дълготраен демон, който трябва да се рестартира при грешка — systemd единица с Restart=on-failure
  • Еднократен скрипт за настройка, който трябва да завърши преди стартирането на други услуги — systemd единица с Type=oneshot и зависимости Before=
  • Скрипт, изискващ мрежата да е напълно онлайн — systemd единица с After=network-online.target
  • Бърза еднолинейна команда за тестване или прототипиране/etc/rc.local (временно)
  • Наследено приложение, доставено с LSB init скрипт/etc/init.d/ с update-rc.d
  • Всичко, работещо в производство — systemd, винаги

За администратори, управляващи множество Ubuntu сървъри, помислете за съчетаване на управлението на systemd единици с инструменти за управление на конфигурации като Ansible, който може да внедрява и активира файлове .service идемпотентно в целия ви парк. Ако имате нужда от управлявана среда с пълен root достъп за прилагане на тези конфигурации, VPS Хостинг с VPS контролен панел осигурява гъвкавостта да управлявате systemd услуги директно без ограничения.

За екипи, изпълняващи ресурсоемки натоварвания, изискващи стартиращи скриптове за инициализиране на GPU драйвери, CUDA среди или ML сървъри за извод, средите за GPU Хостинг се възползват особено от веригите на зависимости After= на systemd, гарантирайки, че драйверите са напълно заредени преди услугите на приложенията да се опитат да се свържат с хардуерните ресурси.

Ако вашите автоматично заредени скриптове взаимодействат с конфигурации на уеб сървъри или рутини за инициализиране на бази данни, свързани с среда на контролен панел, инсталациите на VPS с cPanel изискват специално внимание — cPanel управлява собствен слой за надзор на услуги и персонализираните systemd единици трябва да бъдат дефинирани, за да се избегнат конфликти с куките за управление на услуги на cPanel.

Технически контролен списък с ключови изводи

Преди внедряване на стартиращ скрипт на Ubuntu сървър, проверете следното:

  • Местоположение на файла с единица: Персонализираните скриптове отиват в /etc/systemd/system/, не в /lib/systemd/system/
  • Бит за изпълнимост: Потвърдете с ls -la /path/to/script.sh — битът x трябва да е зададен
  • Абсолютни пътища: Всеки двоичен файл в ExecStart използва пълен път; без разчитане на $PATH
  • Декларации за зависимости: After=network-online.target за всеки скрипт, зависещ от мрежата
  • Тип на услугата: Type=simple за постоянни демони, Type=oneshot за скриптове тип изпълни-и-излез
  • Минимизиране на привилегиите: User=, Group=, NoNewPrivileges=true, ProtectSystem=strict
  • Конфигурирано логване: StandardOutput=journal и StandardError=journal за интеграция с journald
  • Изпълнен daemon-reload: Винаги изпълнявайте sudo systemctl daemon-reload след създаване или редактиране на файлове с единици
  • Enable срещу start: enable създава символната връзка за автоматично стартиране; start го стартира незабавно — и двете са необходими
  • Тествано с journalctl: Потвърдете успешното изпълнение с sudo journalctl -u yourservice.service --since "5 minutes ago"

ЧЗВ

Каква е разликата между systemctl enable и systemctl start?

systemctl enable създава символна връзка, която кара услугата да стартира автоматично при следващото зареждане. systemctl start стартира услугата незабавно в текущата сесия. Обикновено се нуждаете от двете команди при настройване на нова услуга за първи път.

Защо моята systemd услуга се проваля с „executable not found”, въпреки че скриптът съществува?

Това почти винаги означава, че пътят ExecStart е неправилен или скриптът няма бит за изпълнимост. Проверете с which yourscript и ls -la /path/to/script. Също потвърдете, че първият ред на вашия скрипт е валиден shebang (#!/bin/bash или #!/usr/bin/env python3), тъй като systemd не извиква shell по подразбиране за ExecStart.

Мога ли да изпълня скрипт при стартиране само веднъж, а не при всяко зареждане?

Използвайте Type=oneshot с директива ConditionPathExists=!/var/run/myscript.done в секцията [Unit]. Скриптът създава sentinel файла при първото изпълнение; следващите зареждания пропускат изпълнението, защото условието не е изпълнено.

Поддържа ли се /etc/rc.local на Ubuntu 22.04?

Да, но е деактивиран по подразбиране. Трябва ръчно да активирате единицата rc-local.service с sudo systemctl enable rc-local и да се уверите, че файлът съществува и е изпълним. Поддържа се като мярка за съвместимост, а не като препоръчана практика.

Как да проверя защо стартиращ скрипт не е успял да се изпълни?

Изпълнете sudo journalctl -u yourservice.service -b, за да видите всички записи в лога за тази единица от последното зареждане. При грешки в rc.local, проверете sudo systemctl status rc-local.service и прегледайте /var/log/syslog за записи с времеви печат по време на последователността за зареждане.

15%

Спести 15% на всички хостинг услуги

Тествай уменията си и получи Отстъпка за всеки хостинг план

Използвайте код:

Skills
За начало