SSD Nodes Learn Hosting plans →
নির্দেশিকা Matt Connorদ্বারা Matt Connor · আপডেট করা হয়েছে 2026-08-27

systemd কেন বিজয়ী হলো: ইতিহাস ও সাফল্যের কারণ

SysV init-এর সীমাবদ্ধতা, Upstart ও launchd-এর প্রাথমিক চেষ্টা, এবং মাত্র চার বছরে কেন সব distribution systemd গ্রহণ করল তা জানুন। সঠিক আপত্তিগুলোও দেখুন।

systemd কেন বিজয়ী হয়েছে

systemd-এর ইতিহাস শুরু হয় SysV init যে দুটি কাজ করতে পারত না, সেগুলো দিয়ে। SysV init (System V init, AT&T Unix থেকে Linux-এ উত্তরাধিকারসূত্রে আসা startup system) কোনো service কোন বিষয়ের ওপর নির্ভর করে তা বর্ণনা করতে পারত না। চালু হওয়ার পর কোন process-গুলো একটি service-এর অন্তর্ভুক্ত, তাও নির্ধারণ করতে পারত না। systemd এই দুটি সমস্যার সমাধান করেছে এমন kernel feature ব্যবহার করে, যেগুলো shell script সরাসরি ব্যবহার করতে পারে না: process track করার জন্য control group এবং startup order নির্ধারণের জন্য আগে থেকে open করা listening socket। পরবর্তী ইতিহাস হলো, এই দুটি সমাধান কীভাবে userland-এর অন্যান্য অংশে ছড়িয়ে পড়ে। আপত্তিগুলো সেখান থেকেই শুরু হয়, এবং সেগুলোর কয়েকটি যথার্থও ছিল।

SysV init আসলে কী করত

SysV সিস্টেমে PID 1 (process ID 1, kernel যে প্রথম process চালু করে) /etc/inittab পড়ত, একটি runlevel নির্বাচন করত এবং সেই runlevel-এর script চালাত। Script-গুলো /etc/init.d/-এ থাকত। /etc/rc3.d/-এর symbolic link নির্ধারণ করত কোন 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
    ;;
esac

S20nginx-এর 20 একটি অবস্থান নির্দেশ করে, dependency নয়। এর অর্থ, এই script S19-এর পরে এবং S21-এর আগে চলে। এটি কেন এমন ক্রম দরকার তা জানায় না। তাই কোনো কিছু এটি যাচাই করতে পারে না। মানুষের নিরাপদ বলে সিদ্ধান্ত নেওয়া ছাড়া, পরস্পরের সঙ্গে সম্পর্কহীন দুটি script একই সময়ে নিরাপদে চালানোও সম্ভব নয়।

rc program প্রতিটি script একে একে চালাত এবং সেটি শেষ হওয়া পর্যন্ত অপেক্ষা করত। কোনো script network address-এর জন্য ত্রিশ সেকেন্ড অপেক্ষা করে আটকে থাকলে পুরো boot ত্রিশ সেকেন্ড আটকে থাকত। এমন service-এর ক্ষেত্রেও এটি ঘটত, যেগুলো network কখনো ব্যবহার করে না।

সেই script-এর শীর্ষে থাকা LSB (Linux Standard Base) header ভেতর থেকে এই সমস্যা সমাধানের একটি প্রচেষ্টা ছিল। 2011 সালে Debian 6.0 insserv-কে default করে। এটি প্রতিটি script থেকে Required-Start পড়ত, একটি graph তৈরি করত এবং symlink-গুলোর numbering নতুন করে নির্ধারণ করত। এরপর Debian startpar ব্যবহার করে স্বাধীন script-গুলো একই সময়ে চালাতে পারত। এতে কিছুটা সুবিধা হয়েছিল, কিন্তু মূল সমস্যা দূর হয়নি। Dependency তখনও কোনো script exit করার ওপর নির্ভর করত। S20nginx-এর 0 return করা মানে একটি shell function return করেছে। এর অর্থ nginx connection গ্রহণ করছে না।

কোনো init script যে পাঁচটি সমস্যা সমাধান করতে পারত না

  • Parallel startup। Filename অনুযায়ী ordering মেশিনের প্রতিটি service-এর ওপর একটি সম্পূর্ণ order তৈরি করে। তাই boot-এর সময় সব অংশের সময়ের যোগফলের সমান হয়।
  • Readiness। একটি start script daemon-কে fork করার পরই শেষ হয়; daemon request serve করতে পারছে কি না, তা নিশ্চিত হওয়ার পরে নয়। তাই পরের script প্রায়ই খুব তাড়াতাড়ি শুরু হয়।
  • Supervision। একটি daemon দুইবার fork করে এবং তার parent exit করে। এতে সেটি terminal থেকে বিচ্ছিন্ন হয় এবং PID 1 তার নতুন parent হয়। init একটি child exit করতে দেখে, কিন্তু টিকে থাকা process-এর সঙ্গে তার কোনো নির্ভরযোগ্য link থাকে না।
  • On-demand start। inetd (internet super-server) connection এলে daemon চালু করতে পারত। কিন্তু এটি ছিল নিজস্ব configuration file-সহ একটি আলাদা system। boot-এর সময় অন্য সব service-এর ordering নিয়ে এটি কিছুই করত না।
  • Resource control। কোনো init script service-এর memory বা CPU-র share-এর সীমা নির্ধারণ করতে পারত না। ulimit শুধু একটি process-এর ক্ষেত্রে প্রযোজ্য ছিল, আর nice কেবল scheduler-কে প্রভাবিত করত। তাই কোনো service-এর নিয়ন্ত্রণের বাইরে চলে যাওয়া child-কে মেশিনের অন্য যেকোনো process-এর মতোই দেখা হতো।

Supervision-এর ঘাটতিই দৈনন্দিন কাজে সবচেয়ে বেশি সমস্যা তৈরি করত। PID file ছিল এর workaround। daemon তার process ID /run/nginx.pid-এ লিখত, আর stop function সেই file পড়ে ID নিত। daemon-কে জোর করে kill করা হলে file-টি থেকে যেত। এরপর kernel সেই number অন্য কোনো কিছুকে দিয়ে দিত, আর start-stop-daemon --stop --pidfile তখন ওই number-এর বর্তমান owner-কে signal পাঠাত। একটি পুরোনো PID file-এর কারণেই init script ভুল process kill করে।

launchd প্রথমেই socket সমস্যার সমাধান করেছিল

Apple 2005 সালে Mac OS X 10.4-এ Dave Zarzycki-এর লেখা launchd প্রকাশ করে। একটি process init, rc, xinetd, crond এবং watchdogd-এর কাজ প্রতিস্থাপন করে।

অনুকরণ করার মতো ধারণাটি ছিল socket activation। launchd প্রথমে প্রতিটি listening socket তৈরি করে, তারপর daemon-গুলো চালু করে। কোনো daemon এখনও চালু না থাকলেও কোনো client সেটিতে সংযোগ করলে connection refused পায় না, কারণ daemon accept() কল করা পর্যন্ত kernel ওই socket-এর backlog queue-তে সংযোগটি ধরে রাখে। দুটি daemon-এর মধ্যে ordering আর কোনো মানুষের নির্ধারণ করা বিষয় থাকে না। socket নিজেই সেটি পরিচালনা করে।

launchd Mach IPC (inter-process communication)-এর ওপর তৈরি, যা Apple-এর XNU kernel-এর অংশ এবং Linux-এ এর সমতুল্য নেই। Code port করা কখনোই বাস্তবসম্মত ছিল না। তবুও ধারণাটি অন্যত্র ছড়িয়ে পড়ে।

Upstart-এ event-ই কাজের একক ছিল

Scott James Remnant লিখিত Canonical-এর Upstart, October 2006-এ Ubuntu 6.10-এর সঙ্গে প্রকাশিত হয়। Fedora 9 থেকে Fedora 14 পর্যন্ত এটি ব্যবহৃত হয়েছে। RHEL 6 এবং Chrome OS-ও এটি ব্যবহার করেছে। Upstart runlevel-এর পরিবর্তে event ব্যবহার করত। কোন event-এর সময় job শুরু ও বন্ধ হবে, তা job-এই নির্ধারিত থাকত।

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

Job-এর সংখ্যা বাড়ার সঙ্গে দুটি সমস্যা দেখা দেয়। প্রথমটি ছিল নির্ভরতার দিক। একটি job বলে, “এটি ঘটলে আমাকে শুরু করুন।” তাই কোন কিছুর ওপর কোনটি নির্ভর করে, সেই তথ্য ভুল ফাইলে থাকে। একটি service জানে তার কী প্রয়োজন। আগামী বছর কোন service এটি ব্যবহার করবে, তা service-এর পক্ষে জানা সম্ভব নয়। নতুন service যোগ করতে প্রায়ই এমন একটি existing job সম্পাদনা করতে হতো, যাতে সেটি নতুন event তৈরি করে।

দ্বিতীয়টি ছিল tracking। Upstart fork করা daemon অনুসরণ করত fork() call-এর সংখ্যা ptrace দিয়ে গুনে। এই সংখ্যা expect fork অথবা expect daemon হিসেবে configure করতে হতো। fork-এর সংখ্যা ভুল অনুমান করলে Upstart ইতিমধ্যে exit করা process supervise করত, অথবা ইতিমধ্যে সম্পন্ন হওয়া fork-এর জন্য অপেক্ষা করত। এর লক্ষণ ছিল কোনো error ছাড়াই initctl start hang করা। job file-এ এই আচরণ ব্যাখ্যা করার কোনো উপায় ছিল না।

Upstart-এ contributors-দের Canonical-এর contributor agreement-এ স্বাক্ষর করাও বাধ্যতামূলক ছিল। এটি engineering ত্রুটি ছিল না। তবে কারা এতে কাজ করেছেন, তার ওপর এর প্রভাব পড়েছিল।

PID 1 নিয়ে নতুনভাবে ভাবনা, April 2010

30 April 2010-এ Lennart Poettering "Rethinking PID 1" নামে একটি পোস্ট প্রকাশ করেন। Kay Sievers তাঁর সঙ্গে এই প্রকল্পে কাজ করেন। যুক্তিটি চারটি অংশে বিভক্ত ছিল।

  • কম service start করুন। কোনো service-এর জন্য বাস্তবে অনুরোধ না আসা পর্যন্ত অনেক service অপেক্ষা করতে পারে।
  • socket-এর মাধ্যমে যে ক্রম নির্ধারিত হতে পারে, সেখানে আলাদা করে ক্রম ঘোষণা করবেন না। এক ধাপে সব socket open করুন, তারপর সবকিছু একসঙ্গে start করুন।
  • PID file-এর বদলে control group ব্যবহার করে process track করুন।
  • একটি declarative file-এ service-এর বর্ণনা দিন, যাতে একই বর্ণনা সব distribution-এ কাজ করে।

সেই বছরই প্রথম release প্রকাশিত হয়। Fedora 14 November 2010-এ systemd-কে একটি option হিসেবে release করে, এবং Fedora 15 May 2011-এ এটিকে default করে।

supervision নির্ভরযোগ্য হওয়ার কারণ: cgroups

একটি cgroup (control group) হলো process-গুলোকে group করার জন্য kernel-এর একটি feature, যা 2008 সালে Linux 2.6.24-এ যুক্ত হয়। systemd প্রতিটি service-কে নিজস্ব cgroup-এ রাখে। কোনো child তার parent-এর cgroup উত্তরাধিকারসূত্রে পায়, এবং unprivileged process নিজেকে সেখান থেকে বাইরে সরাতে পারে না। তাই double forking কিছুই আড়াল করতে পারে না: PID 1 সব সময় একটি unit-এর অন্তর্ভুক্ত process-গুলোর সঠিক set ধরে রাখে। কোনো service বন্ধ করার অর্থ হলো তার cgroup-এর সব process kill করা; default KillMode=control-group এটাই করে।

systemctl status সেই group-টি দেখায়:

● 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"

stale PID file-এর সমস্যার সম্পূর্ণ উত্তর এই block-এ আছে। কোনো file stale হয়ে পড়ার সুযোগ নেই, কারণ এই list kernel state থেকে আসে।

একই tree limits-ও বহন করে, কারণ tracking-এর জন্য ব্যবহারের আগে cgroup-গুলো accounting-এর জন্য তৈরি করা হয়েছিল। MemoryMax=, CPUQuota= এবং TasksMax= প্রতিটি এক লাইনের। কোনো service-এ কঠোর memory ও CPU cap নির্ধারণ করা এখন একটি drop-in file তৈরির কাজ; আর 2009 সালে এটি এমন একটি shell script-এ patch করার বিষয় ছিল, যা কেউ লেখেনি।

2011 থেকে 2015 সালের মধ্যে কেন প্রতিটি distribution পরিবর্তন করেছিল

  • Fedora 15, May 2011.
  • openSUSE 12.1, November 2011.
  • Mageia 2, May 2012.
  • Arch Linux, October 2012 থেকে নতুন installation-এর জন্য default।
  • RHEL 7, June 2014.
  • SLES 12, October 2014.
  • Debian 8, April 2015.
  • Ubuntu 15.04, April 2015.

RHEL 7-এর সময়কাল অন্যগুলোর চেয়ে বেশি স্থায়ী হয়েছিল, কারণ CentOS 7 সেটি পুনর্নির্মাণ করেছিল এবং অধিকাংশ administrator প্রথম unit file-এর সঙ্গে সেখানেই পরিচিত হন—এটি Red Hat Linux থেকে CentOS হয়ে Rocky ও AlmaLinux পর্যন্ত বিস্তৃত দীর্ঘ ধারাবাহিকতার একটি ধাপ।

কারণগুলো বেশিরভাগই সাধারণ ছিল। তাই পরিবর্তন দ্রুত হয়েছিল।

  • একটি unit file প্রতিটি distribution-এ কাজ করে। তাই upstream project-গুলো একটি .service file সরবরাহ করতে শুরু করে। Distribution-গুলোও প্রতিটি release-এ প্রতিটি package-এর জন্য আলাদা shell script রক্ষণাবেক্ষণ বন্ধ করে।
  • 2012 সালের দিকে ConsoleKit-এর রক্ষণাবেক্ষণ বন্ধ হওয়ার পর desktop session tracking systemd-logind-এ স্থানান্তরিত হয়। GNOME-এর logind প্রয়োজন ছিল। তাই systemd ছাড়া কোনো distribution-কে বিকল্প খুঁজতে হতো। সেই বিকল্প হলো elogind। এটি systemd-এর logind আলাদা করে রক্ষণাবেক্ষণ করা সংস্করণ।
  • Device manager udev April 2012-এ systemd source tree-তে একীভূত হয়। তখন udev সরবরাহকারী distribution-গুলোকে systemd-এর repository অনুসরণ করতে হতো। এর প্রতিক্রিয়ায় Gentoo eudev fork করে।
  • Container ব্যবহারের কারণে নির্ভরযোগ্য process tracking এবং প্রতি-service limit আরও গুরুত্বপূর্ণ হয়ে ওঠে। দুটিই cgroup-এর feature। কোন supervisor একটি container process-এর মালিক হবে, সেই প্রশ্নটি এখনো প্রাসঙ্গিক, বিশেষ করে যখন আপনি reboot-এর পরে Docker Compose stack আবার চালু করেন

Debian-এর সিদ্ধান্তটি সবচেয়ে বেশি আলোচিত হয়েছিল। Technical Committee February 2014-এ ভোট দেয়। ভোট সমান হয়ে যায়। Chair Bdale Garbee systemd-এর পক্ষে নির্ণায়ক ভোট দেন। কয়েক দিন পর Ubuntu ঘোষণা করে যে তারা Upstart চালিয়ে যাওয়ার পরিবর্তে Debian-এর সিদ্ধান্ত অনুসরণ করবে। Debian-এর একদল developer November 2014-এ distribution-টি fork করে Devuan তৈরি করেন। Devuan 1.0 May 2017-এ প্রকাশিত হয়।

ন্যায্যভাবে উপস্থাপিত আপত্তিগুলো

পরিধি। এখন একটি project PID 1, logging daemon, login session management, device manager, network configuration daemon, DNS (domain name system) resolver, NTP (network time protocol) client, container runner এবং boot loader প্রকাশ করে। এগুলো আলাদা binary, আপনাকে সবগুলো install করতে হয় না—এই প্রচলিত যুক্তিটি সত্য, কিন্তু আপত্তির উত্তর দেয় না। কোনো desktop-এর logind প্রয়োজন হলে এবং logind systemd-এর tree থেকে আলাদাভাবে release করা হলে, পছন্দ আর স্বাধীন থাকে না। যুক্তিতে coupling বলতে এটাই বোঝানো হয়েছিল, এবং সেটিই ঘটেছে।

Binary journal। journald plain text-এর পরিবর্তে একটি indexed binary format-এ লেখে। এতে এমন সুবিধা পাওয়া যায় যা text কখনও দেয়নি: per-unit ও per-priority filtering, structured field, এবং এমন metadata যা sending program জাল করতে পারে না, কারণ journald নিজেই unit ও cgroup রেকর্ড করে। journalctl -u nginx -p err --since "-1h"-এ grep-এর পরিবর্তে একটি date regular expression ব্যবহার করা হয়। এর খরচও বাস্তব। যে machine boot হবে না, সেখানে rescue shell থেকে less ব্যবহার করে log পড়তে পারবেন না। এর পরিবর্তে mounted disk-টি journalctl-কে দেখান:

sudo journalctl --directory /mnt/var/log/journal --boot -1 --priority err

এখানে আরেকটি সমস্যা আছে, যা মানুষ সাধারণত একবার বিপদে পড়ার পর বুঝতে পারে। /var/log/journal না থাকলে journald log /run/log/journal-এ রাখে, আর সেটি memory। এমন machine-এ reboot-এর পরে journalctl -b -1 দেখানোর মতো কিছু পায় না, অথচ ঠিক তখনই log-টি আপনার প্রয়োজন হয়। পরীক্ষা করে ঠিক করুন:

journalctl --disk-usage
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

journalctl --disk-usage এখন /var/log/journal-এর অধীনে archived journal দেখানো উচিত। plain text-ও চাইলে /etc/systemd/journald.conf-এ ForwardToSyslog=yes সেট করুন এবং rsyslog installed রাখুন।

Boot-এর debugging। কোনো unit hang করলে console-এ একটি line দেখা যায়, আর কিছু নয়:

[  *** ] A start job is running for Wait for Network to be Configured (1min 32s / no limit)

আরও তদন্তের tool আছে: আটকে থাকা অবস্থায় systemctl list-jobs, পরে systemd-analyze blame এবং systemd-analyze critical-chain, আর kernel command line-এ systemd.log_level=debug। আপত্তিটির ন্যায্য রূপ হলো, sh জানা যে কোনো administrator একটি init script শুরু থেকে শেষ পর্যন্ত পড়তে পারতেন। কিন্তু আটকে থাকা unit বিশ্লেষণ করতে হলে কোন পরিস্থিতিতে কোন dozen command ব্যবহার করতে হবে, তা জানতে হয়। এটি বাস্তব খরচ। প্রত্যেক administrator-এর জন্য এই খরচ একবার করে হয়েছে, এবং একই সময়ে অনেক administrator-কে এটি বহন করতে হয়েছে।

সবার জন্য পরিবর্তিত একটি default। 2016 সালে systemd 230 logind-এর default পরিবর্তন করে, যাতে logout-এর সময় অবশিষ্ট user process-গুলো kill করা হয়। Detached tmux এবং screen session, যে session এগুলো শুরু করেছিল সেটি শেষ হলে বন্ধ হয়ে যায়। Distribution-গুলো KillUserProcesses=no-কে /etc/systemd/logind.conf-এ ship করে, এবং supported উত্তর হলো loginctl enable-linger <user>। একটি project-এর একটি default, লক্ষ লক্ষ মানুষের ওপর নির্ভরশীল একটি অভ্যাস বদলে দিয়েছিল। বাস্তবে “userland-এর অতিরিক্ত অংশ এক জায়গায় থাকা” বলতে এটাই বোঝায়।

একটি default dependency একটি security surface। March 2024-এ xz-utils-এর backdoor Debian ও Ubuntu-র sshd-কে target করেছিল। Upstream OpenSSH libsystemd-এর সঙ্গে link করে না। এই distribution-গুলো sshd যেন systemd-কে readiness জানাতে পারে, সে জন্য patch করে libsystemd যুক্ত করেছিল। libsystemd-এর মাধ্যমে liblzma যুক্ত হয়, আর backdoor-টি সেখানেই ছিল। Readiness protocol নিজেই $NOTIFY_SOCKET-এ নাম দেওয়া socket-এ পাঠানো একটি single datagram। তাই এর জন্য কোনো library কখনও প্রয়োজন ছিল না। systemd-এর প্রতিক্রিয়া ছিল dlopen দিয়ে compression library load করা, যাতে সেগুলো আর default-ভাবে link-in না হয়। একই ধরনের bug-এর আরেকটি উদাহরণ একই চিত্র দেখায়: 2017 সালে digit দিয়ে শুরু হওয়া একটি User= value-কে invalid হিসেবে গণ্য করা হয়েছিল এবং unit fail না করে root হিসেবে চলেছিল। ফলে একটি typo privilege escalation-এ পরিণত হয়। পরবর্তী version-গুলো unit start করতে অস্বীকার করে।

নিজের systemctl prompt-এ ইতিহাস

উপরের প্রতিটি সমস্যা এখন এমন একটি ফাইলে থাকা একটি directive, যা আপনি পড়তে পারেন।

  • Serial boot এখন After= এবং Wants= হয়েছে, আর systemd-analyze critical-chain দেখায় আসলে কোন বিষয়টি boot আটকে রেখেছিল।
  • Readiness এখন Type=notify; service প্রস্তুত হলে সেখানে READY=1 লিখে $NOTIFY_SOCKET। পুরোনো daemon-এর জন্য PIDFile=-সহ Type=forking এখনও আছে। PID file কখনও তৈরি না হলে এই type-ই start operation timed out. Terminating.-এ ব্যর্থ হয়। ভুলটি বেছে নিলে unit active দেখাতে পারে, যদিও সেটি শুরু করা daemon ইতিমধ্যে বন্ধ হয়ে গেছে। তাই ওই line লেখার আগে আপনার daemon যেভাবে শুরু হয়, তার সঙ্গে কোন Type= মেলে তা জানা গুরুত্বপূর্ণ।
  • Supervision এখন cgroup-এর মাধ্যমে হয়। তাই RestartSec=-সহ Restart=on-failure wrapper script-এর বদলে ব্যবহার করা যায়, আর StartLimitBurst= crash loop-কে অনন্তকাল চলতে বাধা দেয়।
  • inetd এখন .service unit-এর পাশে থাকা একটি .socket unit।
  • ulimit এখন MemoryMax=, CPUQuota= এবং TasksMax= হয়েছে।
  • init script-এর su - appuser -c line এখন User=, NoNewPrivileges=yes এবং ProtectSystem=strict হয়েছে। তাই unprivileged user হিসেবে service চালানো 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

ওই ফাইলের একটি line এমন ভুল, যা সবাই একবার করে। Requires=postgresql.service একটি requirement, ordering নয়। এর অর্থ হলো Postgres ব্যর্থ হলে আপনার unit-ও ব্যর্থ হবে। এর অর্থ Postgres আগে start করতে হবে না। After=postgresql.service না থাকলে দুটিই একই সময়ে start হয়, এবং আপনার service এমন একটি port-এ সংযোগ করার চেষ্টা করে যেখানে তখনও কোনো কিছু listening করছে না। দুটিকে ইচ্ছাকৃতভাবে আলাদা রাখা হয়েছে, কারণ কখনও আপনি একটির প্রয়োজন অনুভব করতে পারেন, অন্যটির নয়। ProtectSystem=strict এই service-এর জন্য file system read-only হিসেবে mount করে। তাই StateDirectory= রাখা হয়েছে: এটি service-কে /var/lib-এর অধীনে একটি writable path দেয়।

2026 সালের server-এ 2005 সালের নকশা সবচেয়ে স্পষ্টভাবে দেখা যায় Ubuntu 24.04-এর SSH-এ; August 2026 অনুযায়ী এতে systemd 255 প্রকাশিত হয়। ssh.service default হিসেবে socket activated। ssh.socket listening socket ধরে রাখে, এবং connection এলে sshd start হয়। তাই /etc/ssh/sshd_config-এর Port 2222-এর কোনো প্রভাব নেই, কারণ port খুলেছে sshd process নয়। পরিবর্তনটি socket unit-এ করতে হবে।

sudo systemctl edit ssh.socket
[Socket]
ListenStream=
ListenStream=2222

খালি ListenStream= packaged unit থেকে inherited value মুছে দেয়। এটি বাদ দিলে দুইটি port-ই পাবেন, কারণ systemd list প্রতিস্থাপন না করে তাতে যোগ করে। এরপর apply করে পরীক্ষা করুন। পুরো সময় একটি দ্বিতীয় SSH session খোলা রাখুন:

sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
sudo ss -lntp | grep 2222

ss-এ port 2222-এ একটি socket দেখা উচিত, যার মালিক systemd; sshd নয়। আপনার VPS-এ বিশ বছর পরে এটিই launchd-এর নকশা। পুরোনো আচরণ চাইলে sudo systemctl disable --now ssh.socket-এর পরে sudo systemctl enable --now ssh.service চালান। এতে দীর্ঘক্ষণ চলা sshd তৈরি হবে, যা আবার নিজের config থেকে Port পড়বে।

আপনি কোন বিষয়গুলোর মুখোমুখি হবেন, তা আপনার ব্যবহৃত release-এর ওপর নির্ভর করে। তাই upgrade পরিকল্পনার আগে LTS এবং interim Ubuntu release-এর পার্থক্য জানা উপকারী। একাধিক machine-এ unit file সর্বত্র একই থাকার কারণেই একটি স্থান থেকে একাধিক server পরিচালনা করা এখন configuration সমস্যা, shell scripting সমস্যা নয়। নিজের unit লেখার সময় service এবং timer-এর জোড়া 2009 সালে init script এবং cron line দিয়ে যে কাজ ভাগ করে করতে হতো, সেটিই সম্পন্ন করে।

FAQ

Linux distribution-গুলো SysV init-এর পরিবর্তে systemd কেন ব্যবহার শুরু করল?

এর পেছনে দুটি engineering কারণ এবং একটি maintenance কারণ ছিল। SysV init filename অনুযায়ী service-এর ক্রম নির্ধারণ করত। এটি dependency নয়, শুধু অবস্থান নির্দেশ করত। কোনো daemon parent process থেকে fork হয়ে আলাদা হলে SysV init সেটির tracking হারিয়ে ফেলত। এ কারণেই পুরোনো PID file ভুল process বন্ধ করে দিতে পারত। systemd socket activation এবং dependency directive ব্যবহার করে ordering সমস্যার সমাধান করেছে। Control group ব্যবহার করে tracking সমস্যারও সমাধান করেছে। Maintenance কারণটি adoption-এর গতি নির্ধারণ করেছে: প্রতিটি distribution-এ একই unit file কাজ করে। তাই upstream project-গুলো একটি .service file ship করত, এবং distribution maintainer-রা প্রতিটি package-এর জন্য আলাদা shell script লেখা বন্ধ করে। Fedora 15 May 2011-এ systemd-এ বদলায়। Ubuntu 15.04 April 2015-এ বড় distribution-গুলোর মধ্যে সর্বশেষ holdout ছিল।

systemd কি একটি বিশাল binary?

না। Source tree থেকে অনেকগুলো আলাদা program build হয়। PID 1 হলো /usr/lib/systemd/systemd। journald, logind এবং udevd নিজস্ব binary-সহ আলাদা process হিসেবে চলে। নিজের system-এ এগুলো দেখতে ls /usr/lib/systemd/ চালান। যে সমালোচনাটি এখনও আছে, তা binary size নিয়ে নয়; release coupling নিয়ে। এই program-গুলো একসঙ্গে release হয় এবং private interface share করে। তাই distribution-গুলো সাধারণত এগুলোকে একটি set হিসেবে গ্রহণ করে। GNOME-এর মতো software-ও নির্দিষ্টভাবে logind প্রত্যাশা করতে শুরু করে।

systemd ছাড়া কি Linux চালানো যায়?

হ্যাঁ। Devuan sysvinit ship করে, Gentoo-তে default হলো OpenRC, Void runit ব্যবহার করে, Alpine OpenRC-সহ busybox init ব্যবহার করে, এবং Slackware BSD style script বজায় রাখে। এর খরচ হলো compatibility work। logind প্রত্যাশা করা desktop software-এর জন্য elogind প্রয়োজন। এটি systemd-এর logind, standalone package হিসেবে রক্ষণাবেক্ষণ করা হয়। এছাড়া ক্রমবর্ধমান সংখ্যক server software এখন শুধু একটি .service file ship করে। তাই startup script আপনাকেই লিখে রক্ষণাবেক্ষণ করতে হবে।

journal plain text file-এর পরিবর্তে binary কেন?

কারণ journald একটি index-সহ structured field সংরক্ষণ করে। এর ফলে per-unit filtering, priority filtering এবং এমন metadata পাওয়া যায় যা log পাঠানো program জাল করতে পারে না। journald নিজেই unit, cgroup এবং প্রকৃত UID record করে। এটি log line-এর ওপর নির্ভর করে না। এর বিনিময়ে এটি পড়তে journalctl প্রয়োজন। Rescue system থেকেও এটি প্রয়োজন হবে। সেখানে mounted disk-টি journalctl --directory /mnt/var/log/journal দিয়ে নির্দিষ্ট করতে হয়। Text format-ও চাইলে ForwardToSyslog=yes-এ /etc/systemd/journald.conf সেট করুন।

আমার /etc/init.d script edit করার পরিবর্তে কী ব্যবহার করব?

Drop-in file ব্যবহার করুন। /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 merged result দেখায়। systemd-delta machine-এর সব override তালিকাভুক্ত করে। হাতে কোনো edit করার পরে sudo systemctl daemon-reload চালান। তা না হলে পরের command Warning: The unit file, source configuration file or drop-ins of nginx.service changed on disk. print করবে।

#systemd#linux#init#sysvinit#history