systemd का इतिहास और इसकी सफलता के मुख्य कारण
SysV init की सीमाओं से लेकर systemd के प्रभुत्व तक का सफर जानें। यह लेख समझाता है कि कैसे control groups और socket activation ने Linux जगत को चार वर्षों में पूरी तरह बदल दिया।
systemd क्यों सफल हुआ
systemd का इतिहास उन दो चीजों से शुरू होता है जिन्हें SysV init नहीं कर सकता था। SysV init (System V init, वह startup system जो Linux को AT&T Unix से विरासत में मिला था) के पास यह बताने का कोई तरीका नहीं था कि कोई service किस पर निर्भर है, और यह जानने का भी कोई तरीका नहीं था कि एक बार चलने के बाद कौन सी processes किस service से संबंधित हैं। systemd ने इन दोनों समस्याओं का समाधान उन kernel features के साथ दिया जो shell script की पहुँच से बाहर थे: processes को ट्रैक करने के लिए control groups, और ordering के लिए पहले से खुले हुए listening sockets। बाकी कहानी यह है कि कैसे ये दो समाधान बाकी userland में फैल गए, जहाँ से आपत्तियाँ शुरू हुईं, और उनमें से कई आपत्तियाँ सही थीं।
SysV init वास्तव में क्या करता था
एक SysV सिस्टम पर, PID 1 (process ID 1, kernel द्वारा शुरू की गई पहली process) /etc/inittab को पढ़ती थी, एक runlevel चुनती थी, और उस runlevel के लिए scripts चलाती थी। ये scripts /etc/init.d/ में स्थित होती थीं। /etc/rc3.d/ में मौजूद symbolic links यह तय करते थे कि कौन सी script कब और किस क्रम में चलेगी, इसलिए /etc/rc3.d/S20nginx, /etc/init.d/nginx की ओर इशारा करता था और उसे start तर्क (argument) के साथ कॉल किया जाता था।
#!/bin/sh
### BEGIN INIT INFO
# Provides: nginx
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Stop: $local_fs $remote_fs $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
### END INIT INFO
case "$1" in
start)
start-stop-daemon --start --quiet --pidfile /run/nginx.pid \
--exec /usr/sbin/nginx
;;
stop)
start-stop-daemon --stop --quiet --retry TERM/30/KILL/5 \
--pidfile /run/nginx.pid
;;
esacS20nginx में मौजूद 20 एक स्थान (position) है, न कि कोई dependency। यह बताता है कि यह script S19 के बाद और S21 से पहले चलती है। यह यह नहीं बताता कि ऐसा क्यों है, इसलिए कोई भी सिस्टम इसकी जाँच नहीं कर सकता, और कोई भी इंसान के निर्णय के बिना दो असंबंधित scripts को सुरक्षित रूप से एक साथ नहीं चला सकता।
rc प्रोग्राम प्रत्येक script को बारी-बारी से चलाता था और उसके समाप्त होने का इंतज़ार करता था। एक script जो नेटवर्क एड्रेस के इंतज़ार में तीस सेकंड के लिए रुक जाती थी, वह पूरे बूट प्रोसेस को तीस सेकंड के लिए रोक देती थी, उन सेवाओं के लिए भी जिन्हें नेटवर्क से कोई लेना-देना नहीं था।
उस script के शीर्ष पर मौजूद LSB (Linux Standard Base) header इसे अंदर से ठीक करने का एक प्रयास था। 2011 में Debian 6.0 ने insserv को डिफ़ॉल्ट बना दिया: इसने हर script से Required-Start को पढ़ा, एक ग्राफ बनाया, और symlinks को फिर से नंबर दिया। इसके बाद Debian startpar के साथ स्वतंत्र scripts को एक साथ चलाने में सक्षम हो गया। इससे मदद तो मिली, लेकिन यह मूल समस्या तक नहीं पहुँच पाया। dependency अभी भी script के समाप्त होने पर ही टिकी थी। S20nginx के 0 रिटर्न करने का मतलब केवल यह है कि एक shell function सफलतापूर्वक चला है। इसका मतलब यह नहीं है कि nginx connections स्वीकार कर रहा है।
वे पाँच चीजें जिन्हें कोई init script ठीक नहीं कर सकी
- समानांतर स्टार्टअप (Parallel startup)। फाइलनाम के आधार पर क्रम निर्धारित करना मशीन की हर सेवा पर एक पूर्ण क्रम थोपता है, इसलिए बूट प्रक्रिया उतनी ही धीमी होती है जितना कि उसके सभी हिस्सों का योग।
- तत्परता (Readiness)। एक start script तब exit हो जाती है जब वह daemon को fork कर देती है, न कि तब जब daemon अनुरोध को पूरा करने के लिए तैयार होता है, इसलिए अगली script अक्सर बहुत जल्दी शुरू हो जाती है।
- पर्यवेक्षण (Supervision)। एक daemon दो बार fork होता है और उसका parent exit हो जाता है, जो उसे terminal से अलग कर देता है और उसे PID 1 का child बना देता है। init एक child को exit होते देखता है और उसके पास उस प्रक्रिया से कोई विश्वसनीय लिंक नहीं होता जो जीवित बची है।
- मांग पर शुरू होना (On-demand start)। inetd (इंटरनेट सुपर-सर्वर) कनेक्शन आने पर daemon को लॉन्च कर सकता था, लेकिन यह अपनी अलग configuration file वाला एक पृथक सिस्टम था, और यह बूट के समय बाकी सब चीजों के क्रम के बारे में कुछ नहीं करता था।
- संसाधन नियंत्रण (Resource control)। init script में ऐसा कुछ नहीं था जो किसी सेवा की memory या CPU के हिस्से को सीमित कर सके।
ulimitकेवल एक प्रक्रिया पर लागू होता था औरniceकेवल scheduler को प्रभावित करता था, इसलिए किसी सेवा का अनियंत्रित child भी बॉक्स पर मौजूद किसी अन्य सामान्य प्रक्रिया जैसा ही दिखता था।
पर्यवेक्षण की कमी (supervision gap) वह समस्या है जिसने दैनिक आधार पर सबसे अधिक नुकसान पहुँचाया। PID file इसका समाधान थी: daemon अपना process ID /run/nginx.pid में लिखता था, और stop function उस फाइल को वापस पढ़ता था। यदि daemon को जबरन kill किया जाता था, तो फाइल वहीं रह जाती थी। kernel फिर उस नंबर को किसी और चीज के लिए पुन: उपयोग करता था, और start-stop-daemon --stop --pidfile उस प्रक्रिया को signal भेज देता था जो अब उस PID की स्वामी थी। एक पुरानी (stale) PID file के कारण ही init script गलत प्रक्रिया को kill कर देती है।
launchd ने सबसे पहले socket की समस्या को हल किया
Apple ने 2005 में Mac OS X 10.4 के साथ launchd को पेश किया, जिसे Dave Zarzycki ने लिखा था। एक ही process ने init, rc, xinetd, crond और watchdogd की जगह ले ली।
कॉपी करने योग्य विचार socket activation था। launchd सबसे पहले हर listening socket बनाता है, और उसके बाद daemons को start करता है। यदि कोई client ऐसे daemon से connect करता है जो अभी तक start नहीं हुआ है, तो उसे connection refused का error नहीं मिलता। इसका कारण यह है कि kernel उस connection को socket की backlog queue में तब तक रोक कर रखता है जब तक कि daemon accept() को call नहीं कर देता। दो daemons के बीच start होने के क्रम (ordering) को मैन्युअल रूप से तय करने की आवश्यकता समाप्त हो गई। इसे socket खुद संभाल लेता है।
launchd को Mach IPC (inter-process communication) पर बनाया गया था, जो Apple के XNU kernel का हिस्सा है और Linux में इसका कोई समकक्ष नहीं है। इस code को port करना कभी भी व्यावहारिक नहीं था। फिर भी, यह विचार आगे बढ़ गया।
Upstart ने events को कार्य की इकाई बनाया
Canonical का Upstart, जिसे Scott James Remnant ने लिखा था, Ubuntu 6.10 में अक्टूबर 2006 में release किया गया था। Fedora 9 से Fedora 14 तक, और RHEL 6 तथा Chrome OS ने भी इसका उपयोग किया। इसने runlevel की जगह event का उपयोग किया, और एक job यह निर्धारित करती थी कि किन events पर उसे start और stop होना चाहिए।
# /etc/init/example.conf
start on filesystem and net-device-up IFACE!=lo
stop on runlevel [!2345]
respawn
respawn limit 10 5
exec /usr/local/bin/exampledजैसे-जैसे jobs की संख्या बढ़ी, दो समस्याएँ सामने आईं। पहली समस्या दिशा की थी। एक job कहती है "जब यह हो तो मुझे start करें", इसलिए किस पर क्या निर्भर है, इसका ज्ञान गलत file में होता है: एक service यह जानती है कि उसे क्या चाहिए, लेकिन वह यह नहीं जान सकती कि भविष्य में किसे उसकी आवश्यकता होगी। एक नई service जोड़ने का अर्थ अक्सर किसी मौजूदा job को edit करना होता था ताकि वह एक नया event emit कर सके।
दूसरी समस्या tracking की थी। Upstart एक forking daemon को fork() calls को ptrace के साथ count करके track करता था, जिसे आप expect fork या expect daemon के रूप में configure करते थे। यदि forks की संख्या का अनुमान गलत हो जाए, तो Upstart ऐसी process को supervise करने लगता था जो पहले ही exit हो चुकी होती थी, या फिर वह ऐसे fork की प्रतीक्षा करता था जो पहले ही हो चुका होता था। इसका लक्षण यह था कि initctl start बिना किसी error के hang हो जाता था, जिसे समझाने का कोई तरीका job file में नहीं था।
Upstart के लिए contributors को Canonical के contributor agreement पर हस्ताक्षर करना भी आवश्यक था। यह कोई engineering दोष नहीं था, लेकिन इसने यह जरूर तय किया कि इस पर कौन काम करेगा।
PID 1 पर पुनर्विचार, अप्रैल 2010
30 अप्रैल 2010 को Lennart Poettering ने "Rethinking PID 1" नामक एक पोस्ट प्रकाशित की। Kay Sievers ने इस प्रोजेक्ट पर उनके साथ काम किया। इस तर्क के चार भाग थे।
- कम services शुरू करें। कई services तब तक प्रतीक्षा कर सकती हैं जब तक कि वास्तव में उनकी आवश्यकता न हो।
- जहाँ socket से क्रम का पता चल सके, वहाँ क्रम घोषित करना बंद करें। सभी sockets को एक बार में खोलें, फिर सब कुछ एक साथ शुरू करें।
- PID files के बजाय control groups के साथ processes को ट्रैक करें।
- एक declarative file में service का वर्णन करें, ताकि एक ही विवरण हर distribution पर काम करे।
उस वर्ष इसका पहला release आया। Fedora 14 ने नवंबर 2010 में एक विकल्प के रूप में systemd को शामिल किया, और Fedora 15 ने मई 2011 में इसे default बना दिया।
cgroups ने supervision को विश्वसनीय क्यों बनाया
cgroup (control group) प्रक्रियाओं को समूहबद्ध करने के लिए एक kernel feature है, जिसे 2008 में Linux 2.6.24 में शामिल किया गया था। systemd प्रत्येक service को उसके अपने cgroup में रखता है। एक child प्रक्रिया अपने parent के cgroup को inherit करती है, और एक unprivileged प्रक्रिया खुद को उससे बाहर नहीं निकाल सकती। इसलिए double forking कुछ भी नहीं छिपाती है: PID 1 के पास हर समय उन प्रक्रियाओं का सटीक सेट होता है जो एक unit से संबंधित हैं। एक service को रोकने का अर्थ है उसके cgroup में मौजूद हर चीज़ को kill करना, जो कि default KillMode=control-group का कार्य है।
systemctl status उस समूह को print करता है:
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-08-11 09:14:22 UTC; 3min ago
Main PID: 1042 (nginx)
Tasks: 3 (limit: 4653)
Memory: 6.1M (peak: 7.4M)
CGroup: /system.slice/nginx.service
├─1042 "nginx: master process /usr/sbin/nginx"
├─1043 "nginx: worker process"
└─1044 "nginx: worker process"वह block stale PID file की समस्या का पूरा समाधान है। यहाँ कोई ऐसी file नहीं है जो stale हो सके, क्योंकि यह सूची kernel state है।
वही tree limits भी लागू करती है, क्योंकि cgroups को tracking के लिए उपयोग किए जाने से पहले accounting के लिए बनाया गया था। MemoryMax=, CPUQuota= और TasksMax= प्रत्येक एक line के हैं। किसी service पर hard memory और CPU cap लगाना आज एक drop-in file का काम है, जबकि 2009 में यह एक shell script के लिए ऐसा patch था जिसे किसी ने नहीं लिखा था।
2011 और 2015 के बीच हर distribution ने बदलाव क्यों किया
- Fedora 15, मई 2011।
- openSUSE 12.1, नवंबर 2011।
- Mageia 2, मई 2012।
- Arch Linux, अक्टूबर 2012 से नए installations के लिए default।
- RHEL 7, जून 2014।
- SLES 12, अक्टूबर 2014।
- Debian 8, अप्रैल 2015।
- Ubuntu 15.04, अप्रैल 2015।
RHEL 7 की अवधि बाकी releases से आगे तक चली, क्योंकि CentOS 7 ने उसे rebuild किया था और अधिकांश administrators ने पहली बार unit file वहीं देखा—यह Red Hat Linux से CentOS होते हुए Rocky और AlmaLinux तक चलने वाली लंबी कहानी का एक चरण है।
इसके कारण अधिकतर सामान्य थे, यही कारण है कि यह बदलाव तेजी से हुआ।
- एक unit file हर distribution पर काम करती है, इसलिए upstream projects ने
.servicefile देना शुरू कर दिया और distributions ने हर package के लिए हर release पर shell script बनाए रखना बंद कर दिया। - 2012 के आसपास ConsoleKit का maintenance बंद होने के बाद desktop session tracking
systemd-logindपर स्थानांतरित हो गई। GNOME को logind की आवश्यकता थी, इसलिए जिस distribution में systemd नहीं था, उसे एक विकल्प ढूँढना पड़ा। वह विकल्प,elogind, systemd का logind है जिसे अलग से निकाला और maintain किया गया है। - udev, जो device manager है, को अप्रैल 2012 में systemd source tree में मिला दिया गया। udev का उपयोग करने वाले distributions अब systemd के repository को track कर रहे थे। इसके जवाब में Gentoo ने
eudevको fork कर लिया। - Containers के कारण विश्वसनीय process tracking और प्रति-service limits अधिक महत्वपूर्ण हो गईं, क्योंकि ये दोनों cgroup की विशेषताएं हैं। यह सवाल कि कौन सा supervisor container process का स्वामी है, तब भी बना रहता है जब आप reboot के बाद Docker Compose stack को वापस लाते हैं।
Debian का निर्णय सबसे चर्चित था। Technical Committee ने फरवरी 2014 में मतदान किया, मत बराबर रहे, और अध्यक्ष Bdale Garbee ने systemd के पक्ष में निर्णायक वोट दिया। Ubuntu ने कुछ दिनों बाद घोषणा की कि वह Upstart के साथ जारी रहने के बजाय Debian का अनुसरण करेगा। Debian developers के एक समूह ने नवंबर 2014 में distribution को Devuan के रूप में fork किया और मई 2017 में Devuan 1.0 release किया।
आपत्तियां, निष्पक्ष रूप से प्रस्तुत
दायरा (Scope)। एक प्रोजेक्ट अब PID 1, लॉगिंग डेमन, लॉगिन सेशन मैनेजमेंट, डिवाइस मैनेजर, नेटवर्क कॉन्फ़िगरेशन डेमन, DNS (डोमेन नेम सिस्टम) रिज़ॉल्वर, NTP (नेटवर्क टाइम प्रोटोकॉल) क्लाइंट, कंटेनर रनर और बूट लोडर प्रदान करता है। सामान्य बचाव यह है कि ये अलग-अलग बाइनरी हैं जिन्हें इंस्टॉल करना अनिवार्य नहीं है, यह सच है लेकिन यह आपत्ति का समाधान नहीं करता है। एक बार जब डेस्कटॉप को logind की आवश्यकता होती है, और logind को systemd के ट्री से अलग नहीं किया जा सकता, तो चुनाव अब स्वतंत्र नहीं रह जाता। तर्क में 'कपलिंग' (coupling) का यही अर्थ था, और ऐसा हुआ भी।
बाइनरी जर्नल। journald सादे टेक्स्ट के बजाय एक इंडेक्स किए गए बाइनरी फॉर्मेट में लॉग लिखता है। आपको वे सुविधाएं मिलती हैं जो टेक्स्ट में कभी नहीं थीं: प्रति-यूनिट और प्रति-प्राथमिकता फ़िल्टरिंग, स्ट्रक्चर्ड फ़ील्ड्स, और ऐसा मेटाडेटा जिसे भेजने वाला प्रोग्राम बदल नहीं सकता, क्योंकि journald स्वयं यूनिट और cgroup को रिकॉर्ड करता है। journalctl -u nginx -p err --since "-1h" तारीख के रेगुलर एक्सप्रेशन के साथ grep की जगह लेता है। इसकी कीमत भी वास्तविक है। ऐसी मशीन पर जो बूट नहीं हो रही है, आप रेस्क्यू शेल से less के साथ लॉग नहीं पढ़ सकते। इसके बजाय आप माउन्ट की गई डिस्क पर journalctl को पॉइंट करते हैं:
sudo journalctl --directory /mnt/var/log/journal --boot -1 --priority errयहाँ एक दूसरा जाल है जो लोगों को एक बार फंसाता है। journald लॉग्स को /run/log/journal में रखता है, जो कि मेमोरी है, जब तक कि /var/log/journal मौजूद न हो। जिस बॉक्स पर यह मौजूद नहीं है, वहां रीबूट के बाद journalctl -b -1 के पास दिखाने के लिए कुछ नहीं होता, और यही वह सटीक क्षण है जब आपको इसकी आवश्यकता होती है। इसे जांचें और ठीक करें:
journalctl --disk-usage
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journaldjournalctl --disk-usage को अब /var/log/journal के अंतर्गत आर्काइव किए गए जर्नल्स की रिपोर्ट करनी चाहिए। यदि आप सादा टेक्स्ट भी चाहते हैं, तो /etc/systemd/journald.conf में ForwardToSyslog=yes सेट करें और rsyslog को इंस्टॉल रखें।
बूट की डिबग क्षमता। जब कोई यूनिट हैंग हो जाती है, तो कंसोल केवल एक लाइन दिखाता है और कुछ नहीं:
[ *** ] A start job is running for Wait for Network to be Configured (1min 32s / no limit)आगे बढ़ने के लिए उपकरण मौजूद हैं: अटकने के दौरान systemctl list-jobs, बाद में systemd-analyze blame और systemd-analyze critical-chain, और कर्नल कमांड लाइन पर systemd.log_level=debug। शिकायत का निष्पक्ष संस्करण यह है कि एक init स्क्रिप्ट को कोई भी व्यक्ति जो sh जानता है, ऊपर से नीचे तक पढ़ सकता था, जबकि एक अटकी हुई यूनिट के लिए यह जानना आवश्यक है कि दर्जनों कमांड्स में से किसका उपयोग करना है। यह एक वास्तविक लागत है। इसे प्रत्येक एडमिनिस्ट्रेटर को एक बार चुकाना पड़ता है, और बहुत सारे एडमिनिस्ट्रेटर ने इसे एक ही समय में चुकाया था।
एक डिफ़ॉल्ट जो सभी के लिए बदलता है। 2016 में systemd 230 ने logind के डिफ़ॉल्ट को बदल दिया ताकि लॉगआउट पर बचे हुए यूज़र प्रोसेस समाप्त हो जाएं। अलग किए गए tmux और screen सेशन तब समाप्त हो गए जब उन्हें शुरू करने वाला सेशन समाप्त हुआ। डिस्ट्रिब्यूशंस ने /etc/systemd/logind.conf में KillUserProcesses=no शिप किया, और समर्थित उत्तर loginctl enable-linger <user> है। एक प्रोजेक्ट में एक डिफ़ॉल्ट ने उस आदत को बदल दिया जिस पर लाखों लोग निर्भर थे, जिसका व्यावहारिक अर्थ है "यूज़रलैंड का बहुत अधिक हिस्सा एक ही जगह होना"।
एक डिफ़ॉल्ट निर्भरता एक सुरक्षा सतह है। मार्च 2024 में xz-utils में बैकडोर ने Debian और Ubuntu पर sshd को लक्षित किया। अपस्ट्रीम OpenSSH, libsystemd से लिंक नहीं होता है। उन डिस्ट्रिब्यूशंस ने इसे पैच किया ताकि sshd, systemd को तत्परता (readiness) की रिपोर्ट दे सके, और libsystemd ने liblzma को खींच लिया, जहाँ बैकडोर मौजूद था। तत्परता प्रोटोकॉल स्वयं $NOTIFY_SOCKET में नामित सॉकेट पर भेजा गया एक सिंगल डेटाग्राम है, इसलिए इसके लिए किसी लाइब्रेरी की आवश्यकता नहीं थी। systemd की प्रतिक्रिया dlopen के साथ कम्प्रेशन लाइब्रेरीज़ को लोड करने की थी, ताकि वे अब डिफ़ॉल्ट रूप से लिंक न हों। बग का एक संबंधित वर्ग भी समान रूप दिखाता है: 2017 में एक User= मान जो अंक से शुरू होता था, उसे अमान्य माना गया और यूनिट विफल होने के बजाय root के रूप में चली, इसलिए एक टाइपो विशेषाधिकार वृद्धि (privilege escalation) बन गया। बाद के संस्करण यूनिट को शुरू करने से मना कर देते हैं।
अपने systemctl प्रॉम्प्ट पर इतिहास
ऊपर बताई गई हर समस्या अब एक ऐसी फाइल में एक directive है जिसे आप पढ़ सकते हैं।
- Serial boot अब
After=औरWants=बन गया है, औरsystemd-analyze critical-chainदिखाता है कि वास्तव में आपके boot को किस चीज ने रोक रखा था। - Readiness अब
Type=notifyबन गया है, जहाँ serviceREADY=1को$NOTIFY_SOCKETमें लिखती है जब वह सेवा देने के लिए तैयार होती है। पुराने daemons के लिएType=forkingके साथPIDFile=अभी भी मौजूद है, और यह वह प्रकार है जोstart operation timed out. Terminating.के साथ विफल हो जाता है जब PID फाइल कभी दिखाई नहीं देती। गलत प्रकार चुनने के कारण ही एक unit 'active' रिपोर्ट करती है जबकि वह daemon पहले ही बंद हो चुका होता है, इसलिए यह जानना महत्वपूर्ण है कि कौन सा Type= आपके daemon के शुरू होने के तरीके से मेल खाता है इससे पहले कि आप वह लाइन लिखें। - Supervision अब cgroup बन गया है, इसलिए
Restart=on-failureके साथRestartSec=एक wrapper script की जगह ले लेता है, औरStartLimitBurst=एक crash loop को हमेशा चलने से रोकता है। - inetd अब
.serviceunit के बगल में स्थित एक.socketunit बन गया है। ulimitअबMemoryMax=,CPUQuota=औरTasksMax=बन गया है।- Init script में
su - appuser -cलाइन अबUser=,NoNewPrivileges=yesऔरProtectSystem=strictबन गई है, इसलिए किसी service को unprivileged user के रूप में चलाना अब अतिरिक्त काम के बजाय unit का डिफ़ॉल्ट स्वरूप है।
[Unit]
Description=Example API
Wants=network-online.target
After=network-online.target postgresql.service
Requires=postgresql.service
[Service]
Type=notify
ExecStart=/usr/local/bin/exampled
Restart=on-failure
RestartSec=2
MemoryMax=512M
CPUQuota=50%
TasksMax=128
User=exampled
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
StateDirectory=exampled
[Install]
WantedBy=multi-user.targetउस फाइल में एक लाइन वह गलती है जो हर कोई एक बार जरूर करता है। Requires=postgresql.service एक आवश्यकता है, न कि केवल एक क्रम: यह कहता है कि यदि Postgres विफल होता है तो आपकी unit विफल हो जाएगी, और यह यह नहीं कहता कि Postgres को पहले शुरू करें। After=postgresql.service के बिना दोनों एक ही समय पर शुरू होते हैं, और आपकी service एक ऐसे port से जुड़ने की कोशिश करती है जिस पर अभी कुछ भी listening नहीं है। ये दोनों जानबूझकर अलग रखे गए हैं, क्योंकि कभी-कभी आपको एक की आवश्यकता होती है और दूसरे की नहीं। ProtectSystem=strict इस service के लिए filesystem को read-only माउंट करता है, और इसीलिए StateDirectory= वहां मौजूद है: यह service को /var/lib के अंतर्गत एक writable path देता है।
2026 के सर्वर पर 2005 को देखने की सबसे स्पष्ट जगह Ubuntu 24.04 पर SSH है, जो अगस्त 2026 तक systemd 255 के साथ आता है। ssh.service डिफ़ॉल्ट रूप से socket activated है: ssh.socket listening socket को होल्ड करता है, और कनेक्शन आने पर sshd शुरू होता है। इसलिए /etc/ssh/sshd_config में Port 2222 का कोई प्रभाव नहीं पड़ता है, क्योंकि sshd वह process नहीं है जिसने port खोला है। यह बदलाव socket unit में किया जाना चाहिए।
sudo systemctl edit ssh.socket[Socket]
ListenStream=
ListenStream=2222खाली ListenStream= packaged unit से विरासत में मिली वैल्यू को साफ़ कर देता है। इसे न हटाने पर आपको दोनों ports मिल जाएंगे, क्योंकि systemd रिप्लेस करने के बजाय लिस्ट में जोड़ देता है। फिर लागू करें और जांचें, पूरे समय एक दूसरा SSH session खुला रखें:
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
sudo ss -lntp | grep 2222ss को port 2222 पर एक socket दिखाना चाहिए जो systemd के स्वामित्व में हो, न कि sshd के। यह आपके VPS पर बीस साल बाद का launchd डिज़ाइन है। यदि आप पुराना व्यवहार पसंद करते हैं, तो sudo systemctl disable --now ssh.socket के बाद sudo systemctl enable --now ssh.service आपको एक लंबे समय तक चलने वाला sshd देता है जो फिर से अपनी config से Port पढ़ता है।
आप इनमें से किन विवरणों का सामना करते हैं, यह आपके द्वारा चलाए जा रहे release पर निर्भर करता है, इसलिए अपग्रेड की योजना बनाने से पहले LTS और interim Ubuntu release के बीच का अंतर जानना उचित है। एक से अधिक मशीनों पर, यह तथ्य कि एक unit फाइल हर जगह समान है, यही कारण है कि कई सर्वरों को एक जगह से मैनेज करना अब shell scripting की समस्या के बजाय एक configuration की समस्या है। और जब आप अपनी खुद की units लिखते हैं, तो service और timer की जोड़ी वह काम करती है जिसे आप 2009 में एक init script और एक cron लाइन के बीच विभाजित करते थे।
FAQ
Linux distributions ने SysV init को systemd से क्यों बदल दिया?
दो इंजीनियरिंग कारणों और एक मेंटेनेंस कारण से। SysV init सेवाओं को फाइलनाम के आधार पर क्रमबद्ध करता था, जो कि एक dependency के बजाय केवल एक स्थान (position) था। यह उन daemons को ट्रैक नहीं कर पाता था जो अपने parent से fork हो जाते थे, जिस कारण stale PID files के चलते गलत process kill हो जाती थी। systemd ने socket activation और dependency directives के साथ क्रमबद्धता की समस्या को हल किया, और control groups के साथ ट्रैकिंग की समस्या को। मेंटेनेंस का कारण गति से संबंधित था: एक unit file हर distribution पर काम करती है, इसलिए upstream projects ने एक .service फाइल देना शुरू किया और distribution maintainers ने हर package के लिए shell script लिखना बंद कर दिया। Fedora 15 ने मई 2011 में इसे अपनाया और Ubuntu 15.04 अप्रैल 2015 में इसे अपनाने वाला अंतिम बड़ा distribution था।
क्या systemd एक विशाल binary है?
नहीं। इसका source tree कई अलग-अलग programs बनाता है। PID 1, /usr/lib/systemd/systemd है, जबकि journald, logind और udevd अलग-अलग processes हैं जिनकी अपनी binaries होती हैं; इन्हें अपने सिस्टम पर देखने के लिए ls /usr/lib/systemd/ चलाएं। जो आलोचना आज भी कायम है, वह binary size के बजाय release coupling के बारे में है: ये programs एक साथ release किए जाते हैं और private interfaces साझा करते हैं, इसलिए distributions इन्हें एक सेट के रूप में लेते हैं, और GNOME जैसे software ने विशेष रूप से logind की अपेक्षा करना शुरू कर दिया है।
क्या मैं अभी भी बिना systemd के Linux चला सकता हूँ?
हाँ। Devuan में sysvinit मिलता है, Gentoo डिफ़ॉल्ट रूप से OpenRC का उपयोग करता है, Void में runit का उपयोग होता है, Alpine में OpenRC के साथ busybox init का उपयोग होता है, और Slackware BSD-style scripts का उपयोग करता है। इसकी कीमत compatibility के काम के रूप में चुकानी पड़ती है। जो desktop software logind की अपेक्षा करता है, उसे elogind की आवश्यकता होती है, जो कि systemd का logind है जिसे एक standalone package के रूप में maintain किया जाता है। साथ ही, अब काफी सारा server software केवल .service फाइल के साथ आता है, इसलिए आपको startup script खुद लिखनी और maintain करनी पड़ती है।
journal plain text फाइल के बजाय binary क्यों है?
क्योंकि journald एक index के साथ structured fields को स्टोर करता है। यह per-unit filtering, priority filtering और ऐसा metadata प्रदान करता है जिसे भेजने वाला program बदल नहीं सकता: journald log line पर भरोसा करने के बजाय स्वयं unit, cgroup और वास्तविक UID को रिकॉर्ड करता है। इसकी कीमत यह है कि इसे पढ़ने के लिए आपको journalctl की आवश्यकता होती है, यहाँ तक कि rescue system से भी, जहाँ आप journalctl --directory /mnt/var/log/journal के साथ mounted disk को point करते हैं। यदि आप text भी चाहते हैं, तो /etc/systemd/journald.conf में ForwardToSyslog=yes सेट करें।
मेरी /etc/init.d script को edit करने की जगह अब क्या है?
Drop-in files। /usr/lib/systemd/system/ में unit को edit न करें, क्योंकि package upgrade इसे overwrite कर देता है। sudo systemctl edit nginx.service चलाएं और systemd /etc/systemd/system/nginx.service.d/override.conf बनाएगा, जिसे packaged unit के ऊपर merge किया जाता है। systemctl cat nginx.service मर्ज किया गया परिणाम दिखाता है, और systemd-delta मशीन पर मौजूद हर override को सूचीबद्ध करता है। हाथ से किए गए किसी भी बदलाव के बाद, sudo systemctl daemon-reload चलाएं, अन्यथा अगला command Warning: The unit file, source configuration file or drop-ins of nginx.service changed on disk. प्रिंट करेगा।