Linux 服务管理


init

脚本在/etc/init.d目录下

缺点:

  • 启动时间长

    init进程是串行启动,只有前一个进程启动完,才会启动下一个进程

  • 启动脚本复杂

    init进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这往往使得脚本变得很长

常见的脚本

  • nginx
    #! /bin/sh
    # chkconfig: 2345 55 25
    # Description: Startup script for nginx webserver on Debian. Place in /etc/init.d and
    # run 'update-rc.d -f nginx defaults', or use the appropriate command on your
    # distro. For CentOS/Redhat run: 'chkconfig --add nginx'
    
    ### BEGIN INIT INFO
    # Provides:          nginx
    # Required-Start:    $all
    # Required-Stop:     $all
    # Default-Start:     2 3 4 5
    # Default-Stop:      0 1 6
    # Short-Description: starts the nginx web server
    # Description:       starts nginx using start-stop-daemon
    ### END INIT INFO
    
    PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
    NAME=nginx
    NGINX_BIN=/usr/local/nginx/sbin/$NAME
    CONFIGFILE=/usr/local/nginx/conf/$NAME.conf
    PIDFILE=/var/run/$NAME.pid
    if [ -s /bin/ss ]; then
        StatBin=/bin/ss
    else
        StatBin=/bin/netstat
    fi
    
    
    case "$1" in
        start)
            echo -n "Starting $NAME... "
    
            if $StatBin -tnpl | grep -q nginx;then
                echo "$NAME (pid `pidof $NAME`) already running."
                exit 1
            fi
    
            $NGINX_BIN -c $CONFIGFILE
    
            if [ "$?" != 0 ] ; then
                echo " failed"
                exit 1
            else
                echo " done"
            fi
            ;;
    
        stop)
            echo -n "Stoping $NAME... "
    
            if ! $StatBin -tnpl | grep -q nginx; then
                echo "$NAME is not running."
                exit 1
            fi
    
            $NGINX_BIN -s stop
    
            if [ "$?" != 0 ] ; then
                echo " failed. Use force-quit"
                exit 1
            else
                echo " done"
            fi
            ;;
    
        status)
            if $StatBin -tnpl | grep -q nginx; then
                PID=`pidof nginx`
                echo "$NAME (pid $PID) is running..."
            else
                echo "$NAME is stopped."
                exit 0
            fi
            ;;
    
        force-quit|kill)
            echo -n "Terminating $NAME... "
    
            if ! $StatBin -tnpl | grep -q nginx; then
                echo "$NAME is is stopped."
                exit 1
            fi
    
            kill `pidof $NAME`
    
            if [ "$?" != 0 ] ; then
                echo " failed"
                exit 1
            else
                echo " done"
            fi
            ;;
    
        restart)
            $0 stop
            sleep 1
            $0 start
            ;;
    
        reload)
            echo -n "Reload service $NAME... "
    
            if $StatBin -tnpl | grep -q nginx; then
                $NGINX_BIN -s reload
                echo " done"
            else
                echo "$NAME is not running, can't reload."
                exit 1
            fi
            ;;
    
        configtest)
            echo -n "Test $NAME configure files... "
    
            $NGINX_BIN -t
            ;;
    
        *)
            echo "Usage: $0 {start|stop|restart|reload|status|configtest|force-quit|kill}"
            exit 1
            ;;
    
    esac
  • php-fpm
    #! /bin/sh
    
    ### BEGIN INIT INFO
    # Provides:          php-fpm
    # Required-Start:    $remote_fs $network
    # Required-Stop:     $remote_fs $network
    # Default-Start:     2 3 4 5
    # Default-Stop:      0 1 6
    # Short-Description: starts php-fpm
    # Description:       starts the PHP FastCGI Process Manager daemon
    ### END INIT INFO
    
    prefix=/usr/local/php
    exec_prefix=${prefix}
    
    php_fpm_BIN=${exec_prefix}/sbin/php-fpm
    php_fpm_CONF=${prefix}/etc/php-fpm.conf
    php_fpm_PID=${prefix}/var/run/php-fpm.pid
    
    
    php_opts="--fpm-config $php_fpm_CONF --pid $php_fpm_PID"
    
    
    wait_for_pid () {
    	try=0
    
    	while test $try -lt 35 ; do
    
    		case "$1" in
    			'created')
    			if [ -f "$2" ] ; then
    				try=''
    				break
    			fi
    			;;
    
    			'removed')
    			if [ ! -f "$2" ] ; then
    				try=''
    				break
    			fi
    			;;
    		esac
    
    		echo -n .
    		try=`expr $try + 1`
    		sleep 1
    
    	done
    
    }
    
    case "$1" in
    	start)
    		echo -n "Starting php-fpm "
    
    		$php_fpm_BIN --daemonize $php_opts
    
    		if [ "$?" != 0 ] ; then
    			echo " failed"
    			exit 1
    		fi
    
    		wait_for_pid created $php_fpm_PID
    
    		if [ -n "$try" ] ; then
    			echo " failed"
    			exit 1
    		else
    			echo " done"
    		fi
    	;;
    
    	stop)
    		echo -n "Gracefully shutting down php-fpm "
    
    		if [ ! -r $php_fpm_PID ] ; then
    			echo "warning, no pid file found - php-fpm is not running ?"
    			exit 1
    		fi
    
    		kill -QUIT `cat $php_fpm_PID`
    
    		wait_for_pid removed $php_fpm_PID
    
    		if [ -n "$try" ] ; then
    			echo " failed. Use force-quit"
    			exit 1
    		else
    			echo " done"
    		fi
    	;;
    
    	status)
    		if [ ! -r $php_fpm_PID ] ; then
    			echo "php-fpm is stopped"
    			exit 0
    		fi
    
    		PID=`cat $php_fpm_PID`
    		if ps -p $PID | grep -q $PID; then
    			echo "php-fpm (pid $PID) is running..."
    		else
    			echo "php-fpm dead but pid file exists"
    		fi
    	;;
    
    	force-quit)
    		echo -n "Terminating php-fpm "
    
    		if [ ! -r $php_fpm_PID ] ; then
    			echo "warning, no pid file found - php-fpm is not running ?"
    			exit 1
    		fi
    
    		kill -TERM `cat $php_fpm_PID`
    
    		wait_for_pid removed $php_fpm_PID
    
    		if [ -n "$try" ] ; then
    			echo " failed"
    			exit 1
    		else
    			echo " done"
    		fi
    	;;
    
    	restart)
    		$0 stop
    		$0 start
    	;;
    
    	reload)
    
    		echo -n "Reload service php-fpm "
    
    		if [ ! -r $php_fpm_PID ] ; then
    			echo "warning, no pid file found - php-fpm is not running ?"
    			exit 1
    		fi
    
    		kill -USR2 `cat $php_fpm_PID`
    
    		echo " done"
    	;;
    
    	configtest)
    		$php_fpm_BIN -t
    	;;
    
    	*)
    		echo "Usage: $0 {start|stop|force-quit|restart|reload|status|configtest}"
    		exit 1
    	;;
    
    esac
    

service

service 是去/etc/init.d目录下执行相关程序

和直接执行init的shell没什么区别

/etc/init.d/nginx start
等价于
service nginx start

systemd

Systemd 就是为了解决上面的问题而诞生,它包括 System and Service Manager,为系统的启动和管理提供一套完整的解决方案

Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面

systemctl

systemctl是 Systemd 的主命令,用于管理系统

  • 重启系统
    systemctl reboot

  • 启动进入救援状态(单用户状态)
    systemctl rescue

  • 管理服务
    systemctl start nginx

常用的 restart status stop 等

systemctl list-units命令可以查看当前系统的所有 Unit

hostnamectl

查看当前主机的信息

  • 显示当前主机信息
    hostnamectl

  • 设置主机名
    hostnamectl set-hostname name1

localectl

  • 查看本地化设置
    localectl

  • 设置本地化参数
    localectl set-locale LANG=en_GB.utf8
    localectl set-keymap en_GB

timedatectl

查看当前时区设置

  • 查看当前时区设置
    timedatectl

  • 显示所有可用的时区
    timedatectl list-timezones

  • 设置当前时区
    timedatectl set-timezone Asia/Shanghai
    timedatectl set-time YYYY-MM-DD
    timedatectl set-time HH:MM:SS

Unit

Systemd 可以管理所有系统资源。不同的资源统称为 Unit(单位)

Systemd 默认从目录/etc/systemd/system/读取配置文件。
但是,里面存放的大部分文件都是符号链接,指向目录/usr/lib/systemd/system/,真正的配置文件存放在那个目录

systemctl enable命令用于在上面两个目录之间,建立符号链接关系

类型

  • Service unit:系统服务
  • Target unit:多个 Unit 构成的一个组
  • Device Unit:硬件设备
  • Mount Unit:文件系统的挂载点
  • Automount Unit:自动挂载点
  • Path Unit:文件或路径
  • Scope Unit:不是由 Systemd 启动的外部进程
  • Slice Unit:进程组
  • Snapshot Unit:Systemd 快照,可以切回某个快照
  • Socket Unit:进程间通信的 socket
  • Swap Unit:swap 文件
  • Timer Unit:定时器

配置

[Unit]

  • Description:简短描述
  • Documentation:文档地址
  • Requires:当前 Unit 依赖的其他 Unit,如果它们没有运行,当前 Unit 会启动失败
  • Wants:与当前 Unit 配合的其他 Unit,如果它们没有运行,当前 Unit 不会启动失败
  • BindsTo:与Requires类似,它指定的 Unit 如果退出,会导致当前 Unit 停止运行
  • Before:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之后启动
  • After:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动
  • Conflicts:这里指定的 Unit 不能与当前 Unit 同时运行
  • Condition…:当前 Unit 运行必须满足的条件,否则不会运行
  • Assert…:当前 Unit 运行必须满足的条件,否则会报启动失败

[Install]

  • WantedBy:它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放入/etc/systemd/system目录下面以 Target 名 + .wants后缀构成的子目录中

  • RequiredBy:它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放入/etc/systemd/system目录下面以 Target 名 + .required后缀构成的子目录中

  • Alias:当前 Unit 可用于启动的别名

  • Also:当前 Unit 激活(enable)时,会被同时激活的其他 Unit

    [Service]

  • Type:定义启动时的进程行为。它有以下几种值。

  • Type=simple:默认值,执行ExecStart指定的命令,启动主进程

  • Type=forking:以 fork 方式从父进程创建子进程,创建后父进程会立即退出

  • Type=oneshot:一次性进程,Systemd 会等当前服务退出,再继续往下执行

  • Type=dbus:当前服务通过D-Bus启动

  • Type=notify:当前服务启动完毕,会通知Systemd,再继续往下执行

  • Type=idle:若有其他任务执行完毕,当前服务才会运行

  • ExecStart:启动当前服务的命令

  • ExecStartPre:启动当前服务之前执行的命令

  • ExecStartPost:启动当前服务之后执行的命令

  • ExecReload:重启当前服务时执行的命令

  • ExecStop:停止当前服务时执行的命令

  • ExecStopPost:停止当其服务之后执行的命令

  • RestartSec:自动重启当前服务间隔的秒数

  • Restart:定义何种情况 Systemd 会自动重启当前服务,可能的值包括always(总是重启)、on-success、on-failure、on-abnormal、on-abort、on-watchdog

  • TimeoutSec:定义 Systemd 停止当前服务之前等待的秒数

  • Environment:指定环境变量

一个例子

[Unit]
Description=测试服务
Requires=
After=
[Service]
ExecStart=/home/www/test run
Restart=on-failure
LimitNOFILE=2000000
[Install]
WantedBy=multi-user.target

Target

启动计算机的时候,需要启动大量的 Unit。如果每一次启动,都要一一写明本次启动需要哪些 Unit,显然非常不方便。Systemd 的解决方案就是 Target

Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候,Systemd 就会启动里面所有的 Unit

References

https://segmentfault.com/a/1190000038458363
http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html


文章作者: 江湖义气
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 江湖义气 !
  目录