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 0Krok 2: Umieść skrypt w /etc/init.d/
sudo cp examplescript /etc/init.d/examplescriptKrok 3: Nadaj mu uprawnienia do wykonywania
sudo chmod +x /etc/init.d/examplescriptKrok 4: Zarejestruj go w systemie poziomów uruchamiania
sudo update-rc.d examplescript defaultsArgument 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 examplescriptPowinieneś 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 disableAby całkowicie go usunąć:
sudo update-rc.d examplescript removeMetoda 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.localJeśli nie istnieje, utwórz go:
sudo bash -c 'cat > /etc/rc.local << EOF
#!/bin/bash
exit 0
EOF'
sudo chmod +x /etc/rc.localKrok 2: Włącz jednostkę systemd rc-local (Ubuntu 18.04+)
sudo systemctl enable rc-local
sudo systemctl start rc-localKrok 3: Dodaj swoje polecenie przed exit 0
sudo nano /etc/rc.localWstaw 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-localKrytyczna 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.targetjest 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.shKrok 2: Utwórz plik jednostki
sudo nano /etc/systemd/system/examplescript.servicePlik 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.targetKrok 3: Przeładuj demona systemd
Po utworzeniu lub modyfikacji dowolnego pliku jednostki, musisz przeładować indeks konfiguracji demona:
sudo systemctl daemon-reloadKrok 4: Włącz usługę dla autostartu
sudo systemctl enable examplescript.serviceTworzy 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.serviceKrok 6: Zweryfikuj status i logi
sudo systemctl status examplescript.service
sudo journalctl -u examplescript.service -fZrozumienie 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.
| Typ | Zachowanie | Przypadek użycia |
|---|---|---|
simple | Proces uruchomiony przez ExecStart jest procesem głównym. Systemd uznaje go za gotowy natychmiast. | Skrypty i proste demony, które się nie rozgałęziają |
forking | Proces rozgałęzia się, a rodzic kończy działanie. Systemd śledzi dziecko przez plik PID. | Tradycyjne demony Unix (np. Apache z PidFile) |
oneshot | Proces działa do zakończenia i kończy się. Systemd czeka przed uruchomieniem zależnych jednostek. | Jednorazowe zadania inicjalizacyjne, skrypty konfiguracyjne |
notify | Proces sygnalizuje gotowość przez sd_notify(). | Demony z natywną integracją systemd |
idle | Wykonanie 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.targetRóż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.local | Jednostka systemd |
|---|---|---|---|
| Zalecane dla produkcji | Nie | Nie | Tak |
| Obsługa równoległego uruchamiania | Nie | Nie | Tak |
| Nadzór procesów / automatyczny restart | Nie | Nie | Tak |
| Zarządzanie zależnościami | Ograniczone (nagłówki LSB) | Brak | Pełne |
| Strukturowane logowanie | Nie | Nie | Tak (journald) |
| Piaskownica bezpieczeństwa | Nie | Nie | Tak |
| Złożoność | Niska | Bardzo niska | Średnia |
| Obsługiwane na Ubuntu 22.04+ | Przez warstwę kompatybilności | Przez rc-local.service | Natywnie |
| Odpowiednie dla długo działających demonów | Częściowo | Nie | Tak |
| Odpowiednie dla jednorazowych zadań init | Tak | Tak | Tak (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=oneshoti zależnościamiBefore= - 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/zupdate-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— bitxmusi być ustawiony - Ścieżki bezwzględne: Każdy plik binarny w
ExecStartużywa pełnej ścieżki; bez polegania na$PATH - Deklaracje zależności:
After=network-online.targetdla każdego skryptu zależnego od sieci - Typ usługi:
Type=simpledla trwałych demonów,Type=oneshotdla skryptów uruchom-i-zakończ - Minimalizacja uprawnień:
User=,Group=,NoNewPrivileges=true,ProtectSystem=strict - Skonfigurowane logowanie:
StandardOutput=journaliStandardError=journaldla integracji zjournald - Wykonano daemon-reload: Zawsze uruchamiaj
sudo systemctl daemon-reloadpo utworzeniu lub edycji plików jednostek - Enable vs. start:
enabletworzy dowiązanie symboliczne autostartu;starturuchamia 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.
