環境: Centos8
本文由 Justin-Zhang 原創, 轉載請註明出處!

啟動項匯總

定位到 /etc 目錄下, 我們可以發現在這個目錄下,至少有這幾個和啟動有關的文件(夾):

$ ls

cron.d/
cron.daily/
cron.deny/
cron.hourly/
cron.monthly/
cron.weekly/
crontab	

init.d/

inittab

profile.d/
profile

rc.d/
rc.local/
rc0.d/
rc1.d/
rc2.d/
rc3.d/
rc4.d/
rc5.d/
c6.d/	

反正我第一眼看到這張表是完全迷惑的.

那麼接下的博文, 就是要分別介紹, 上述的所有文件(夾).

功能介紹

crontab 組合

維基百科:

工具型软件cron是一款类Unix下的基于时间的任务管理系统。用户们可以通过cron在固定时间、日期、间隔下,运行定期任务(可以是命令和脚本)。cron常用于运维和管理,但也可用于其他地方,如:定期下载文件和邮件。cron该词来源于希腊语chronos(χρόνος),原意是时间。

文件位置

  • /var/spool/cron/ - 用戶層次
  • /etc/contab/etc/cron* - 系統層次

crontab 格式

# 文件格式說明
# ┌──分鐘(0 - 59)
# │ ┌──小時(0 - 23)
# │ │ ┌──日(1 - 31)
# │ │ │ ┌─月(1 - 12)
# │ │ │ │ ┌─星期(0 - 6,表示从周日到周六)
# │ │ │ │ │
# *  *  *  *  *  用户名 被執行的命令

管理方法

  • 直接編輯 /etc/crontab 文件
  • echo '指令' >> /etc/crontab
  • 使用 crontab -e 指令

crontab 和 cron.d

** Manpage(8): **

Like /etc/crontab, the files in the /etc/cron.d directory are monitored for changes. In general, the system administrator should not use /etc/cron.d/, but use the standard system crontab /etc/crontab.

/etc/crontab and the files in /etc/cron.d must be owned by root, and must not be group- or other-writable. In contrast to the spool area, the files under /etc/cron.d or the files under /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly and /etc/cron.monthly may also be symlinks, provided that both the symlink and the file it points to are owned by root. The files under /etc/cron.d do not need to be executable, while the files under /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly and /etc/cron.monthly do, as they are run by run-parts (see run-parts(8) for more information).

從文中我們可以獲取這麼一些信息:

  • 我們只需要使用 crontab 文件, 其餘的事情由系統管理
  • cron.d 和 其他的 cron* 文件夾都是放腳本用的, 準確說來, 是放符號連接
  • cron.dcron* 的區別是 放在 cron.d 目錄下的腳本必須可執行, 後者不需要

init.d

$ cat /etc/init.d/README

You are looking for the traditional init scripts in /etc/rc.d/init.d,
and they are gone?

Here's an explanation on what's going on:

You are running a systemd-based OS where traditional init scripts have
been replaced by native systemd services files. Service files provide
very similar functionality to init scripts. To make use of service
files simply invoke "systemctl", which will output a list of all
currently running services (and other units). Use "systemctl
list-unit-files" to get a listing of all known unit files, including
stopped, disabled and masked ones. Use "systemctl start
foobar.service" and "systemctl stop foobar.service" to start or stop a
service, respectively. For further details, please refer to
systemctl(1).

Note that traditional init scripts continue to function on a systemd
system. An init script /etc/rc.d/init.d/foobar is implicitly mapped
into a service unit foobar.service during system initialization.

Thank you!

Further reading:
        man:systemctl(1)
        man:systemd(1)
        http://0pointer.de/blog/projects/systemd-for-admins-3.html
        https://www.freedesktop.org/wiki/Software/systemd/Incompatibilities

上述陳述基本已經講清楚了情況:

  • 傳統的啟動腳本功能已經整合進了 systemd, 由 systemctl 程序提供給用戶操作
  • 現在的 /etc/init.d/ 其實是 /etc/rc.d/init.d/ 的符號鏈接
  • /etc/init.d/ 仍然可以藉由 systemd 提供的兼容正常工作

講清楚了這個, 下一個就是看 rc.d 文件夾掉內容了

rc 組合

rc 的意思是 “run command”, d 意味 “sub-directory”, 就是 /etc 下的字目錄的意思

首先要明確的一點是, 上述的 rc* 組合都是指向 /etc/rc.d/rc* 的符號鏈接, 因此我們只要研究 rc.d 文件夾內的結構就可以了. 這樣還不夠明確的話, 可以參考 ll 結果:

$ ll

drwxr-xr-x. 10 root  root     4096 Dec 18 07:31 rc.d
lrwxrwxrwx.  1 root  root       13 Dec 18 07:31 rc.local -> rc.d/rc.local
lrwxrwxrwx.  1 root  root       10 Aug  5  2020 rc0.d -> rc.d/rc0.d
lrwxrwxrwx.  1 root  root       10 Aug  5  2020 rc1.d -> rc.d/rc1.d
lrwxrwxrwx.  1 root  root       10 Aug  5  2020 rc2.d -> rc.d/rc2.d
lrwxrwxrwx.  1 root  root       10 Aug  5  2020 rc3.d -> rc.d/rc3.d
lrwxrwxrwx.  1 root  root       10 Aug  5  2020 rc4.d -> rc.d/rc4.d
lrwxrwxrwx.  1 root  root       10 Aug  5  2020 rc5.d -> rc.d/rc5.d
lrwxrwxrwx.  1 root  root       10 Aug  5  2020 rc6.d -> rc.d/rc6.d
lrwxrwxrwx.  1 root  root       11 Apr 27  2020 init.d -> rc.d/init.d

...

init.d 文件夾

如之前所述, 所有開機運行的腳本都放在 init.d 裡面,

$ ll

-rw-r--r--. 1 root root  1161 Dec 18 07:30 README
-rwxr-xr-x. 1 root root 10438 Jun 22  2018 bt
-rwxr-xr-x  1 root root  7039 Mar 29 21:37 fail2ban
-rw-r--r--. 1 root root 18434 Jul 24  2020 functions
-rwxr-xr-x  1 root root 10672 Mar 29 19:44 mysqld
-rwxr-xr-x  1 root root  2753 Dec  6  2018 nginx
-rwxr-xr-x  1 root root  2361 Mar 29 20:09 php-fpm-56
-rwxr-xr-x  1 root root  1447 Aug 17  2016 pure-ftpd

需要注意的是, init.d 僅僅是一個放腳本的地方, 要讓他開機啟動還是需要在 rc#.d 中調用到他的.

rc#.d 文件夾用途

  • 文件夾名稱中的數字, 代表了 run-level, 也就是 “運行級別”. 詳細的說明可以看 維基百科, 下面簡單的 copy 了維基百科的內容

    • 0: 停機, 關機
    • 1: 單用戶, 無網路鏈接, 無守護進程, 不允許 非超級用戶登陸 (僅root)
    • 2: 多用戶, 無網路鏈接, 無守護進程
    • 3: 多用戶, 正常啟動系統
    • 4: 用戶自定義
    • 5: 多用戶, 帶圖形介面
    • 6: 重啟

    在Debian上, 2-5 這四個運行級別都集中在 2上, 2也是系統默認的正常情況.
    現在在 systemd 體系中已經使用 target 來代替 runlevel, 如multi-user.target相当于init 3,graphical.target相当于init 5,但是 runlevel 仍然被 systemd 支持.

  • 舊版本可以使用 chkconfig 來配置不同的 runlevel 運行的服務.

  • init.d 不同, rc#.d 裡面不放腳本, 而是放對應到 init.d 中腳本的符號鏈接, 不同的名稱代表的含義不同. 比如說, “K” 開頭意思是 K 掉這個程序, “S” 開頭代表 開始這個程序. “K” 或者 “S” 後面的數字越小, 執行的優先級越高, 下面是我的樹莓派的配置:

    [root@RaspberryPi rc3.d]$ ll
    
    lrwxrwxrwx 1 root root 20 Mar 29 20:09 K50php-fpm-56 -> ../init.d/php-fpm-56
    lrwxrwxrwx 1 root root 15 Mar 29 21:49 K55nginx -> ../init.d/nginx
    lrwxrwxrwx 1 root root 16 Mar 29 19:44 K64mysqld -> ../init.d/mysqld
    lrwxrwxrwx 1 root root 19 Mar 29 19:48 K85pure-ftpd -> ../init.d/pure-ftpd
    lrwxrwxrwx 1 root root 18 Mar 29 21:38 S50fail2ban -> ../init.d/fail2ban
    lrwxrwxrwx 1 root root 12 Mar 29 18:46 S55bt -> ../init.d/bt
    

(一大堆前面加K的是我禁止了這些服務的自啟, 暫時還用不到.) 不僅是 rc3, 在其他 rc# 文件夾裡面也有大概相同的文件, 所以規則是, 那個 runlevel 用到就加到 rc幾 , 不怕重複的.

  • 所以說, 除非有特殊的需求, 這幾個文件夾也是一般用戶不需要碰到的, 可以使用systemd 解決需求.

rc.local 文件用途

可以首先看一下 rc.local 文件裡面寫了什麼.

$ cat /etc/rc.d/rc.local

#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
#
# It is highly advisable to create own systemd services or udev rules
# to run scripts during boot instead of using this file.
#
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
#
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.

touch /var/lock/subsys/local


所以說, 這個文件是很久以前用於開機運行一些命令的(不是 sh文件, 而是一些自定義的命令組合), 現在只為了兼容性保留, 最好不要使用了.

inittab 文件

$ cat inittab

# inittab is no longer used.
#
# ADDING CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# Ctrl-Alt-Delete is handled by /usr/lib/systemd/system/ctrl-alt-del.target
#
# systemd uses 'targets' instead of runlevels. By default, there are two main targets:
#
# multi-user.target: analogous to runlevel 3
# graphical.target: analogous to runlevel 5
#
# To view current default target, run:
# systemctl get-default
#
# To set a default target, run:
# systemctl set-default TARGET.target

這個文件告訴我們, inittab 已經被徹底廢棄了, 甚至都不會兼容它.

這也印證了前面的說法, runlevel 的機制已經被 target 機制取代了.

在廢棄前, inittab 是用來決定默認 runlevel 的.

profile 組合

這個就比較好理解了, 這個其實就是一個所有用戶的Bash變量設置, (不侷限於Bash), 功能於設置當前用戶的 ~/.profile 是相似的. 所以說他雖然是啟動項, 但是是專門設置終端環境的, 我也許會以後專門寫一篇來做介紹.

至於 profile.d , 就把 profile 裡面寫不下的專門拿出來模塊化加載, 可以看一下他的內容:

[root@RaspberryPi profile.d]$ ls
colorgrep.csh  colorls.sh       colorzgrep.csh  gawk.csh  lang.sh   sh.local  which2.csh
colorgrep.sh   colorxzgrep.csh  colorzgrep.sh   gawk.sh   less.csh  vim.csh   which2.sh
colorls.csh    colorxzgrep.sh   csh.local       lang.csh  less.sh   vim.sh

都是一些關於終端環境的設置.
明確它的功能之後, 以下討論不會再涉及 profile.

各個方案對比

那麼現在匯總一下開機運行程序的所有方案:

名稱 隸屬於 機制 支持格式 應用場景
/etc/crontab crontab - 命令 開機 @reboot
定時運行任務
/etc/cron.d/ crontab - 腳本 無須手動配置
/etc/cron.*/ crontab - 腳本(符號鏈接) 無須手動配置
/etc/init.d/ rc.d runlevel 可執行腳本 放置要用到的腳本供rc#.d調用
/etc/rc#.d/ rc.d runlevel 指向init.d中腳本的符號鏈接 指定腳本的運行場景和優先級
/etc/rc.local rc.d runlevel 命令 執行自定義指令
systemd - target service 開機執行任務
定時執行任務
特定條件執行任務

systemd 對比 init

之前已經提到, init 已經被 systemd 取代了, 現在的 rc.d 目錄內的一切事務全部由 systemd 代為執行.

(就是說, systemd 替代 init 作為系統最開始啟動的進程 )

所以這沒什麼可比性. 你仍然可以往 init.d 裡面灌腳本然後到 rc#.d 裡面創建符號鏈接 – 一般用在服務器上, 用來啟動程序已經夠了, 但是顯然, 這樣的方式沒有 service 來的靈活.

systemd 對比 crontab

這兩個東西, 功能有重疊, 具體如下:

  • systemd timer 可以定時完成任務
  • crontab 設置條件為 @reboot 可以開機執行命令

在匯總了網上的問答之後, 以及我的親身體驗, 我總結出如下結論:

  • 機械化的定時執行任務, 首選 crontab, 直觀可靠
  • 一句話開機執行任務, 也可以使用 crontab, 原因如上
  • 執行複雜的腳本, 使用 systemd 更為方便.

也就是說, 能用 crontab 就避免使用 systemd, systemd timer 其實可以被 crontab 替代.

資料

在寫這篇博文時, 我搜索了很多資料, 也因此學到了很多, 以下列出我參考過的資料(可能有一點點亂):