Init System เป็นโปรแกรมแรกที่ถูกเรียกใช้งานโดย Linux kernel หลังจากที่ระบบบูตเสร็จสิ้น มีหน้าที่หลักดังนี้:
%%{init: {'theme':'base', 'themeVariables': {'primaryTextColor':'#000000', 'secondaryTextColor':'#000000', 'tertiaryTextColor':'#000000', 'fontSize':'16px'}}}%%
timeline
title Timeline ของ Init System ของ Linux
1983 : SysV init
: System V Unix init
: ระบบ init แบบดั้งเดิม
1991 : Linux เกิดขึ้น
: ใช้ SysV init style
2001 : daemontools
: runit เริ่มพัฒนา
: ทางเลือกสำหรับ SysV
2006 : Upstart
: พัฒนาโดย Canonical (Ubuntu)
: Event-based init
: แทนที่ SysV ใน Ubuntu
2007 : OpenRC
: พัฒนาโดย Gentoo
: Dependency-based init
2010 : systemd เริ่มต้น
: พัฒนาโดย Lennart Poettering
: ประกาศโครงการ
2011 : systemd v1.0
: Fedora 15 นำมาใช้
2012 : systemd แพร่หลาย
: Arch Linux นำมาใช้
: openSUSE นำมาใช้
2014 : Debian ใช้ systemd
: การโหวตเลือก systemd
: Ubuntu เปลี่ยนมาใช้ systemd
2015 : systemd กลายเป็น standard
: ใช้ใน distro ส่วนใหญ่
: RHEL 7 ใช้ systemd
2016-ปัจจุบัน : systemd ครองตลาด
: ใช้ใน major distros เกือบทั้งหมด
: OpenRC, runit ยังมีใน niche distros
: Gentoo, Void Linux ใช้ทางเลือกอื่น
OpenRC เป็น dependency-based init system ที่พัฒนาโดยชุมชน Gentoo Linux เริ่มต้นในปี 2007 โดยมีจุดประสงค์เพื่อปรับปรุง init scripts ของ Gentoo ให้มีความยืดหยุ่นและจัดการ dependencies ได้ดีขึ้น
graph TB
A[Linux Kernel] --> B[OpenRC PID 1]
B --> C[rc-service]
B --> D[openrc-run]
B --> E[openrc-init]
C --> F[/etc/init.d/]
D --> G[Service Scripts]
E --> H[Boot Process]
F --> I[Individual Services]
G --> I
H --> J[Runlevels]
J --> K[boot]
J --> L[default]
J --> M[shutdown]
style B fill:#f9f,stroke:#333,stroke-width:4px
style C fill:#bbf,stroke:#333,stroke-width:2px
style D fill:#bbf,stroke:#333,stroke-width:2px
style E fill:#bbf,stroke:#333,stroke-width:2px
| คุณสมบัติ | OpenRC | systemd | SysVinit | runit |
|---|---|---|---|---|
| ปีที่เริ่มพัฒนา | 2007 | 2010 | 1983 | 2004 |
| ภาษาที่ใช้เขียน | Shell Script | C | Shell Script | C |
| Dependency Management | ✅ มี | ✅ มี | ❌ ไม่มี | ⚠️ จำกัด |
| Parallel Startup | ✅ มี | ✅ มี | ❌ ไม่มี | ✅ มี |
| ขนาดโค้ด | ~20K SLOC | ~1.3M SLOC | ~5K SLOC | ~3K SLOC |
| ความซับซ้อน | ต่ำ-ปานกลาง | สูง | ต่ำ | ต่ำมาก |
| Cross-platform | ✅ Linux, BSD | ❌ Linux only | ✅ Unix-like | ✅ Unix-like |
| Configuration Format | Shell Scripts | Unit Files | Shell Scripts | Directory-based |
| Service Supervision | ⚠️ จำกัด | ✅ มี | ❌ ไม่มี | ✅ มี |
| Socket Activation | ❌ ไม่มี | ✅ มี | ❌ ไม่มี | ❌ ไม่มี |
| Logging | syslog/logger | journald | syslog | svlogd |
| Timer Support | ⚠️ ใช้ cron | ✅ มี (timers) | ⚠️ ใช้ cron | ⚠️ ใช้ cron |
ข้อดี:
ข้อเสีย:
ข้อดี:
ข้อเสีย:
ข้อดี:
ข้อเสีย:
ข้อดี:
ข้อเสีย:
# OpenRC มาพร้อมกับ Gentoo อยู่แล้ว
emerge --ask sys-apps/openrc
# Alpine ใช้ OpenRC เป็นค่าเริ่มต้น
apk add openrc
# ติดตั้ง OpenRC package
pacman -S openrc openrc-system
# ใน Artix Linux
# 1. ติดตั้ง OpenRC
pacman -S openrc-system
# 2. ลบ systemd
pacman -Rdd systemd
# 3. ติดตั้ง OpenRC init
pacman -S openrc openrc-init
# 4. รีบูตระบบ
reboot
/etc/init.d/ # Service scripts
/etc/conf.d/ # Service configuration files
/etc/runlevels/ # Runlevel configurations
├── boot/ # Services for boot runlevel
├── default/ # Services for default runlevel
├── shutdown/ # Services for shutdown
└── sysinit/ # System initialization
/etc/rc.conf # Global OpenRC configuration
/lib/rc/ # OpenRC library files
/var/log/rc.log # OpenRC log file
graph TD
A[Kernel Loaded] --> B[OpenRC Init PID 1]
B --> C[sysinit Runlevel]
C --> C1[devfs - Mount /dev]
C --> C2[dmesg - Kernel messages]
C --> C3[udev/mdev - Device management]
C1 --> D[boot Runlevel]
C2 --> D
C3 --> D
D --> D1[fsck - File system check]
D --> D2[root - Mount root filesystem]
D --> D3[localmount - Mount local filesystems]
D --> D4[hostname - Set hostname]
D --> D5[networking - Network initialization]
D1 --> E[default Runlevel]
D2 --> E
D3 --> E
D4 --> E
D5 --> E
E --> E1[sshd - SSH daemon]
E --> E2[cronie - Cron daemon]
E --> E3[nginx - Web server]
E --> E4[Custom Services]
E1 --> F[System Ready]
E2 --> F
E3 --> F
E4 --> F
style B fill:#f96,stroke:#333,stroke-width:4px
style C fill:#ff9,stroke:#333,stroke-width:2px
style D fill:#9f9,stroke:#333,stroke-width:2px
style E fill:#9ff,stroke:#333,stroke-width:2px
style F fill:#f9f,stroke:#333,stroke-width:4px
# ดูสถานะของ service เดียว
rc-service sshd status
# ดูสถานะทั้งหมด
rc-status
# ดูสถานะแบบละเอียด
rc-status -v
# ดูสถานะ service ใน runlevel เฉพาะ
rc-status default
# เริ่ม service
rc-service nginx start
# หยุด service
rc-service nginx stop
# รีสตาร์ท service
rc-service nginx restart
# โหลดการตั้งค่าใหม่
rc-service nginx reload
# ตรวจสอบ configuration
rc-service nginx checkconfig
# เพิ่ม service ไปยัง default runlevel
rc-update add nginx default
# ลบ service จาก runlevel
rc-update del nginx default
# ดูรายการ services ใน runlevels
rc-update show
# ดูรายการ services ทั้งหมดที่มี
rc-update show -v
# เปลี่ยน runlevel
openrc default
# รีบูตระบบ
openrc reboot
# ปิดระบบ
openrc shutdown
# ดู runlevel ปัจจุบัน
rc-status --runlevel
# อัปเดต dependency cache
rc-update -u
# Dry-run การเปลี่ยนแปลง
rc-update add nginx default --dry-run
# แสดง dependencies ของ service
rc-service --ifexists --ifstopped sshd start --nodeps
# Debug service
rc-service nginx start --debug
Service script ใน OpenRC เป็น shell script ที่มีโครงสร้างเฉพาะ มาดูตัวอย่างกัน
สร้างไฟล์ /etc/init.d/myapp
#!/sbin/openrc-run
# Copyright 2025 Your Name
# Distributed under the terms of the GNU General Public License v2
description="My Custom Application"
command="/usr/bin/myapp"
command_args="${myapp_args:---config /etc/myapp/config.conf}"
pidfile="/run/myapp.pid"
command_background=true
depend() {
need net
use logger dns
after firewall
}
start_pre() {
# ตรวจสอบว่า config file มีอยู่
if [ ! -f /etc/myapp/config.conf ]; then
eerror "Configuration file not found!"
return 1
fi
# สร้าง directories ที่จำเป็น
checkpath --directory --mode 0755 --owner myapp:myapp /var/log/myapp
checkpath --directory --mode 0755 --owner myapp:myapp /var/run/myapp
}
start_post() {
einfo "MyApp started successfully"
}
stop_post() {
einfo "Cleaning up..."
rm -f /var/run/myapp/*.tmp
}
สร้างไฟล์ configuration /etc/conf.d/myapp
# Configuration for myapp
# Command line arguments
myapp_args="--config /etc/myapp/config.conf --verbose"
# User and group
myapp_user="myapp"
myapp_group="myapp"
# Resource limits
rc_ulimit="-n 4096"
สร้างไฟล์ /etc/init.d/webapp
#!/sbin/openrc-run
# Web Application Service
description="My Web Application"
description_reload="Reload configuration"
description_checkconfig="Check configuration"
command="/usr/bin/node"
command_args="/opt/webapp/server.js"
command_user="webapp:webapp"
command_background=true
pidfile="/run/webapp.pid"
# Output redirection
output_log="/var/log/webapp/output.log"
error_log="/var/log/webapp/error.log"
# Respawn if crashed
supervisor="supervise-daemon"
respawn_delay=5
respawn_max=5
respawn_period=60
depend() {
need net localmount
use dns logger mysql postgresql redis
after firewall nginx
provide web-app
}
start_pre() {
# ตรวจสอบ Node.js
if ! command -v node >/dev/null 2>&1; then
eerror "Node.js is not installed"
return 1
fi
# ตรวจสอบ application files
if [ ! -f /opt/webapp/server.js ]; then
eerror "Application files not found"
return 1
fi
# สร้าง directories
checkpath --directory --mode 0755 --owner webapp:webapp /var/log/webapp
checkpath --directory --mode 0755 --owner webapp:webapp /run/webapp
checkpath --directory --mode 0755 --owner webapp:webapp /opt/webapp/tmp
# ล้าง temp files
rm -rf /opt/webapp/tmp/*
einfo "Starting web application..."
}
checkconfig() {
# ตรวจสอบ syntax ของ config
/usr/bin/node /opt/webapp/check-config.js
return $?
}
reload() {
ebegin "Reloading webapp configuration"
if [ ! -f "${pidfile}" ]; then
eerror "webapp is not running"
return 1
fi
# ส่ง SIGHUP เพื่อโหลด config ใหม่
kill -HUP $(cat ${pidfile})
eend $?
}
stop_post() {
# Cleanup
einfo "Cleaning up temporary files..."
rm -rf /opt/webapp/tmp/*
rm -f /run/webapp/*.sock
}
Configuration file /etc/conf.d/webapp
# Web Application Configuration
# Environment variables
export NODE_ENV="production"
export PORT="3000"
export DATABASE_URL="postgresql://localhost/webapp"
# Resource limits
rc_ulimit="-n 8192" # Max open files
# Nice level
rc_nice="-10"
สร้างไฟล์ /etc/init.d/worker
#!/sbin/openrc-run
# Background Worker Service - supports multiple instances
instance="${RC_SVCNAME#worker.}"
description="Background Worker ${instance}"
if [ "${instance}" = "worker" ]; then
instance="default"
fi
command="/usr/bin/python3"
command_args="/opt/workers/worker.py --instance ${instance}"
command_user="worker:worker"
command_background=true
pidfile="/run/worker.${instance}.pid"
output_log="/var/log/worker/worker.${instance}.log"
error_log="/var/log/worker/worker.${instance}.error.log"
supervisor="supervise-daemon"
respawn_delay=10
respawn_max=3
respawn_period=300
depend() {
need net
use logger redis rabbitmq
after postgresql
}
start_pre() {
# ตรวจสอบ Python
if ! command -v python3 >/dev/null 2>&1; then
eerror "Python 3 is not installed"
return 1
fi
# สร้าง directories
checkpath --directory --mode 0755 --owner worker:worker /var/log/worker
checkpath --directory --mode 0755 --owner worker:worker /run/worker
# โหลด configuration สำหรับ instance นี้
if [ -f "/etc/worker/worker.${instance}.conf" ]; then
. "/etc/worker/worker.${instance}.conf"
export WORKER_CONFIG="/etc/worker/worker.${instance}.conf"
else
ewarn "No specific configuration found for instance ${instance}"
ewarn "Using default configuration"
fi
einfo "Starting worker instance: ${instance}"
}
stop_pre() {
einfo "Stopping worker instance: ${instance}"
}
การใช้งาน multiple instances:
# สร้าง symlinks สำหรับแต่ละ instance
ln -s /etc/init.d/worker /etc/init.d/worker.email
ln -s /etc/init.d/worker /etc/init.d/worker.image
ln -s /etc/init.d/worker /etc/init.d/worker.video
# เพิ่มไปยัง runlevel
rc-update add worker.email default
rc-update add worker.image default
rc-update add worker.video default
# จัดการแต่ละ instance
rc-service worker.email start
rc-service worker.image start
rc-service worker.video start
สร้างไฟล์ /etc/init.d/api-server
#!/sbin/openrc-run
# API Server with Health Check
description="API Server with health monitoring"
description_healthcheck="Check service health"
command="/usr/bin/api-server"
command_args="--port ${API_PORT:-8080}"
command_user="apiserver:apiserver"
command_background=true
pidfile="/run/api-server.pid"
supervisor="supervise-daemon"
healthcheck_delay=30
healthcheck_timer=60
depend() {
need net
use dns logger postgresql redis
after firewall
}
start_pre() {
checkpath --directory --mode 0755 --owner apiserver:apiserver /var/log/api-server
checkpath --directory --mode 0755 --owner apiserver:apiserver /run/api-server
# ตรวจสอบ database connection
einfo "Checking database connection..."
if ! su -s /bin/sh apiserver -c "psql ${DATABASE_URL} -c 'SELECT 1' >/dev/null 2>&1"; then
eerror "Cannot connect to database"
return 1
fi
}
healthcheck() {
ebegin "Checking API server health"
# ตรวจสอบว่า process ยังทำงานอยู่
if [ ! -f "${pidfile}" ]; then
eend 1 "PID file not found"
return 1
fi
local pid=$(cat "${pidfile}")
if ! kill -0 ${pid} 2>/dev/null; then
eend 1 "Process is not running"
return 1
fi
# ตรวจสอบ health endpoint
local health_url="http://localhost:${API_PORT:-8080}/health"
local response=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "${health_url}" 2>/dev/null)
if [ "${response}" = "200" ]; then
eend 0 "Health check passed"
return 0
else
eend 1 "Health check failed (HTTP ${response})"
# Auto-restart if health check fails
if [ "${AUTO_RESTART:-yes}" = "yes" ]; then
ewarn "Auto-restarting service..."
rc-service api-server restart
fi
return 1
fi
}
stop_post() {
# Graceful shutdown - wait for connections to close
einfo "Waiting for connections to close..."
local wait_time=0
local max_wait=30
while [ ${wait_time} -lt ${max_wait} ]; do
if ! netstat -an | grep -q ":${API_PORT:-8080}.*ESTABLISHED"; then
einfo "All connections closed"
break
fi
sleep 1
wait_time=$((wait_time + 1))
done
if [ ${wait_time} -ge ${max_wait} ]; then
ewarn "Timeout waiting for connections"
fi
}
depend() {
# need: service ที่จำเป็นต้องทำงานก่อน (hard dependency)
need net localmount
# use: service ที่ควรทำงานก่อนถ้ามี (soft dependency)
use dns logger
# want: เหมือน use แต่ไม่ warning ถ้าไม่มี
want bluetooth
# after: ทำงานหลังจาก service นี้ (order dependency)
after firewall postgresql
# before: ทำงานก่อน service นี้
before nginx apache2
# provide: ประกาศว่า service นี้ให้บริการอะไร
provide database
# keyword: platform-specific directives
keyword -docker -lxc -openvz -prefix -systemd-nspawn -uml -vserver -xenu
}
graph LR
A[localmount] --> B[postgresql]
A --> C[mysql]
D[net] --> B
D --> C
D --> E[redis]
B --> F[webapp]
C --> F
E --> F
G[nginx] --> H[System Ready]
F --> G
style A fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#ff9,stroke:#333,stroke-width:2px
style C fill:#ff9,stroke:#333,stroke-width:2px
style E fill:#ff9,stroke:#333,stroke-width:2px
style F fill:#9f9,stroke:#333,stroke-width:2px
style G fill:#9ff,stroke:#333,stroke-width:2px
style H fill:#f96,stroke:#333,stroke-width:4px
# Global OpenRC Configuration
# ระบบ
rc_parallel="YES" # เปิดใช้ parallel startup
rc_logger="YES" # บันทึก log
rc_log_path="/var/log/rc.log" # ตำแหน่งไฟล์ log
# Network
rc_hotplug="YES" # รองรับ hotplug devices
rc_depend_strict="YES" # strict dependency checking
# Shell
rc_shell=/bin/sh # Shell ที่ใช้
# Startup/Shutdown
rc_send_sighup="NO" # ส่ง SIGHUP เมื่อ reload
rc_send_sigterm="NO" # ส่ง SIGTERM เมื่อ stop
rc_timeout_stopsec=90 # Timeout สำหรับการ stop (วินาที)
# TTY
unicode="YES" # รองรับ UTF-8
rc_tty_number=12 # จำนวน TTY ที่สร้าง
# 1. ติดตั้ง packages
apk add nginx postgresql php-fpm
# 2. เตรียม services
rc-service postgresql setup
# 3. เพิ่ม services ไปยัง default runlevel
rc-update add nginx default
rc-update add postgresql default
rc-update add php-fpm default
# 4. เริ่มต้น services
rc-service postgresql start
rc-service php-fpm start
rc-service nginx start
# 5. ตรวจสอบสถานะ
rc-status
สร้างไฟล์ /etc/init.d/devenv
#!/sbin/openrc-run
description="Development Environment Setup"
depend() {
need localmount net
after docker postgresql redis
}
start() {
ebegin "Starting development environment"
# เริ่ม database containers
docker start dev-postgres dev-redis dev-mongo
# รอให้ databases พร้อม
sleep 5
# เริ่ม development servers
su - developer -c "cd /home/developer/project && npm run dev &"
eend $?
}
stop() {
ebegin "Stopping development environment"
# หยุด development servers
pkill -f "npm run dev"
# หยุด containers
docker stop dev-postgres dev-redis dev-mongo
eend $?
}
สร้างไฟล์ /etc/init.d/backup-service
#!/sbin/openrc-run
description="Automated Backup Service"
command="/usr/local/bin/backup-daemon"
command_background=true
pidfile="/run/backup-service.pid"
depend() {
need localmount net
use logger
after postgresql mysql
}
start_pre() {
# ตรวจสอบพื้นที่
local available=$(df /backup | tail -1 | awk '{print $4}')
local required=10485760 # 10GB in KB
if [ ${available} -lt ${required} ]; then
eerror "Insufficient disk space for backups"
eerror "Available: ${available}KB, Required: ${required}KB"
return 1
fi
checkpath --directory --mode 0700 --owner root:root /backup
einfo "Backup location ready: /backup"
}
สร้างไฟล์ /etc/init.d/monitor
#!/sbin/openrc-run
description="System Monitoring Service"
description_status="Show monitoring status"
command="/usr/local/bin/monitor-daemon"
command_args="--config /etc/monitor/config.yaml"
command_background=true
pidfile="/run/monitor.pid"
command_user="monitor:monitor"
retry="TERM/30/KILL/5"
depend() {
need net
use logger dns
}
start_pre() {
checkpath --directory --mode 0755 --owner monitor:monitor /var/log/monitor
checkpath --directory --mode 0755 --owner monitor:monitor /var/lib/monitor
# ตรวจสอบ configuration
/usr/local/bin/monitor-daemon --config /etc/monitor/config.yaml --check-config
local ret=$?
if [ ${ret} -ne 0 ]; then
eerror "Configuration validation failed"
return 1
fi
}
extra_started_commands="status"
status() {
einfo "Monitoring Service Status:"
/usr/local/bin/monitor-ctl status
}
# เปิด verbose logging
RC_DEBUG=yes rc-service myservice start
# ดู log file
tail -f /var/log/rc.log
# Debug dependency
rc-service myservice start --nodeps
# ตรวจสอบ syntax ของ init script
sh -n /etc/init.d/myservice
# ทดสอบ start_pre function
. /etc/init.d/myservice
start_pre
# ตรวจสอบ dependencies
rc-service --debug myservice start
# ตรวจสอบ log
grep myservice /var/log/rc.log
# ตรวจสอบ permissions
ls -l /etc/init.d/myservice
ls -l /run/myservice.pid
# ตรวจสอบ startup time
time rc-service myservice start
# ดู dependencies ที่ทำให้ช้า
rc-service --ifexists --debug myservice start
# พิจารณาเปลี่ยน 'need' เป็น 'use' ถ้าเป็นไปได้
# อัปเดต dependency cache
rc-update -u
# ตรวจสอบ circular dependencies
rc-depend --show myservice
# ลบ dependency cache และสร้างใหม่
rm -rf /lib/rc/cache
rc-update -u
# ดู service dependencies
rc-depend --depend myservice
# ดู services ที่ขึ้นกับ service นี้
rc-depend --depend myservice --rev
# ตรวจสอบ runlevel configuration
rc-status --all
# ดู crashed services
rc-status --crashed
# ทดสอบ service script
sh -x /etc/init.d/myservice start
# 1. เปิด parallel startup
echo 'rc_parallel="YES"' >> /etc/rc.conf
# 2. ลด timeout
echo 'rc_timeout_stopsec=30' >> /etc/rc.conf
# 3. ใช้ use แทน need เมื่อเป็นไปได้
# ใน /etc/init.d/myservice
depend() {
use logger dns # แทนที่ need
}
# 4. ลบ services ที่ไม่จำเป็น
rc-update del service-name default
สร้างสคริปต์ /usr/local/bin/boot-time.sh
#!/bin/sh
# แสดงเวลาในการ boot แต่ละ service
grep -E "Starting|Started" /var/log/rc.log | \
while read line; do
echo "$line"
done | \
awk '{
if ($3 == "Starting") {
start[$4] = $1" "$2
} else if ($3 == "Started") {
if (start[$4]) {
print $4, "took:", $1" "$2, "-", start[$4]
}
}
}'
checkpath สำหรับสร้าง directoriesstart_pre()command_background=true สำหรับ daemonspidfile อย่างชัดเจนsupervise-daemon สำหรับ process supervisionstop_post()need สำหรับ hard dependenciesuse สำหรับ optional dependenciesafter สำหรับ orderingneed มากเกินไป# ใน init script
command_user="service-user:service-group" # อย่าใช้ root
umask 027 # กำหนด default permissions
# ใน start_pre()
checkpath --directory --mode 0750 --owner user:group /var/lib/service
# เปิด logging
rc_logger="YES"
# ใช้ output redirection
output_log="/var/log/service/output.log"
error_log="/var/log/service/error.log"
# Log rotation - ใน /etc/logrotate.d/service
/var/log/service/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
}
OpenRC เป็น init system ที่มีความยืดหยุ่นและมีประสิทธิภาพ เหมาะสำหรับผู้ที่:
✅ Dependency-based startup
✅ Parallel service execution
✅ Shell script configuration
✅ Cross-platform (Linux/BSD)
✅ Service supervision (ด้วย supervise-daemon)
✅ ยืดหยุ่นและปรับแต่งได้ง่าย
⚠️ ไม่มี socket activation
⚠️ Service supervision จำกัดกว่า systemd
⚠️ Documentation น้อยกว่า
⚠️ Community เล็กกว่า
# OpenRC tools
rc-service # จัดการ services
rc-status # ดูสถานะ
rc-update # จัดการ runlevels
openrc-run # รัน init scripts
rc-depend # แสดง dependencies
# ยูทิลิตี้เสริม
openrc-init # PID 1 init system
supervise-daemon # Process supervisor
start-stop-daemon # Start/stop daemons