15%

Zaoszczędź 15% na wszystkich usługach hostingowych

Sprawdź swoje umiejętności i zdobądź Rabat na dowolny plan hostingowy

Użyj kodu:

Skills
Rozpocznij
10.11.2023

Jak włączyć automatyczne ładowanie skryptów w Ubuntu: trzy metody gotowe do produkcji

Włączenie automatycznego ładowania skryptów w Ubuntu oznacza skonfigurowanie systemu operacyjnego do automatycznego wykonywania jednego lub więcej skryptów powłoki lub usług podczas uruchamiania systemu, bez żadnej ręcznej interwencji. Osiąga się to za pomocą trzech podstawowych mechanizmów: opartego na starszym SysVinit katalogu /etc/init.d/, podkładki kompatybilności /etc/rc.local oraz nowoczesnego frameworka jednostek usług systemd — przy czym ten ostatni jest autorytatywnym, zalecanym podejściem we wszystkich wersjach Ubuntu od 15.04 wzwyż.

Dla administratorów systemów uruchamiających obciążenia w środowisku VPS Hosting, automatyzacja uruchamiania nie jest udogodnieniem — jest wymogiem niezawodności. Błędnie skonfigurowany lub nieobecny wpis autostartu oznacza, że krytyczne demony, agenty monitorowania, skrypty kopii zapasowych lub niestandardowe konfiguracje sieciowe po cichu nie uruchamiają się po restarcie, powodując przerwy w działaniu usług, które są trudne do zdiagnozowania po fakcie.

Dlaczego automatyzacja skryptów startowych ma znaczenie na serwerach Ubuntu

Każdy produkcyjny serwer Ubuntu gromadzi z czasem skrypty operacyjne: procedury wstępnego rozgrzewania bazy danych, wyzwalacze rotacji logów, inicjalizatory tuneli VPN, programy ładujące reguły zapory sieciowej oraz kontrole stanu aplikacji. Bez ustrukturyzowanego mechanizmu automatycznego ładowania, skrypty te są całkowicie zależne od ręcznego wykonania — jeden pominięty krok po aktualizacji jądra lub awaryjnym restarcie może kaskadowo prowadzić do przestoju.

Ekosystem automatyzacji uruchamiania Ubuntu znacznie ewoluował:

  • SysVinit (przed Ubuntu 15.04): Sekwencyjny, wolny, oparty na skryptach. Każda usługa blokowała następną.
  • Upstart (Ubuntu 6.10–15.04): Sterowany zdarzeniami, szybszy, ale już przestarzały.
  • systemd (Ubuntu 15.04+): Równoległe aktywowanie usług, grafy zależności, aktywacja gniazd, kontrola zasobów oparta na cgroup oraz strukturalne logowanie przez journald.

Zrozumienie, z którą warstwą pracujesz — i dlaczego — zapobiega wdrożeniu działającego rozwiązania w środowisku testowym, które po cichu psuje się w produkcji.

Metoda 1: Używanie katalogu /etc/init.d/ (SysVinit / skrypty LSB)

Jak to działa

Katalog /etc/init.d/ jest tradycyjnym miejscem dla skryptów init Linux Standard Base (LSB). Każdy skrypt w tym katalogu jest skryptem powłoki, który odpowiada na standardowe polecenia: start, stop, restart, status i opcjonalnie reload. Narzędzie update-rc.d tworzy dowiązania symboliczne w katalogach poziomów uruchamiania /etc/rcN.d/, określając kiedy i w jakiej kolejności skrypt jest wykonywany podczas sekwencji uruchamiania i wyłączania systemu.

W nowoczesnych systemach Ubuntu działających na systemd, skrypty te są nadal obsługiwane przez warstwę kompatybilności zwaną systemd-sysv-generator, która automatycznie konwertuje skrypty init LSB na przejściowe jednostki systemd. Oznacza to, że Twoje skrypty /etc/init.d/ nadal będą działać, ale są opakowane przez systemd zamiast być wykonywane bezpośrednio przez SysVinit.

Implementacja krok po kroku

Krok 1: Utwórz swój skrypt

Napisz swój skrypt i upewnij się, że przestrzega konwencji nagłówka LSB. Minimalny, bezpieczny dla produkcji przykład:

#!/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

Krok 2: Umieść skrypt w /etc/init.d/

sudo cp examplescript /etc/init.d/examplescript

Krok 3: Nadaj mu uprawnienia do wykonywania

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

Krok 4: Zarejestruj go w systemie poziomów uruchamiania

sudo update-rc.d examplescript defaults

Argument defaults rejestruje skrypt do uruchamiania na poziomach 2, 3, 4 i 5 oraz zatrzymywania na poziomach 0, 1 i 6 — standardowe zachowanie dla większości demonów serwerowych.

Krok 5: Zweryfikuj rejestrację

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

Powinieneś zobaczyć dowiązanie symboliczne takie jak S01examplescript wskazujące z powrotem na /etc/init.d/examplescript.

Krytyczna pułapka

Najczęstszym błędem przy tej metodzie jest pominięcie bloku nagłówka LSB. Bez niego update-rc.d nie może określić kolejności zależności, a systemd-sysv-generator może przypisać nieprawidłową kolejność wykonania względem dostępności sieci lub montowania systemu plików. Zawsze definiuj zależności Required-Start explicite.

Aby usunąć skrypt z autostartu bez jego usuwania:

sudo update-rc.d examplescript disable

Aby całkowicie go usunąć:

sudo update-rc.d examplescript remove

Metoda 2: Używanie /etc/rc.local (podkładka kompatybilności)

Jak to działa

/etc/rc.local to starszy mechanizm, który wykonuje skrypt powłoki jednorazowo, po uruchomieniu wszystkich standardowych usług poziomu wielu użytkowników. Jest to najprostsza możliwa metoda autostartu — bez zarządzania usługami, bez deklaracji zależności, bez logiki restartu. W Ubuntu 18.04 i nowszych, obsługa rc.local jest zapewniana przez jednostkę systemd rc-local.service, która jest domyślnie wyłączona i musi być jawnie włączona.

Kiedy jej używać

Używaj /etc/rc.local tylko do:

  • Jednorazowych poleceń inicjalizacyjnych, które nie muszą być zarządzane jako usługi
  • Szybkiego prototypowania lub testowania przed sformalizowaniem jednostki systemd
  • Prostych eksportów zmiennych środowiskowych lub modyfikacji parametrów jądra

Nie używaj /etc/rc.local dla długo działających demonów. Ponieważ działa w sposób blokujący, sekwencyjny bez nadzoru procesów, zawieszone polecenie w rc.local opóźni lub uniemożliwi zakończenie sekwencji uruchamiania.

Implementacja krok po kroku

Krok 1: Sprawdź czy /etc/rc.local istnieje

ls -la /etc/rc.local

Jeśli nie istnieje, utwórz go:

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

Krok 2: Włącz jednostkę systemd rc-local (Ubuntu 18.04+)

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

Krok 3: Dodaj swoje polecenie przed exit 0

sudo nano /etc/rc.local

Wstaw swoje polecenie powyżej linii exit 0:

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

& na końcu jest niezbędny dla każdego długo działającego polecenia — rozgałęzia proces do tła, aby rc.local nie blokował.

Krok 4: Zweryfikuj wykonanie

sudo systemctl status rc-local

Krytyczna pułapka

W Ubuntu 20.04 i 22.04, rc-local.service ma zakodowany limit czasu 30 sekund. Jeśli Twój skrypt trwa dłużej niż 30 sekund, systemd oznaczy usługę jako nieudaną, a kolejne polecenia w rc.local nie zostaną wykonane. Jawnie przekierowuj wyjście i uruchamiaj długo działające procesy w tle.

Metoda 3: Używanie jednostek usług systemd (zalecane)

Dlaczego systemd jest właściwym podejściem dla produkcji

systemd nie jest po prostu zamiennikiem SysVinit — jest kompletnym menedżerem systemu i sesji, który zapewnia rozwiązywanie zależności, równoległe uruchamianie, aktywację gniazd i D-Bus, uruchamianie usług na żądanie, nadzór procesów z automatycznym restartem, izolację zasobów opartą na cgroup oraz strukturowaną agregację logów przez journald. Dla każdego obciążenia działającego na Serwerze Dedykowanym lub produkcyjnym VPS, jednostki systemd są jedynym odpowiednim mechanizmem do zarządzania automatycznie ładowanymi skryptami.

Anatomia pliku jednostki systemd

Plik jednostki .service jest podzielony na trzy obowiązkowe sekcje:

  • [Unit]: Metadane, opis czytelny dla człowieka i deklaracje zależności (After=, Requires=, Wants=).
  • [Service]: Parametry wykonania — plik binarny lub skrypt do uruchomienia, typ usługi, polityka restartu, zmienne środowiskowe i opcje piaskownicy bezpieczeństwa.
  • [Install]: Definiuje, który cel systemd aktywuje tę jednostkę (WantedBy=multi-user.target jest standardem dla demonów serwerowych).

Implementacja krok po kroku

Krok 1: Przygotuj swój skrypt

Upewnij się, że Twój skrypt jest wykonywalny i znajduje się w stabilnej ścieżce:

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

Krok 2: Utwórz plik jednostki

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

Plik jednostki klasy produkcyjnej z wzmocnieniem bezpieczeństwa:

[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

Krok 3: Przeładuj demona systemd

Po utworzeniu lub modyfikacji dowolnego pliku jednostki, musisz przeładować indeks konfiguracji demona:

sudo systemctl daemon-reload

Krok 4: Włącz usługę dla autostartu

sudo systemctl enable examplescript.service

Tworzy to dowiązanie symboliczne w /etc/systemd/system/multi-user.target.wants/ wskazujące na Twój plik jednostki.

Krok 5: Uruchom usługę natychmiast

sudo systemctl start examplescript.service

Krok 6: Zweryfikuj status i logi

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

Zrozumienie typów usług systemd

Dyrektywa Type= w sekcji [Service] jest jednym z najbardziej niezrozumianych parametrów. Wybranie niewłaściwego typu powoduje, że systemd błędnie raportuje gotowość usługi, prowadząc do błędów zależności.

TypZachowaniePrzypadek użycia
simpleProces uruchomiony przez ExecStart jest procesem głównym. Systemd uznaje go za gotowy natychmiast.Skrypty i proste demony, które się nie rozgałęziają
forkingProces rozgałęzia się, a rodzic kończy działanie. Systemd śledzi dziecko przez plik PID.Tradycyjne demony Unix (np. Apache z PidFile)
oneshotProces działa do zakończenia i kończy się. Systemd czeka przed uruchomieniem zależnych jednostek.Jednorazowe zadania inicjalizacyjne, skrypty konfiguracyjne
notifyProces sygnalizuje gotowość przez sd_notify().Demony z natywną integracją systemd
idleWykonanie jest opóźnione do czasu wysłania wszystkich aktywnych zadań.Zadania w tle o niskim priorytecie

Dla skryptu, który uruchamia się raz podczas rozruchu i kończy działanie, użyj Type=oneshot z RemainAfterExit=yes, aby utrzymać jednostkę w stanie „aktywnym” po zakończeniu skryptu.

Zaawansowane: Kolejność zależności z After= i Wants=

Częsty błąd produkcyjny występuje, gdy skrypt wymagający łączności sieciowej uruchamia się przed pełną inicjalizacją stosu sieciowego. Prawidłowy łańcuch zależności dla skryptów zależnych od sieci to:

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

Różni się to od After=network.target, który gwarantuje jedynie skonfigurowanie interfejsów sieciowych — nie to, że są faktycznie online i osiągalne. Zależność network-online.target wymaga, aby systemd-networkd-wait-online.service lub odpowiednik potwierdził łączność.

Porównanie: Wszystkie trzy metody w skrócie

Funkcja/etc/init.d//etc/rc.localJednostka systemd
Zalecane dla produkcjiNieNieTak
Obsługa równoległego uruchamianiaNieNieTak
Nadzór procesów / automatyczny restartNieNieTak
Zarządzanie zależnościamiOgraniczone (nagłówki LSB)BrakPełne
Strukturowane logowanieNieNieTak (journald)
Piaskownica bezpieczeństwaNieNieTak
ZłożonośćNiskaBardzo niskaŚrednia
Obsługiwane na Ubuntu 22.04+Przez warstwę kompatybilnościPrzez rc-local.serviceNatywnie
Odpowiednie dla długo działających demonówCzęściowoNieTak
Odpowiednie dla jednorazowych zadań initTakTakTak (oneshot)

Typowe błędy i jak ich unikać

Uruchamianie skryptów jako root bez potrzeby. Dyrektywy User= i Group= w plikach jednostek systemd pozwalają na rezygnację z uprawnień. Skrypt, który musi tylko zapisywać do /var/log/myapp/, nie potrzebuje roota — utwórz dedykowanego użytkownika systemowego i odpowiednio przypisz własność katalogu.

Brak przekierowania wyjścia w rc.local. Bez przekierowania wyjścia, wszelkie wyjście echo lub błędy z poleceń rc.local trafiają na konsolę systemową i są tracone. Zawsze dołączaj >> /var/log/yourscript.log 2>&1.

Niespójne używanie ścieżek bezwzględnych. Usługi systemd działają w minimalnym środowisku bez PATH użytkownika. Zawsze używaj ścieżek bezwzględnych dla każdego pliku binarnego przywoływanego w ExecStart, w tym interpreterów takich jak /usr/bin/python3 lub /bin/bash.

Zapominanie o daemon-reload po edycji plików jednostek. systemd buforuje zawartość plików jednostek. Jeśli edytujesz plik .service i nie uruchomisz sudo systemctl daemon-reload, systemd będzie nadal używać starej konfiguracji.

Umieszczanie plików jednostek w /lib/systemd/system/ dla niestandardowych skryptów. Katalog /lib/systemd/system/ jest zarządzany przez menedżera pakietów. Niestandardowe pliki jednostek należą do /etc/systemd/system/, który ma pierwszeństwo i przeżywa aktualizacje pakietów.

Praktyczna macierz decyzyjna: Którą metodę wybrać

Użyj tego schematu, aby wybrać odpowiednią metodę dla swojego konkretnego scenariusza:

  • Długo działający demon, który musi restartować się po awarii — jednostka systemd z Restart=on-failure
  • Jednorazowy skrypt konfiguracyjny, który musi zakończyć się przed uruchomieniem innych usług — jednostka systemd z Type=oneshot i zależnościami Before=
  • Skrypt wymagający pełnej dostępności sieci — jednostka systemd z After=network-online.target
  • Szybkie jednolinijkowe polecenie do testowania lub prototypowania/etc/rc.local (tymczasowo)
  • Starsza aplikacja dostarczona ze skryptem init LSB/etc/init.d/ z update-rc.d
  • Cokolwiek działającego w produkcji — systemd, zawsze

Dla administratorów zarządzających wieloma serwerami Ubuntu, rozważ połączenie zarządzania jednostkami systemd z narzędziami do zarządzania konfiguracją, takimi jak Ansible, które mogą idempotentnie wdrażać i włączać pliki .service w całej flocie. Jeśli potrzebujesz zarządzanego środowiska z pełnym dostępem root do implementacji tych konfiguracji, VPS Hosting z Panelem Sterowania VPS zapewnia elastyczność zarządzania usługami systemd bezpośrednio bez ograniczeń.

Dla zespołów uruchamiających zasobochłonne obciążenia wymagające skryptów startowych do inicjalizacji sterowników GPU, środowisk CUDA lub serwerów wnioskowania ML, środowiska GPU Hosting szczególnie korzystają z łańcuchów zależności After= systemd, zapewniając pełne załadowanie sterowników przed próbą powiązania usług aplikacyjnych z zasobami sprzętowymi.

Jeśli Twoje automatycznie ładowane skrypty wchodzą w interakcję z konfiguracjami serwera WWW lub procedurami inicjalizacji bazy danych powiązanymi ze środowiskiem panelu sterowania, instalacje VPS z cPanel wymagają szczególnej ostrożności — cPanel zarządza własną warstwą nadzoru usług, a niestandardowe jednostki systemd muszą być zdefiniowane tak, aby unikać konfliktów z hakami zarządzania usługami cPanel.

Techniczna lista kontrolna kluczowych wniosków

Przed wdrożeniem jakiegokolwiek skryptu startowego na serwerze Ubuntu, zweryfikuj następujące kwestie:

  • Lokalizacja pliku jednostki: Niestandardowe skrypty trafiają do /etc/systemd/system/, nie do /lib/systemd/system/
  • Bit wykonywalności: Potwierdź za pomocą ls -la /path/to/script.sh — bit x musi być ustawiony
  • Ścieżki bezwzględne: Każdy plik binarny w ExecStart używa pełnej ścieżki; bez polegania na $PATH
  • Deklaracje zależności: After=network-online.target dla każdego skryptu zależnego od sieci
  • Typ usługi: Type=simple dla trwałych demonów, Type=oneshot dla skryptów uruchom-i-zakończ
  • Minimalizacja uprawnień: User=, Group=, NoNewPrivileges=true, ProtectSystem=strict
  • Skonfigurowane logowanie: StandardOutput=journal i StandardError=journal dla integracji z journald
  • Wykonano daemon-reload: Zawsze uruchamiaj sudo systemctl daemon-reload po utworzeniu lub edycji plików jednostek
  • Enable vs. start: enable tworzy dowiązanie symboliczne autostartu; start uruchamia go natychmiast — oba są wymagane
  • Przetestowane z journalctl: Potwierdź pomyślne wykonanie za pomocą sudo journalctl -u yourservice.service --since "5 minutes ago"

FAQ

Jaka jest różnica między systemctl enable a systemctl start?

systemctl enable tworzy dowiązanie symboliczne, które powoduje automatyczne uruchamianie usługi przy następnym rozruchu. systemctl start uruchamia usługę natychmiast w bieżącej sesji. Zazwyczaj potrzebujesz obu poleceń podczas konfigurowania nowej usługi po raz pierwszy.

Dlaczego moja usługa systemd kończy się błędem „executable not found”, mimo że skrypt istnieje?

Prawie zawsze oznacza to, że ścieżka ExecStart jest nieprawidłowa lub skryptowi brakuje bitu wykonywalności. Zweryfikuj za pomocą which yourscript i ls -la /path/to/script. Potwierdź również, że pierwsza linia Twojego skryptu jest prawidłowym shebangiem (#!/bin/bash lub #!/usr/bin/env python3), ponieważ systemd domyślnie nie wywołuje powłoki dla ExecStart.

Czy mogę uruchomić skrypt podczas uruchamiania tylko raz, nie przy każdym rozruchu?

Użyj Type=oneshot z dyrektywą ConditionPathExists=!/var/run/myscript.done w sekcji [Unit]. Skrypt tworzy plik wartowniczy przy pierwszym uruchomieniu; kolejne rozruchy pomijają wykonanie, ponieważ warunek nie jest spełniony.

Czy /etc/rc.local jest nadal obsługiwany w Ubuntu 22.04?

Tak, ale jest domyślnie wyłączony. Musisz ręcznie włączyć jednostkę rc-local.service za pomocą sudo systemctl enable rc-local i upewnić się, że plik istnieje i jest wykonywalny. Jest obsługiwany jako środek kompatybilności, a nie zalecana praktyka.

Jak sprawdzić, dlaczego skrypt startowy nie uruchomił się?

Uruchom sudo journalctl -u yourservice.service -b, aby wyświetlić wszystkie wpisy logów dla tej jednostki od ostatniego rozruchu. W przypadku błędów rc.local, sprawdź sudo systemctl status rc-local.service i przejrzyj /var/log/syslog pod kątem wpisów z sygnaturą czasową podczas sekwencji rozruchu.

15%

Zaoszczędź 15% na wszystkich usługach hostingowych

Sprawdź swoje umiejętności i zdobądź Rabat na dowolny plan hostingowy

Użyj kodu:

Skills
Rozpocznij