Linux服務管理

本文介紹了CentOS 5、6、7服務管理相關內容

一. 概念

服務(Service)是指執行指定系統功能的程序、例程或進程,以便支持其他程序,尤其是底層(接近硬件)程序1

簡單來說,服務就是計算機對上層提供的某種功能或能力,如網絡功能、任務計劃等,而這些能力需要有相應的程序來完成,我們知道,進程是程序運行的一個實例,通常,這類提供特定服務的進程會隨系統啓動而運行,如我們一開機就可以使用網絡,可以通過SSH登錄系統……

與此前所不同的是,這類進程並不佔用命令提示符,僅在後臺默默運行,常駐在內存中,遂我們將其稱爲守護進程(Daemon) ,在Unix-Like系統中,提供服務的進程大部分都是Daemon,故很多服務的Server端程序(如sshd、crond、httpd),甚至CentOS 7使用的systemd,其最後的字母“d”就是Daemon之意

Linux系統啓動一文中,介紹了SysV、Upstart、Systemd,而就服務管理的角度而言,SysV與Upstart類似,以下將介紹SysV與Systemd在服務管理方面的相關機制

二. SysV init的服務管理

1. 服務分類

我們知道,服務的具體提供這一般爲守護進程,SysV將守護進程分爲兩種

  • 獨立守護進程
  • 超級守護進程

獨立守護進程提供一種或一類服務,相應的進程可獨立啓動2(Stand Alone)

而超級守護進程(Super Daemon)將由一個進程相應客戶端請求,而後將喚醒相應的進程,當服務結束時,所喚醒的進程也將被關閉

想象這樣一個場景,有5個人A、B、C、D、E,其中B、C、D、E每人都有一項技能,平時就在房間裏休息,而A這個傢伙就守在大家門口,外人若需要幫助,則根據大家請求的事情叫醒相應的人去提供幫助即可,事情幹完後,依然回去休息

在這個場景中,A就相當於超級守護進程,事實上在Linux中,該角色一般由xinetd或inetd擔當,如今inetd已經被xinetd取代

2. SysV服務管理風格

服務腳本

所有的服務腳本放置於/etc/init.d/下,多數是shell腳本,他們接受諸如startstoprestartstatus等參數,如

  • 啓動:/etc/init.d/DAEMON start

  • 關閉:/etc/init.d/DAEMON stop

  • 重新啓動:/etc/init.d/DAEMON restart

  • 狀態查看:/etc/init.d/DAEMON status

依賴關係

我們知道,同軟件一樣,服務之間有依賴關係,此前在Linux系統啓動中已有提及,顯而易見,被依賴的服務應該優先啓動

/etc/rc.d/rcX.d/下有KS開頭的鏈接文件,通過字母后的數字來確定啓動或關閉次序,在關閉操作中,被依賴到的服務應該後關閉,而在啓動操作中,被依賴到的服務應該優先啓動

另外,在/etc/rc.d/rc{2,3,4,5}.d/下,都有一個S99local文件,與其他文件不同的是,該文件指向其父目錄的rc.local,即/etc/rc.local
我們亦可將在2、3、4、5級別需要運行的操作或服務指令寫入該文件

運行級別

從服務管理的角度來看,運行級別就是服務運行的一套配置,在用戶切換運行級別時,sysvinit 開始運行/etc/rc.d/rc腳本。該腳本接受一個RunLevel作爲其參數,根據不同的 RunLevel,rc 腳本將打開對應該RunLevel的rcX.d目錄(X爲runlevel),找到並運行存放在該目錄下的所有啓動腳本。每個RunLevel都有一個這樣的目錄,目錄名爲/etc/rc.d/rcX.d

在這些目錄下存放着很多不同的腳本。文件名以S開頭的腳本就是啓動時應該運行的腳本,S後面跟的數字定義了這些腳本的執行順序。在/etc/rc.d/rcX.d目錄下的腳本其實都是一些軟鏈接文件,真實的腳本文件存放在/etc/init.d目錄下

/etc/rc.d/rc腳本中關於服務的啓動與停止大致方式爲

for srv in /etc/rc.d/rc$runlevel.d/K*; do
	$srv stop
done

###

for srv in /etc/rc.d/rc$runlevel.d/S*; do
	$srv start
done

相關內容在Linux系統啓動-SysV init已有介紹

3. 相關命令

service

上文已有說明,服務腳本放置於/etc/init.d/下,他們接受諸如startstoprestartstatus等參數,此外還可以使用service命令執行相同的管理操作

事實上,該命令也是一個腳本(/sbin/service),內容如下

#!/bin/sh

. /etc/init.d/functions

VERSION="$(basename $0) ver. 0.91"
USAGE="Usage: $(basename $0) < option > | --status-all | \
[ service_name [ command | --full-restart ] ]"
SERVICE=
SERVICEDIR="/etc/init.d"
OPTIONS=

if [ $# -eq 0 ]; then
   echo "${USAGE}" >&2
   exit 1
fi

cd /
while [ $# -gt 0 ]; do
  case "${1}" in
    --help | -h | --h* )
       echo "${USAGE}" >&2
       exit 0
       ;;
    --version | -V )
       echo "${VERSION}" >&2
       exit 0
       ;;
    *)
       if [ -z "${SERVICE}" -a $# -eq 1 -a "${1}" = "--status-all" ]; then
          cd ${SERVICEDIR}
          for SERVICE in * ; do
            case "${SERVICE}" in
              functions | halt | killall | single| linuxconf| kudzu)
                  ;;
              *)
                if ! is_ignored_file "${SERVICE}" \
		    && [ -x "${SERVICEDIR}/${SERVICE}" ]; then
                  env -i PATH="$PATH" TERM="$TERM" "${SERVICEDIR}/${SERVICE}" status
                fi
                ;;
            esac
          done
          exit 0
       elif [ $# -eq 2 -a "${2}" = "--full-restart" ]; then
          SERVICE="${1}"
          if [ -x "${SERVICEDIR}/${SERVICE}" ]; then
            env -i PATH="$PATH" TERM="$TERM" "${SERVICEDIR}/${SERVICE}" stop
            env -i PATH="$PATH" TERM="$TERM" "${SERVICEDIR}/${SERVICE}" start
            exit $?
          fi
       elif [ -z "${SERVICE}" ]; then
         SERVICE="${1}"
       else
         OPTIONS="${OPTIONS} ${1}"
       fi
       shift
       ;;
   esac
done

if [ -f "${SERVICEDIR}/${SERVICE}" ]; then
   env -i PATH="$PATH" TERM="$TERM" "${SERVICEDIR}/${SERVICE}" ${OPTIONS}
else
   echo $"${SERVICE}: unrecognized service" >&2
   exit 1
fi

該腳本實際上就是將/etc/init.d/中的腳本封裝進行統一調用

此外,在/etc/rc.d/rc腳本中,有以下內容:

...
# First, run the KILL scripts.
for i in /etc/rc$runlevel.d/K* ; do

	# Check if the subsystem is already up.
	subsys=${i#/etc/rc$runlevel.d/K??}
	[ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] || continue
	check_runlevel "$i" || continue

	# Bring the subsystem down.
	[ -n "$UPSTART" ] && initctl emit --quiet stopping JOB=$subsys
	$i stop
	[ -n "$UPSTART" ] && initctl emit --quiet stopped JOB=$subsys
done

# Now run the START scripts.
for i in /etc/rc$runlevel.d/S* ; do

	# Check if the subsystem is already up.
	subsys=${i#/etc/rc$runlevel.d/S??}
	[ -f /var/lock/subsys/$subsys ] && continue
	[ -f /var/lock/subsys/$subsys.init ] && continue
	check_runlevel "$i" || continue

	# If we're in confirmation mode, get user confirmation
	if [ "$do_confirm" = "yes" ]; then
		confirm $subsys
		rc=$?
		if [ "$rc" = "1" ]; then
			continue
		elif [ "$rc" = "2" ]; then
			do_confirm="no"
		fi
	fi

	update_boot_stage "$subsys"
	# Bring the subsystem up.
	[ -n "$UPSTART" ] && initctl emit --quiet starting JOB=$subsys
	if [ "$subsys" = "halt" -o "$subsys" = "reboot" ]; then
		export LC_ALL=C
		exec $i start
	fi
	$i start
	[ -n "$UPSTART" ] && initctl emit --quiet started JOB=$subsys
done
...

可以看到,在rc腳本啓動或關閉服務時,是通過查看/var/lock/subsys/SERVICE_NAME來確定服務當前是否運行,在啓動服務時,將在該目錄下創建相應文件:

[root@localhost ~]# ll /var/lock/subsys/
total 0
-rw-r--r-- 1 root root 0 Mar 27 12:00 abrt-ccpp
-rw-r--r-- 1 root root 0 Mar 27 12:00 abrtd
-rw-r--r-- 1 root root 0 Mar 27 12:00 acpid
-rw-r--r-- 1 root root 0 Mar 27 12:00 atd
-rw-r--r-- 1 root root 0 Mar 27 12:00 auditd
-rw-r--r-- 1 root root 0 Mar 27 12:00 autofs
-rw-r--r-- 1 root root 0 Mar 27 12:00 blk-availability
-rw-r--r-- 1 root root 0 Mar 27 12:00 certmonger
-rw-r--r-- 1 root root 0 Mar 27 12:00 crond
-rw-r--r-- 1 root root 0 Mar 27 12:00 cups
-rw-r--r-- 1 root root 0 Mar 27 12:00 fcoe
-rw-r--r-- 1 root root 0 Mar 27 12:00 haldaemon
-rw-r--r-- 1 root root 0 Mar 27 12:00 ip6tables
-rw-r--r-- 1 root root 0 Mar 27 12:00 lldpad
-rw-r--r-- 1 root root 0 Mar 27 12:00 local
-rw-r--r-- 1 root root 0 Mar 27 12:00 lvm2-monitor
-rw-r--r-- 1 root root 0 Mar 27 12:00 mcelogd
-rw-r--r-- 1 root root 0 Mar 27 12:00 messagebus
-rw-r--r-- 1 root root 0 Mar 27 12:00 named
-rw-r--r-- 1 root root 0 Mar 27 12:00 netfs
-rw-r--r-- 1 root root 0 Mar 27 12:00 network
-rw-r--r-- 1 root root 0 Mar 27 12:00 NetworkManager
-rw-r--r-- 1 root root 0 Mar 27 12:00 postfix
-rw-r--r-- 1 root root 0 Mar 27 12:00 rpcbind
-rw-r--r-- 1 root root 0 Mar 27 12:00 rpc.statd
-rw------- 1 root root 0 Mar 27 12:00 rsyslog
-rw-r--r-- 1 root root 0 Mar 27 12:00 sshd
-rw-r--r-- 1 root root 0 Mar 27 12:00 xinetd

若刪除該文件,在切換運行級別時,rc腳本則認爲相應的服務沒有啓動(事實上服務的依然正常運行)

chkconfig

在介紹chkconfig命令之前,我們先提一下如何讓服務開機自啓的問題

通過上面的介紹可知,我們只需要在/etc/rc.d/rcX.d目錄中創建一個以S開頭的連接文件,使其指向/etc/init.d中的腳本即可讓一個 服務在特定Level下啓動,反之創建以K開頭的鏈接即可

而chkconfig工具可幫助用戶實現該操作

chkconfig即check configuration之意,用於查看或管控/etc/init.d/每個服務腳本在各級別下的啓動或關閉狀態,使用方式爲

chkconfig --add|--del|--level|--list SERVICE_NAME
	--add
		讓服務接受chkconfig的管控,即給腳本創建鏈接,腳本應放到/etc/rc.d/init.d/中

	--del
		移除創建的鏈接文件
	
	--list
		查看服務的啓動設定,若省略SERVICE_NAME,則可查看所有服務

[root@localhost ~]# chkconfig --list sshd
sshd           	0:off	1:off	2:on	3:on	4:on	5:on	6:off

欲對服務在各級別下的情動情況進行管理,可使用

chkconfig [--level RUNLEVELS] SERVICE_NAME {on|off}

若省略級別指定,則缺省爲2、3、4、5級別,如

[root@localhost ~]# chkconfig sshd off
[root@localhost ~]# chkconfig --list sshd
sshd           	0:off	1:off	2:off	3:off	4:off	5:off	6:off
[root@localhost ~]# chkconfig sshd on
[root@localhost ~]# chkconfig --list sshd
sshd           	0:off	1:off	2:on	3:on	4:on	5:on	6:off

另外,ntsysv命令也可實現類似功能,不過他只能同時修改一個運行級別的配置,現基本已被chkconfig取代,這是一個TUI工具,界面如下

ntsysv

服務腳本

我們知道,服務腳本一般位於/etc/init.d/下,且可接收固定幾個參數,而使用chkconfig管理後,其對應在/etc/rc.d/rcX.d中的鏈接文件的啓動次序如何確定?以及默認在哪些級別下啓動?

這些信息可在服務腳本中以特定格式指出,chkconfig會讀取特定行,來收集這些信息,我們只需在腳本開頭處(不必是最開頭)
寫兩行註釋:

# chkconfig: DEFAULT_START_LEVEL START_PRIORITY STOP_PRIORITY
# description: DESCRIPTION_INFORMATION

# chkconfig:後跟三組數字字符

  • 第一組爲默認在哪些級別下啓動該服務
    • 若指定爲-,則默認在任何級別都不啓動
  • 第二組爲啓動優先級,即創建的以S開頭的鏈接文件後的數字
  • 第三組爲停止優先級,即創建的以K開頭的鏈接文件後的數字

如下爲一個簡單的樣例服務腳本

#!/bin/bash
#
# chkconfig: 2345 77 22
# description: Test Service
# 
LOCKFILE=/var/lock/subsys/myservice

status() {
	if [ -e $LOCKFILE ]; then
	echo "Running..."
	else
	echo "Stopped."
	fi
}

usage() {
	echo "`basename $0` {start|stop|restart|status}"
}

case $1 in
	start)
		echo "Starting..." 
		touch $LOCKFILE ;;
	stop)
		echo "Stopping..." 
		rm -f $LOCKFILE &> /dev/null
	;;
	restart)
		echo "Restarting..." ;;
	status)
		status ;;
	*)
		usage ;;
esac

以上代碼僅爲了說明基本運作機制,並無實際作用,另外關於服務的啓動與停止,可根據/var/lock/subsys/myservice文件是否存在決定是否實際執行

通常,服務腳本會使用/etc/rc.d/init.d/functions中的函數

基於xinetd的服務

使用chkconfig也可直接管理基於超級守護進程的服務,不過與獨立守護進程不同,它修改的是xinetd的配置,即/etc/xinetd.d/SERVICE_NAME,以telnet服務爲例,安裝telnet-server後,使用chkconfig查看:

[root@localhost ~]# chkconfig --list
NetworkManager 	0:off	1:off	2:on	3:on	4:on	5:on	6:off
abrt-ccpp      	0:off	1:off	2:off	3:on	4:off	5:on	6:off
abrtd          	0:off	1:off	2:off	3:on	4:off	5:on	6:off
acpid          	0:off	1:off	2:on	3:on	4:on	5:on	6:off
atd            	0:off	1:off	2:off	3:on	4:on	5:on	6:off
auditd         	0:off	1:off	2:on	3:on	4:on	5:on	6:off
autofs         	0:off	1:off	2:off	3:on	4:on	5:on	6:off
blk-availability	0:off	1:on	2:on	3:on	4:on	5:on	6:off
certmonger     	0:off	1:off	2:off	3:on	4:on	5:on	6:off
cgconfig       	0:off	1:off	2:off	3:off	4:off	5:off	6:off
cgred          	0:off	1:off	2:off	3:off	4:off	5:off	6:off
cpuspeed       	0:off	1:on	2:on	3:on	4:on	5:on	6:off
crond          	0:off	1:off	2:on	3:on	4:on	5:on	6:off
cups           	0:off	1:off	2:on	3:on	4:on	5:on	6:off
dnsmasq        	0:off	1:off	2:off	3:off	4:off	5:off	6:off
fcoe           	0:off	1:off	2:on	3:on	4:on	5:on	6:off
haldaemon      	0:off	1:off	2:off	3:on	4:on	5:on	6:off
htcacheclean   	0:off	1:off	2:off	3:off	4:off	5:off	6:off
httpd          	0:off	1:off	2:off	3:off	4:off	5:off	6:off
ip6tables      	0:off	1:off	2:on	3:on	4:on	5:on	6:off
iptables       	0:off	1:off	2:off	3:off	4:off	5:off	6:off
irqbalance     	0:off	1:off	2:off	3:on	4:on	5:on	6:off
iscsi          	0:off	1:off	2:off	3:on	4:on	5:on	6:off
iscsid         	0:off	1:off	2:off	3:on	4:on	5:on	6:off
kdump          	0:off	1:off	2:off	3:on	4:on	5:on	6:off
lldpad         	0:off	1:off	2:on	3:on	4:on	5:on	6:off
lvm2-monitor   	0:off	1:on	2:on	3:on	4:on	5:on	6:off
mcelogd        	0:off	1:off	2:off	3:on	4:off	5:on	6:off
mdmonitor      	0:off	1:off	2:on	3:on	4:on	5:on	6:off
messagebus     	0:off	1:off	2:on	3:on	4:on	5:on	6:off
multipathd     	0:off	1:off	2:off	3:off	4:off	5:off	6:off
named          	0:off	1:off	2:on	3:on	4:on	5:on	6:off
netconsole     	0:off	1:off	2:off	3:off	4:off	5:off	6:off
netfs          	0:off	1:off	2:off	3:on	4:on	5:on	6:off
network        	0:off	1:off	2:on	3:on	4:on	5:on	6:off
nfs            	0:off	1:off	2:off	3:off	4:off	5:off	6:off
nfslock        	0:off	1:off	2:off	3:on	4:on	5:on	6:off
ntpd           	0:off	1:off	2:off	3:off	4:off	5:off	6:off
ntpdate        	0:off	1:off	2:off	3:off	4:off	5:off	6:off
numad          	0:off	1:off	2:off	3:off	4:off	5:off	6:off
oddjobd        	0:off	1:off	2:off	3:off	4:off	5:off	6:off
portreserve    	0:off	1:off	2:on	3:on	4:on	5:on	6:off
postfix        	0:off	1:off	2:on	3:on	4:on	5:on	6:off
pppoe-server   	0:off	1:off	2:off	3:off	4:off	5:off	6:off
psacct         	0:off	1:off	2:off	3:off	4:off	5:off	6:off
quota_nld      	0:off	1:off	2:off	3:off	4:off	5:off	6:off
rdisc          	0:off	1:off	2:off	3:off	4:off	5:off	6:off
restorecond    	0:off	1:off	2:off	3:off	4:off	5:off	6:off
rngd           	0:off	1:off	2:off	3:off	4:off	5:off	6:off
rpcbind        	0:off	1:off	2:on	3:on	4:on	5:on	6:off
rpcgssd        	0:off	1:off	2:off	3:on	4:on	5:on	6:off
rpcsvcgssd     	0:off	1:off	2:off	3:off	4:off	5:off	6:off
rsyslog        	0:off	1:off	2:on	3:on	4:on	5:on	6:off
saslauthd      	0:off	1:off	2:off	3:off	4:off	5:off	6:off
smartd         	0:off	1:off	2:off	3:off	4:off	5:off	6:off
sshd           	0:off	1:off	2:on	3:on	4:on	5:on	6:off
sssd           	0:off	1:off	2:off	3:off	4:off	5:off	6:off
sysstat        	0:off	1:on	2:on	3:on	4:on	5:on	6:off
udev-post      	0:off	1:on	2:on	3:on	4:on	5:on	6:off
vncserver      	0:off	1:off	2:off	3:off	4:off	5:off	6:off
winbind        	0:off	1:off	2:off	3:off	4:off	5:off	6:off
wpa_supplicant 	0:off	1:off	2:off	3:off	4:off	5:off	6:off
xinetd         	0:off	1:off	2:off	3:on	4:on	5:on	6:off
ypbind         	0:off	1:off	2:off	3:off	4:off	5:off	6:off

xinetd based services:
	chargen-dgram: 	off
	chargen-stream:	off
	daytime-dgram: 	off
	daytime-stream:	off
	discard-dgram: 	off
	discard-stream:	off
	echo-dgram:    	off
	echo-stream:   	off
	rsync:         	off
	tcpmux-server: 	off
	telnet:        	off
	time-dgram:    	off
	time-stream:   	off

可以看到在“xinetd based services”段中,telnet服務爲關閉狀態,我們使用chkconfig telnet on後,即可將其開啓,而此時查看/etc/xinetd.d/telnet


# default: on
# description: The telnet server serves telnet sessions; it uses \
#       unencrypted username/password pairs for authentication.
service telnet
{
        disable = no
        flags           = REUSE
        socket_type     = stream
        wait            = no
        user            = root
        server          = /usr/sbin/in.telnetd
        log_on_failure  += USERID
}

其中有一個字段disable = no,意爲“不禁用”,即啓動狀態,此時,我們重啓xinetd服務使其重讀配置:service xinetd restart

telnet監聽TCP/23端口,使用ss查看:

[root@localhost ~]# ss -tanp | grep 23
LISTEN     0      64                       :::23                      :::*      users:(("xinetd",3573,5))

可以看到,該端口有xinetd監聽(回憶上文的五人例子),而此時在外部使用telnet客戶端連接

[root@localhost ~]# w
 15:30:28 up  3:30,  3 users,  load average: 0.01, 0.01, 0.00
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
user1    pts/2    192.168.18.128	15:30    6.00s  0.00s  0.00s -bash
root     pts/0    192.168.18.1     	12:00   15.00s  0.09s  0.09s -bash
root     pts/1    192.168.18.1     	12:00    0.00s  0.33s  0.00s w

此時再次使用ss查看:

[root@localhost ~]# ss -tanp | grep 23
LISTEN     0      64                       :::23                      :::*      users:(("xinetd",3573,5))
ESTAB      0      0            192.168.18.131:23            192.168.18.1:4956   users:(("in.telnetd",3633,0),("in.telnetd",3633,1),("in.telnetd",3633,2))

已建立會話的進程爲telnet

三、SystemD服務管理

1. 概述

關於SystemD,在Linux系統啓動-Systemd中已有部分介紹,此處將介紹Systemd在服務管理方面的一些特點3

  • 並行啓動所有服務,加速開機流程
    舊的init啓動腳本是“一項一項任務依序啓動”的模式,因此彼此沒有依賴關係的服務也是得要一個一個的等待。systemd就是可以讓所有的服務同時啓動,因此你會發現到,系統啓動的速度變快了!
  • 一經要求就回應的on-demand啓動方式
    systemd全部就是僅有一隻systemd服務搭配systemctl命令來處理,無須其他額外的指令來支持。不像systemV還要init, chkconfig, service…等等指令。此外, systemd由於常駐內存,因此任何要求(on-demand)都可以立即處理後續的daemon啓動的任務。
  • 服務依賴性的自我檢查:
    由於systemd可以自訂服務相依性的檢查,因此如果B服務是架構在A服務上面啓動的,那當你在沒有啓動A服務的情況下僅手動啓動B服務時, systemd會自動幫你啓動A服務喔!這樣就可以免去管理員得要一項一項服務去分析的麻煩~(如果讀者不是新手,應該會有印象,當你沒有啓動網路,但卻啓動NIS/NFS時,那個開機時的timeout甚至可達到10~30分鐘…)
  • 依daemon功能分類:
    systemd旗下管理的服務非常多,systemd先定義所有的服務爲一個服務單位(unit),並將該unit歸類到不同的服務類型(type)去。舊的init僅分爲stand alone與super daemon實在不夠看,systemd將服務單位(unit)區分爲service, socket, target, path, snapshot, timer等多種不同的類型(type),方便管理員的分類與記憶。
  • 將多個daemons集合成爲一個組:
    如同systemV的init裏頭有個runlevel的特色,systemd亦將許多的功能集合成爲一個所謂的target項目,這個項目主要在設計操作環境的建置,所以是集合了許多的daemons,亦即是執行某個target就是執行好多個daemon的意思!
  • 向下兼容舊有的init服務腳本:
    基本上, systemd是可以兼容init的啓動腳本的,因此,舊的init啓動腳本也能夠通過systemd來管理,只是更高級的systemd功能就沒有辦法支援就是了。

另外,與SysVinit不同的是,systemd使用systemctl命令來管理服務,遂只能接收固定的參數,而/etc/init.d/下的腳本文件可由開發者自定義參數(也有幾個約定俗成的參數,如startstop等)

若服務不是通過systemd啓動,則systemctl無法與之通信,即無法使用該命令管理

2. 相關文件

目錄

關於systemd各Unit已在Linux系統啓動-Systemd中有介紹,此處再次站在服務管理的角度贅述一下其配置文件

主要由三個目錄保存了相關配置:

  • /usr/lib/systemd/system/:每個服務最主要的啓動腳本配置,類似於SysVinit的/etc/init.d下的文件

  • /run/systemd/system/:系統執行過程中所產生的服務腳本,這些腳本的優先級比/usr/lib/systemd/system/

  • /etc/systemd/system/:管理員依據主機系統的需求所建立的執行腳本,該目錄類似於SysVinit的/etc/rc.d/rc5.d/Sxx功能,執行優先序比/run/systemd/system/

    • /etc/systemd/system/SERVICE.service.d/custom.conf:用戶自定義的服務配置文件,最好以.conf結尾,此時其中的配置可與/usr/lib/systemd/system/中的相應配置結合

    • /etc/systemd/system/*.wangts/:該目錄下爲軟鏈接文件,意爲啓動當前unit後,請求啓動該目錄下的unit

    • /etc/systemd/system/*.requires/:當前unit的依賴項,啓動前必須啓動該目錄下的unit

Service Unit File

.service文件,這些文件通常位於以下位置:

  • /etc/systemd/system/*.service

  • /usr/lib/systemd/system/*.service

  • /run/systemd/system/*.service

以下內容爲sshd服務的service文件:

[root@localhost ~]# cat /usr/lib/systemd/system/sshd.service
[Unit]
Description=OpenSSH server daemon
After=network.target sshd-keygen.service
Wants=sshd-keygen.service

[Service]
EnvironmentFile=/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target

可以看到,這類文件有三部分組成

  • [Unit]
    定義與Unit類型無關的通用選項,用於提供當前Unit的描述信息、unit行爲以及依賴關係等
  • [Service]
    定義與特性類型相關的專用選項,此處爲Service類型,其他還有如[Socket],[Timer],[Mount],[Path]等
  • [Install]
    將此unit 安裝到哪個target 裏,即定義由“systemctl enable”以及“systemctl disable”命令在實現服務啓用或禁用時用到的一些選項

Unit段

  • Description:描述信息;意義性描述
  • After:定義的啓動次序;表示當前unit應該晚於哪些unit啓動,其功能與Before相反
  • Requies:依賴到的其他unit;強依賴,被依賴的unit無法激活時,當前unit將無法激活
  • Wants:依賴到的其他unit;弱依賴,被依賴到的unit無法激活時,當前unit也可以激活
  • Conflicts:定義unit間的衝突關係

Service段

  • Type:用於定義影響ExecStart及相關參數的功能的unit進程啓動類型

    • simple:默認,表示ExecStart指定的程序所啓動的進程是主進程
    • forking:表示ExecStart指定的程序所啓動的進程,所生成對的一個子進程爲主進程,啓動完成後,父進程將退出
    • oneshot:類似於simple,但啓動後續的unit之前,主進程將退出
    • dbus:類似於simple,但後續的unit僅在主進程得到dbus名稱之後再啓動
    • notify:類似於simple,但後續的unit僅在通過sd_notify函數發送通知以後才啓動
    • idle:與simple類似, 不同之處在於該進程將會被延遲到所有活動的任務都完成之後再執行(這樣可以避免控制檯上的狀態信息與shell腳本的輸出混雜在一起)
  • EnvironmentFile:環境配置文件;指定的文件將在ExecStart之前被讀取,並未其配置諸如變量等自定義功能

  • ExecStart:指明要啓動unit要運行的命令或腳本

    • ExecStartPre:運行ExecStart之前運行的命令或腳本
    • ExecStartPost:運行ExecStart之後運行的命令或腳本
  • ExecStop:指明停止unit要運行的命令或腳本

  • Restart:當服務進程正常退出、異常退出、被殺死、超時的時候, 是否重新啓動該服務

Install段

  • Alias:當前unit的別名

  • RequiredBy:被哪些unit所依賴,強依賴

  • WantedBy:被哪些unit所依賴,弱依賴

對於新創建的unit文件,或修改了的unit文件,要通知systemd重載此配置文件:

systemctl daemon-reload

3. systemctl

該命令名即System Control之意,SYSTEMCTL(1)中的描述爲:

Control the systemd system and service manager

以下按照不同應用場景對該命令基礎用法進行說明

Service管理

基本管理

基礎的服務啓動停止、是否自啓的使用格式爲

systemctl [COMMAND] [SERVICE] 
	COMMAND
		start :立刻啓動後面接的SERVICE
		stop :立刻關閉後面接的SERVICE
		restart :立刻關閉後啓動後面接的SERVICE,即執行SERVICE再SERVICE
		reload :不關閉後面接的SERVICE的情況下,重新讀取配置文件
		enable :後面的SERVICE設定爲開機自啓
		disable :後面的SERVICE設定爲開機不自啓
		status :查看SERVICE狀態
		is-active :查看SERVICE是否已啓動
		is-enabled:查看SERVICE是否開機自啓
		mask:註銷SERVICE,使其無法啓動
		unmask:取消標記位註銷狀態

如,查看sshd服務的狀態:

[root@localhost ~]# systemctl status sshd.service
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2019-03-29 13:46:22 CST; 1h 10min ago
 Main PID: 6504 (sshd)
   CGroup: /system.slice/sshd.service
           └─6504 /usr/sbin/sshd -D

Mar 29 13:46:22 localhost systemd[1]: Started OpenSSH server daemon.
Mar 29 13:46:22 localhost sshd[6504]: Server listening on 0.0.0.0 port 22.
Mar 29 13:46:22 localhost sshd[6504]: Server listening on :: port 22.
Mar 29 14:32:49 localhost sshd[8050]: Accepted password for root from 192.168.18.1 port 1153 ssh2

結合以上的介紹,其輸出結果相信很好理解:

  • Loaded:表示該服務是否開機自啓,有以下幾種狀態:

    • enabled表示開機自啓

    • disabled表示開機不自啓

    • static表示該服務不可開機自啓,即不能設置爲enabled,但是可被其他服務啓動,如依賴此服務的服務

    • mask表示該服務無法啓動

  • Active:表示該服務是否在運行,有以下幾種狀態:

    • active (running):服務正在運行
    • active (exited):僅執行一次就結束的服務,並且目前沒有進程在運行,bash腳本多數是這種類型
    • active (waiting):正在運行,但是被阻塞,需要等待另一個事件完成纔可繼續
    • inactive:服務沒有運行
  • Main PID:表示服務主進程PID

事實上,開機是否自啓,只需在/etc/systemd/system/下對應的target目錄創建一個符號鏈接,指向/usr/lib/systemd/system/下對應的Service unit文件即可:

[root@localhost ~]# systemctl disable sshd.service
Removed symlink /etc/systemd/system/multi-user.target.wants/sshd.service.
[root@localhost ~]# systemctl enable sshd.service
Created symlink from /etc/systemd/system/multi-user.target.wants/sshd.service to /usr/lib/systemd/system/sshd.service.
[root@localhost ~]# ll /etc/systemd/system/multi-user.target.wants/sshd.service
lrwxrwxrwx. 1 root root 36 Mar 29 15:24 /etc/systemd/system/multi-user.target.wants/sshd.service -> /usr/lib/systemd/system/sshd.service

而註銷操作實際上就是將/etc/systemd/system/SERVICE鏈接到/dev/null而已:

[root@localhost ~]# systemctl mask httpd.service
Created symlink from /etc/systemd/system/httpd.service to /dev/null.
[root@localhost ~]# systemctl unmask httpd.service
Removed symlink /etc/systemd/system/httpd.service.

查看多個服務

systemctl可以查看多個服務,用法如下:

systemctl [COMMAND] [--type=TYPE] [--all] 
	COMMAND
		list-units :依據unit 列出目前啓動的unit,若加上--all增會列出沒啓動的
		list-unit-files :將/usr/lib/systemd/system/下所有文件列出狀態
		--type=TYPE:指定unit type,如service, socket, target……

另外,可僅適用不帶任何參數的systemctl命令,與systemctl liist-units相同,如:

[root@localhost ~]# systemctl
  UNIT                                               LOAD   ACTIVE SUB       DESCRIPTION
  sys-devices-virtual-block-dm\x2d0.device           loaded active plugged   /sys/devices/virtual/block/dm-0
  sys-devices-virtual-block-dm\x2d1.device           loaded active plugged   /sys/devices/virtual/block/dm-1
  sys-devices-virtual-block-dm\x2d2.device           loaded active plugged   /sys/devices/virtual/block/dm-2
  sys-devices-virtual-block-dm\x2d3.device           loaded active plugged   /sys/devices/virtual/block/dm-3
  sys-devices-virtual-block-dm\x2d4.device           loaded active plugged   /sys/devices/virtual/block/dm-4
  sys-devices-virtual-block-dm\x2d5.device           loaded active plugged   /sys/devices/virtual/block/dm-5
  sys-devices-virtual-block-dm\x2d6.device           loaded active plugged   /sys/devices/virtual/block/dm-6
  sys-devices-virtual-block-md0.device               loaded active plugged   /sys/devices/virtual/block/md0
  sys-module-configfs.device                         loaded active plugged   /sys/module/configfs

……

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

151 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

Target管理

關於Target管理的命令格式與Service類似:

systemctl [COMMAND] [TARGET]
	COMMAND
		get-default :獲取默認target 
		set-default :設定默認target
		isolate :切換target

系統已有的Target我們可通過上文介紹的方式查看:

[root@localhost ~]# systemctl list-units --type=target --all
  UNIT                   LOAD      ACTIVE   SUB    DESCRIPTION
  basic.target           loaded    active   active Basic System
  bluetooth.target       loaded    inactive dead   Bluetooth
  cryptsetup.target      loaded    active   active Local Encrypted Volumes
  emergency.target       loaded    inactive dead   Emergency Mode
  final.target           loaded    inactive dead   Final Step
  getty-pre.target       loaded    inactive dead   Login Prompts (Pre)
  getty.target           loaded    active   active Login Prompts
  graphical.target       loaded    inactive dead   Graphical Interface
  local-fs-pre.target    loaded    active   active Local File Systems (Pre)
  local-fs.target        loaded    active   active Local File Systems
  multi-user.target      loaded    active   active Multi-User System
  network-online.target  loaded    active   active Network is Online
  network-pre.target     loaded    inactive dead   Network (Pre)
  network.target         loaded    active   active Network
  nss-lookup.target      loaded    inactive dead   Host and Network Name Lookups
  nss-user-lookup.target loaded    inactive dead   User and Group Name Lookups
  paths.target           loaded    active   active Paths
  remote-fs-pre.target   loaded    active   active Remote File Systems (Pre)
  remote-fs.target       loaded    active   active Remote File Systems
  rescue.target          loaded    inactive dead   Rescue Mode
  shutdown.target        loaded    inactive dead   Shutdown
  slices.target          loaded    active   active Slices
  sockets.target         loaded    active   active Sockets
  sound.target           loaded    inactive dead   Sound Card
  swap.target            loaded    active   active Swap
  sysinit.target         loaded    active   active System Initialization
● syslog.target          not-found inactive dead   syslog.target
  time-sync.target       loaded    inactive dead   System Time Synchronized
  timers.target          loaded    active   active Timers
  umount.target          loaded    inactive dead   Unmount All Filesystems

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

30 loaded units listed.
To show all installed unit files use 'systemctl list-unit-files'.

另外,一些常用的操作可以有簡潔的指令實現

  • systemctl poweroff:關機

  • systemctl reboot:重啓

  • systemctl suspend:掛起,即睡眠

  • systemctl hibernate:休眠

  • systemctl rescue:救援模式

  • systemctl emergency:緊急救援模式

此處說明一下suspend與hibernate的區別,即掛起(Windows中稱爲睡眠)與休眠

  • 掛起狀態即ACPI中的S3,是指僅爲RAM供電,保證其數據不丟失,其他組件停止供電,計算機可快速恢復爲G0(即工作)狀態

  • 休眠狀態即ACPI中的S4,是指將RAM的內容保存到非易失性存儲(一般爲硬盤)後,所有組件停止供電,喚醒時需要先將數據恢復到RAM,故喚醒速度較S3慢

關於ACPI(Advanced Configuration and Power Interface),可參考Wikipedia

查看依賴性

我們可以通過systemctl list-dependencies [UNIT] [--reverse]來查看各Unit之間的依賴性,若不指定UNIT,則爲當前的Target Unit:

[root@localhost ~]# systemctl list-dependencies
default.target
● ├─abrt-ccpp.service
● ├─abrt-oops.service
● ├─abrt-vmcore.service
● ├─abrt-xorg.service
● ├─abrtd.service
● ├─atd.service
● ├─auditd.service
● ├─brandbot.path
● ├─chronyd.service
● ├─crond.service
● ├─cups.path
● ├─dbus.service
● ├─httpd.service
● ├─hypervkvpd.service
● ├─hypervvssd.service
● ├─irqbalance.service
● ├─kdump.service
● ├─libstoragemgmt.service
● ├─mariadb.service
● ├─mdmonitor.service
● ├─ModemManager.service
● ├─network.service
● ├─NetworkManager.service
● ├─plymouth-quit-wait.service
● ├─plymouth-quit.service
● ├─postfix.service
● ├─rhel-configure.service
● ├─rngd.service
● ├─rsyslog.service
● ├─smartd.service
● ├─sshd.service
● ├─sysstat.service
● ├─systemd-ask-password-wall.path
● ├─systemd-logind.service
● ├─systemd-readahead-collect.service
● ├─systemd-readahead-replay.service
● ├─systemd-update-utmp-runlevel.service
● ├─systemd-user-sessions.service
● ├─tuned.service
● ├─vmtoolsd.service
● ├─basic.target
● │ ├─alsa-restore.service
● │ ├─alsa-state.service
● │ ├─microcode.service
● │ ├─rhel-dmesg.service
● │ ├─paths.target
● │ ├─slices.target
● │ │ ├─-.slice
● │ │ └─system.slice
● │ ├─sockets.target
● │ │ ├─cups.socket
● │ │ ├─dbus.socket
● │ │ ├─dm-event.socket
● │ │ ├─iscsid.socket
● │ │ ├─iscsiuio.socket
● │ │ ├─rpcbind.socket
● │ │ ├─systemd-initctl.socket
● │ │ ├─systemd-journald.socket
● │ │ ├─systemd-shutdownd.socket
● │ │ ├─systemd-udevd-control.socket
● │ │ └─systemd-udevd-kernel.socket
● │ ├─sysinit.target
● │ │ ├─dev-hugepages.mount
● │ │ ├─dev-mqueue.mount
● │ │ ├─dmraid-activation.service
● │ │ ├─iscsi.service
● │ │ ├─kmod-static-nodes.service
● │ │ ├─lvm2-lvmetad.socket
● │ │ ├─lvm2-lvmpolld.socket
● │ │ ├─lvm2-monitor.service
● │ │ ├─multipathd.service
● │ │ ├─plymouth-read-write.service
● │ │ ├─plymouth-start.service
● │ │ ├─proc-sys-fs-binfmt_misc.automount
● │ │ ├─rhel-autorelabel-mark.service
● │ │ ├─rhel-autorelabel.service
● │ │ ├─rhel-domainname.service
● │ │ ├─rhel-import-state.service
● │ │ ├─rhel-loadmodules.service
● │ │ ├─sys-fs-fuse-connections.mount
● │ │ ├─sys-kernel-config.mount
● │ │ ├─sys-kernel-debug.mount
● │ │ ├─systemd-ask-password-console.path
● │ │ ├─systemd-binfmt.service
● │ │ ├─systemd-firstboot.service
● │ │ ├─systemd-hwdb-update.service
● │ │ ├─systemd-journal-catalog-update.service
● │ │ ├─systemd-journal-flush.service
● │ │ ├─systemd-journald.service
● │ │ ├─systemd-machine-id-commit.service
● │ │ ├─systemd-modules-load.service
● │ │ ├─systemd-random-seed.service
● │ │ ├─systemd-sysctl.service
● │ │ ├─systemd-tmpfiles-setup-dev.service
● │ │ ├─systemd-tmpfiles-setup.service
● │ │ ├─systemd-udev-trigger.service
● │ │ ├─systemd-udevd.service
● │ │ ├─systemd-update-done.service
● │ │ ├─systemd-update-utmp.service
● │ │ ├─systemd-vconsole-setup.service
● │ │ ├─cryptsetup.target
● │ │ ├─local-fs.target
● │ │ │ ├─-.mount
● │ │ │ ├─boot.mount
● │ │ │ ├─home.mount
● │ │ │ ├─rhel-readonly.service
● │ │ │ └─systemd-remount-fs.service
● │ │ └─swap.target
● │ │   └─dev-mapper-centos\x2dswap.swap
● │ └─timers.target
● │   └─systemd-tmpfiles-clean.timer
● ├─getty.target
● │ └─[email protected]
● └─remote-fs.target

對了,每個Unit條目的左側的●是有顏色的,這裏無法顯示

最頂層的default.target即默認的Target,此處爲multi-user.target,此外,還可以使用--reverse選項進行反向查詢,即查看當前Unit被誰所依賴;

[root@localhost ~]# systemctl list-dependencies --reverse
default.target
● └─graphical.target

4. 日誌

概述

這裏的日誌主要用於記錄應用程序與操作系統內核的操作與發生的事件,以方便後期的審計與故障排除,RHEL系列發行版的日誌使用syslog協議,其服務提供者爲rsyslog,爲syslog的補充,一下內容來自rsyslog.com

RSYSLOG is the rocket-fast system for log processing.
It offers high-performance, great security features and a modular design. While it started as a regular syslogd, rsyslog has evolved into a kind of swiss army knife of logging, being able to accept inputs from a wide variety of sources, transform them, and output to the results to diverse destinations.
RSYSLOG can deliver over one million messages per second to local destinations when limited processing is applied. Even with remote destinations and more elaborate processing the performance is usually considered “stunning”.
rsyslog
RSYSLOG:
  • Multi-threading
  • TCP, SSL, TLS, RELP
  • MySQL, PostgreSQL, Oracle and more
  • Filter any part of syslog message
  • Fully configurable output format
  • Suitable for enterprise-class relay chains

在Systemd出現之前,Linux系統及各應用的日誌都是分別管理的,Systemd開始統一管理了所有Unit的啓動日誌,而時至RHEL 7,日誌系統由systemd-journaldrsyslog兩服務組成

systemd啓動後,systemd-journald也會立即啓動。將日誌存RAM中,當rsyslog啓動後會讀取該RAM並完成篩選分類寫入目錄/var/logsyslog的信息也可以由systemd-journald轉發到rsyslog中進一步處理

默認情況下,systemd的日誌保存在/run/log/journal中,系統重啓就會清除,通過新建/var/log/journal目錄,日誌會自動記錄到這個目錄中,並永久存儲

journalctl

systemd日誌可由jpurnalctl命令查看,其使用格式爲

journalctl [OPTIONS...] [MATCHES...]
	OPTIONS
		-n N			查看最後N行日誌
		-f				顯示最近的10條記錄,輸出後不退出,可持續查看最新信息,可使用-n選項修改顯示條目數
		-k				查看內核日誌
		
		-b				查看本次啓動後的所有日誌
		
			可使用“-b -N”查看前幾次系統日誌,如:
				-b -1			上次啓動的信息
				-b -2			上上次啓動的信息
				-b -0			本次啓動的信息,相當於-b
				
		-p LOG_LEVEL	根據日誌級別查看
			LOG_LEVEL=[0-7]
		
		-u=UNIT			根據UNIT查看日誌,支持模式匹配

		--since="YYYY-MM-DD hh-mm-ss"
			顯示自YYYY-MM-DD hh-mm-ss以來的日誌
			
		--until="YYYY-MM-DD hh-mm-ss"
			顯示截止到YYYY-MM-DD hh-mm-ss的日誌

		-o=FORMAT		指定輸出格式,可用的FORMAT下文將介紹

關於日誌級別,此前已有介紹,這裏將其列出以供參考:

編碼 優先級 嚴重性
0 emerg 系統不可用
1 alert 必須立即採取措施
2 crit 嚴重狀況
3 err 非嚴重錯誤狀況
4 warning 警告狀況
5 notice 正常但重要的事件
6 info 信息性事件
7 debug 調試級別消息

以上的編碼爲RHEL標準,不同發行版可能不盡相同,建議使用優先級描述

以下爲-o選項中可用的格式4

格式 描述
short is the default and generates an output that is mostly identical to the formatting of classic syslog files, showing one line per journal entry.
short-iso is very similar, but shows ISO 8601 wallclock timestamps.
short-precise is very similar, but shows timestamps with full microsecond precision.
short-monotonic is very similar, but shows monotonic timestamps instead of wallclock timestamps.
verbose shows the full-structured entry items with all fields.
export serializes the journal into a binary (but mostly text-based) stream suitable for backups and network transfer (see Journal Export Format[1] for more information).
json formats entries as JSON data structures, one per line (see Journal JSON Format[2] for more information).
json-pretty formats entries as JSON data structures, but formats them in multiple lines in order to make them more readable by humans.
json-sse formats entries as JSON data structures, but wraps them in a format suitable for Server-Sent Events[3].
cat generates a very terse output, only showing the actual message of each journal entry with no metadata, not even a timestamp.

四、例

提供一個systemd的配置文件, 讓nginx服務可以開機啓動

/etc/systemd/system/下創建nginx.service文件,內容如下:

[Unit]
Description=nginx Service
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop

[Install]
WantedBy=multi-user.target

關於nginx專用的一些選項,在介紹nginx時說明

文件保存後,通知systemd重讀配置文件:systemctl daemon-reload

用awk查看tcp連接處於TIMEOUT的連接個數
netstat -tna | awk '{count=0;if ($NF=="TIMEOUT") count++}END{print count}'

netstat -tna用於列出TCP狀態的鏈接,awk中使用count變量作爲計數器,根據netstat輸出結果可知,狀態信息爲最後一個字段(分隔符爲空白),我們判斷若其爲TIMEOUT時計數器+1,在最後打印計數器數值

關於awk的詳細介紹,詳見文本處理三劍客之AWK


  1. 來自 https://baike.baidu.com/item/系統服務 ↩︎

  2. 這裏的獨立啓動僅指進程啓動,而服務的提供依然可能有依賴性關係 ↩︎

  3. 以下內容參考鳥哥的Linux私房菜-systemd 使用的 unit 分類 ↩︎

  4. 參考自journalctl(1) ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章