systemd,upstart, systemV是LInux系统三种主流的启动方式。但是技术的发展,systemV以及upstart的一些局限,systemd已经成为当下最主要的启动方式了,systemd的最大优点就是可以让开机启动的服务并行运行,减少了开机运行的时间。
systemd管理的服务的配置文件存放在三个目录,三个目录分别是:
/usr/lib/systemd/system/ 安装包自带的service配置文件存放的位置
/etc/systemd/system/ systemctl enable创建的service文件(当你手动添加了一个服务的配置文件,并且还要让它开机自启动运行,那么就必须执行systemctl enable xxx.service)。通常情况下,这些文件基本都是/usr/lib/systemd/system/下的软连接,而且是以target组分类存放的的;也或者是用户手动添加的服务的service文件。
/run/systemd/system/ 运行时创建的service文件;优先级/etc/systemd/system/ > /run/systemd/system/ > /usr/lib/systemd/system/
谈到systemd的target组,他其实就和systemV的runlevel(运行等级)对应。
用户自己手动在systemd下增加一个服务,就需要在/etc/systemd/system下创建一个service配置文件,当然在 /usr/lib/systemd/system/创建也可以。配置文件大致如下:
[Unit]
Description=Systemd service test
After=syslog.target #在syslog.target中的服务启动后再启动
[Service] #Unit类型
ExecStart=/bin/bash -c "exec FOO.sh" #这样执行,即使FOO.sh有while死循环,systemctl start/top 也会执行完就退出
ExecStart=Other CMD
ExecStartPost=/bin/bash -c "exec FOO1.sh" #ExecStart执行完后执行这个
Restart=on-failure
RestartSec=30s
Type=simple
[Install]
WantedBy=multi-user.target #systemctl enable 后,就会在/etc/systemd/multi-user.target.wants下创建一个软连接到这里
Service项中的ExecStart是必须的,但是其他的,比如ExecStartPost,ExecStop,都是可选的。对于ExecStop,就是停止服务所需要运行的脚本,看到这里可能会产生疑问,没有设定ExecStop,那么怎么停止服务呢,答案是系统中已经记录已经通过systemd启动的服务,执行systemctl stop 就会向对应的服务发送SIGTERM信号,默认5分钟如果没有收到对应服务的答复,那么就会在发送SIGKILL信号强行终止服务。
需要说明一下的就是,用户手动起的服务,是没办法通过这三个工具去停止或者查询状态的,因为systemd没办法监控"
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."
在对应的目录编写好service配置文件后,执行systemctl daemon-reload后就可以通过syetemctl start/stop去停起服务了
如果要加到开机自启动,那么还要执行systemctl enable xxx.service,这个服务就加到了对应的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
关于upstart,它是ubuntu主推的,向下兼容systemV,他的配置文件是/etc/init/目录下以.conf结尾的文件。因此在upstart管理服务的系统中要加入一个服务,就在/etc/init/目录增加一个服务对应的配置文件即可。配置文件的大致内容如下:
/etc/init/FOO.conf
description "uwsgi service"
start on runlevel [2345] #哪些运行等级自动运行该服务
stop on runlevel [06] #哪些运行等级不自动运行该服务
env LANG=en_US.UTF-8
limit nofile 65535 65535
script
exec cmd #服务启动时执行的脚本
end script
post-start script
exec cmd #服务启动后执行的脚本
end script
respawn
respawn limit 10 5
对于更多脚本语法和配置,可参照http://upstart.ubuntu.com/
或者:http://upstart.ubuntu.com/cookbook/
想要看到start或者stop的大概执行过程,可以先sudo initctl log-priority debug改变initctl的日志级别,然后就可以在/var/log/syslog中查看执行过程的日志了。
关于systemV,三者中最传统,最古老的服务启动方式,他的配置文件存放在/etc/init.d/目录下,这个目录下是服务停起的直接控制脚本,而关于开机时启动哪些服务,这个是根据runlevel决定的,系统开机分为7个运行等级,分别是0到6,每个运行等级所需要运行的服务存放在/etc/rc.d/rc(0,1...6).d/目录下,这个目录下的脚本是/etc/init.d/目录下脚本的软连接。systemV的脚本样例如下:
#!/bin/bash
#
# chkconfig: 2345 80 20 #chkconfig --add service 会根据这里的设定,在对应的启动级别加上这个服务
# 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="需要启动的服务的命令"
# Get function from functions library
. /etc/init.d/functions #关键是这个文件,这个文件中有很多有用的函数
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 #这里可以自己写一个kill的命令,但是要能保证杀死所有由这个服务起的进程
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这个命令也是/etc/init.d/functions里面的命令,当然你也可以更简单的使用上面的is_runing函数
;;
restart|reload)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|restart|reload|status}"
exit 1
esac
exit 0
这个脚本的缺点就是使用了. /etc/init.d/functions,这句就相当于source /etc/init.d/functions,因为在systemd和upstart主导的系统中,很可能没有自带/etc/init.d/functions,这个文件中定义了很多内部的shell命令函数,没有这个文件,很多功能函数都得自己去写,或者找替代,比如上面脚本中用到的killproc函数。但是,幸运的是,对于uwsgi程序spawan出来的多进程,只需要杀掉父进程就会把其他进程全部杀掉,所以/etc/init.d/functions中的很多功能函数比如killproc还是可以自己实现的。
对于systemV,如果要将开服务设置成开机自启动,那么就执行chkconfig --add 服务名,这个命令会依据脚本开头设置的chkconfig: 2345 80 20,在/etc/rc.d/rc(2345).d/4个目录下创建S80开头家K20开头的软连接到这个服务在/etc/init.d/下的脚本。