systemd,upstart, systemV是LInux系統(tǒng)三種主流的啟動(dòng)方式。但是技術(shù)的發(fā)展,systemV以及upstart的一些局限,systemd已經(jīng)成為當(dāng)下最主要的啟動(dòng)方式了,systemd的最大優(yōu)點(diǎn)就是可以讓開(kāi)機(jī)啟動(dòng)的服務(wù)并行運(yùn)行,減少了開(kāi)機(jī)運(yùn)行的時(shí)間。
systemd管理的服務(wù)的配置文件存放在三個(gè)目錄,三個(gè)目錄分別是:
/usr/lib/systemd/system/ 安裝包自帶的service配置文件存放的位置
/etc/systemd/system/ systemctl enable創(chuàng)建的service文件(當(dāng)你手動(dòng)添加了一個(gè)服務(wù)的配置文件,并且還要讓它開(kāi)機(jī)自啟動(dòng)運(yùn)行,那么就必須執(zhí)行systemctl enable xxx.service)。通常情況下,這些文件基本都是/usr/lib/systemd/system/下的軟連接,而且是以target組分類存放的的;也或者是用戶手動(dòng)添加的服務(wù)的service文件。
/run/systemd/system/ 運(yùn)行時(shí)創(chuàng)建的service文件;優(yōu)先級(jí)/etc/systemd/system/ > /run/systemd/system/ > /usr/lib/systemd/system/
談到systemd的target組,他其實(shí)就和systemV的runlevel(運(yùn)行等級(jí))對(duì)應(yīng)。
用戶自己手動(dòng)在systemd下增加一個(gè)服務(wù),就需要在/etc/systemd/system下創(chuàng)建一個(gè)service配置文件,當(dāng)然在 /usr/lib/systemd/system/創(chuàng)建也可以。配置文件大致如下:
[Unit]
Description=Systemd service test
After=syslog.target #在syslog.target中的服務(wù)啟動(dòng)后再啟動(dòng)
[Service] #Unit類型
ExecStart=/bin/bash -c "exec FOO.sh" #這樣執(zhí)行,即使FOO.sh有while死循環(huán),systemctl start/top 也會(huì)執(zhí)行完就退出
ExecStart=Other CMD
ExecStartPost=/bin/bash -c "exec FOO1.sh" #ExecStart執(zhí)行完后執(zhí)行這個(gè)
Restart=on-failure
RestartSec=30s
Type=simple
[Install]
WantedBy=multi-user.target #systemctl enable 后,就會(huì)在/etc/systemd/multi-user.target.wants下創(chuàng)建一個(gè)軟連接到這里
Service項(xiàng)中的ExecStart是必須的,但是其他的,比如ExecStartPost,ExecStop,都是可選的。對(duì)于ExecStop,就是停止服務(wù)所需要運(yùn)行的腳本,看到這里可能會(huì)產(chǎn)生疑問(wèn),沒(méi)有設(shè)定ExecStop,那么怎么停止服務(wù)呢,答案是系統(tǒng)中已經(jīng)記錄已經(jīng)通過(guò)systemd啟動(dòng)的服務(wù),執(zhí)行systemctl stop 就會(huì)向?qū)?yīng)的服務(wù)發(fā)送SIGTERM信號(hào),默認(rèn)5分鐘如果沒(méi)有收到對(duì)應(yīng)服務(wù)的答復(fù),那么就會(huì)在發(fā)送SIGKILL信號(hào)強(qiáng)行終止服務(wù)。
需要說(shuō)明一下的就是,用戶手動(dòng)起的服務(wù),是沒(méi)辦法通過(guò)這三個(gè)工具去停止或者查詢狀態(tài)的,因?yàn)閟ystemd沒(méi)辦法監(jiān)控"
The systemctl utility does not communicate with services that have not been started by systemd. When systemd starts a system service, it stores the ID of its main process in order to keep track of it. The systemctl utility then uses this PID to query and manage the service. Consequently, if a user starts a particular daemon directly on the command line, systemctl is unable to determine its current status or stop it."
在對(duì)應(yīng)的目錄編寫好service配置文件后,執(zhí)行systemctl daemon-reload后就可以通過(guò)syetemctl start/stop去停起服務(wù)了
如果要加到開(kāi)機(jī)自啟動(dòng),那么還要執(zhí)行systemctl enable xxx.service,這個(gè)服務(wù)就加到了對(duì)應(yīng)的target組了。
具體參考
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/chap-Managing_Services_with_systemd.html
https://wiki.ubuntu.com/SystemdForUpstartUsers
http://www.jinbuguo.com/systemd/systemd.service.html
關(guān)于upstart,它是ubuntu主推的,向下兼容systemV,他的配置文件是/etc/init/目錄下以.conf結(jié)尾的文件。因此在upstart管理服務(wù)的系統(tǒng)中要加入一個(gè)服務(wù),就在/etc/init/目錄增加一個(gè)服務(wù)對(duì)應(yīng)的配置文件即可。配置文件的大致內(nèi)容如下:
/etc/init/FOO.conf
description "uwsgi service"
start on runlevel [2345] #哪些運(yùn)行等級(jí)自動(dòng)運(yùn)行該服務(wù)
stop on runlevel [06] #哪些運(yùn)行等級(jí)不自動(dòng)運(yùn)行該服務(wù)
env LANG=en_US.UTF-8
limit nofile 65535 65535
script
exec cmd #服務(wù)啟動(dòng)時(shí)執(zhí)行的腳本
end script
post-start script
exec cmd #服務(wù)啟動(dòng)后執(zhí)行的腳本
end script
respawn
respawn limit 10 5
對(duì)于更多腳本語(yǔ)法和配置,可參照http://upstart.ubuntu.com/
或者:http://upstart.ubuntu.com/cookbook/
想要看到start或者stop的大概執(zhí)行過(guò)程,可以先sudo initctl log-priority debug改變initctl的日志級(jí)別,然后就可以在/var/log/syslog中查看執(zhí)行過(guò)程的日志了。
關(guān)于systemV,三者中最傳統(tǒng),最古老的服務(wù)啟動(dòng)方式,他的配置文件存放在/etc/init.d/目錄下,這個(gè)目錄下是服務(wù)停起的直接控制腳本,而關(guān)于開(kāi)機(jī)時(shí)啟動(dòng)哪些服務(wù),這個(gè)是根據(jù)runlevel決定的,系統(tǒng)開(kāi)機(jī)分為7個(gè)運(yùn)行等級(jí),分別是0到6,每個(gè)運(yùn)行等級(jí)所需要運(yùn)行的服務(wù)存放在/etc/rc.d/rc(0,1...6).d/目錄下,這個(gè)目錄下的腳本是/etc/init.d/目錄下腳本的軟連接。systemV的腳本樣例如下:
#!/bin/bash
#
# chkconfig: 2345 80 20 #chkconfig --add service 會(huì)根據(jù)這里的設(shè)定,在對(duì)應(yīng)的啟動(dòng)級(jí)別加上這個(gè)服務(wù)
# description: Agent daemon service
# /etc/rc.d/init.d/xxxserver
name=xxxservice
pid_file="/var/run/${name}.pid"
stdout_log="/var/log/${name}_success.log"
stderr_log="/var/log/${name}_error.log"
cmd="需要啟動(dòng)的服務(wù)的命令"
# Get function from functions library
. /etc/init.d/functions #關(guān)鍵是這個(gè)文件,這個(gè)文件中有很多有用的函數(shù)
get_pid() {
cat "$pid_file"
}
is_running() {
[ -f "$pid_file" ] && ps -p `get_pid` > /dev/null 2>&1
}
# Start the host agent
start() {
if is_running; then
echo "$name already started"
else
echo "Starting $name ..."
date -R >> "$stdout_log" 2>> "$stderr_log"
$cmd >> "$stdout_log" 2>> "$stderr_log" &
### Create the lock file ###
echo $! > "$pid_file"
if ! is_running; then
echo "Unable to start $name, see $stdout_log and $stderr_log"
exit 1
fi
echo "$name startup success"
fi
}
# Stop the host agent
stop() {
if is_running; then
echo -n "Stopping $name ..."
killproc $name #這里可以自己寫一個(gè)kill的命令,但是要能保證殺死所有由這個(gè)服務(wù)起的進(jìn)程
for i in 1 2 3 4 5 6 7 8 9 10
do
if ! is_running; then
break
fi
echo -n "."
sleep 1
done
echo
if is_running; then
echo "Not stopped; may still be shutting down or shutdown may have failed"
exit 1
else
echo "Stopped"
if [ -f "$pid_file" ]; then
rm "$pid_file"
fi
fi
else
echo "$name not running"
fi
}
### main logic ###
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status $name #status這個(gè)命令也是/etc/init.d/functions里面的命令,當(dāng)然你也可以更簡(jiǎn)單的使用上面的is_runing函數(shù)
;;
restart|reload)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|restart|reload|status}"
exit 1
esac
exit 0
這個(gè)腳本的缺點(diǎn)就是使用了. /etc/init.d/functions,這句就相當(dāng)于source /etc/init.d/functions,因?yàn)樵趕ystemd和upstart主導(dǎo)的系統(tǒng)中,很可能沒(méi)有自帶/etc/init.d/functions,這個(gè)文件中定義了很多內(nèi)部的shell命令函數(shù),沒(méi)有這個(gè)文件,很多功能函數(shù)都得自己去寫,或者找替代,比如上面腳本中用到的killproc函數(shù)。但是,幸運(yùn)的是,對(duì)于uwsgi程序spawan出來(lái)的多進(jìn)程,只需要?dú)⒌舾高M(jìn)程就會(huì)把其他進(jìn)程全部殺掉,所以/etc/init.d/functions中的很多功能函數(shù)比如killproc還是可以自己實(shí)現(xiàn)的。
對(duì)于systemV,如果要將開(kāi)服務(wù)設(shè)置成開(kāi)機(jī)自啟動(dòng),那么就執(zhí)行chkconfig --add 服務(wù)名,這個(gè)命令會(huì)依據(jù)腳本開(kāi)頭設(shè)置的chkconfig: 2345 80 20,在/etc/rc.d/rc(2345).d/4個(gè)目錄下創(chuàng)建S80開(kāi)頭家K20開(kāi)頭的軟連接到這個(gè)服務(wù)在/etc/init.d/下的腳本。