systemd简介

回到顶部

linux启动的第一个用户进程是init进程,PID为1,init进程是所有用户进程的祖先进程。 传统的init进程已经被systemd(system daemon)取代。 用ps或者pstree可以看到1号进程显示的还是init进程,但是可执行程序文件其实是指向systemd的符号链接:

              [root@initroot ~]# ps aux
              USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
              root         1  0.0  0.1 225604  5812 ?        Ss   Mar01   0:04 /sbin/init splash
              root         2  0.0  0.0      0     0 ?        S    Mar01   0:00 [kthreadd]
              root         4  0.0  0.0      0     0 ?        I<   Mar01   0:00 [kworker/0:0H]
              ...
              [root@initroot ~]# ls -l /sbin/init
              lrwxrwxrwx 1 root root 20 Sep 30 23:23 /sbin/init -> /lib/systemd/systemd
            
systemd进程也是系统守护进程,主要用来管理系统中的其他守护进程,所有随系统启动的进程都由systemd进程启动。
systemd进程提供systemctl命令管理系统守护进程。
传统的systemV init进程需要多个命令互相配合管理守护进程,这些命令有service、chkconfig、setup、init等, systemd只提供systemctl命令,所有的管理工作都通过systemctl命令完成。

systemd取代init的优势

回到顶部

大部分linux发行版都用systemd取代了传统System V系统的init进程。systemd有如下优势:
1.并行启动所有服务,加速开机启动流程:
传统的init进程按顺序执行启动脚本,具有相互依赖关系的进程需要按照顺序启动,这是合理的。 但是一些没有相互依赖关系的服务进程也必须按照顺序启动,这显然是不合理的。 没有相互依赖关系的服务进程完全可以并行启动,而systemd就可以让没有依赖关系的服务进程同时启动,大大加速了系统的启动速度!
2.立即响应的on-demand启动方式:
传统的init进程通过服务对应的启动脚本来管理服务进程,脚本的加载执行需要一定的时间,而且管理命令也比较多如init, chkconfig, service等。 而systemd进程常驻内存,任何请求都可以立即处理。systemd进程提供的管理命令也只有一个systemctl。 只需要通过systemctl命令就可以完成所有的系统服务管理工作。所以不管是系统的响应速度还是用户的使用效率都大大提高。
3.自动检查服务的依赖关系
systemd可以进行服务依赖性检查,假设服务进程B依赖服务进程A,当用systemctl启动服务进程B的时候,如果A进程没有启动, sysytemd会自动检查并启动进程A!这样管理员不需要一项一项分析服务的依赖关系。
4.按daemon功能分类:
systemd管理的服务非常多,systemd将所有的服务定义为一个服务单元unit,并将unit划分为不同的服务类型type。 传统的init仅将守护进程分为stand alone与super daemon, systemd将服务单元unit分为service, socket, target, path, snapshot, timer等多种不同的类型(type).
5.将多个服务集合成为一个群组target:
systemd将服务进程集合为一个target,一个target集合了许多daemons,执行某个target就相当于执行了该target内的所有daemons. target可以将操作系统启动到某个运行环境,类似传统systemV init的运行等级runlevel。
6.兼容传统的init服务脚本:
systemd可以兼容init的启动脚本,传统的 init 启动脚本也能通过 systemd 管理。

systemd并没有完全兼容传统的init,例如init runlevel 1, 3, 5可以对应到systemd的某些target,但没有全部对应;
systemd只提供一个systemctl管理服务命令,systemctl支持的语法有限制,不像/etc/init.d/daemon纯脚本可以自定义参数,systemctl不可自定义参数。
如果服务不是通过systemctl启动,systemd将无法跟踪该服务,也就无法通过systemctl命令管理了.
systemd启动服务的过程中,无法通过终端与用户交互,自行编写systemd的启动设置时,必须取消互动机制.

systemctl管理服务(service unit)

回到顶部

服务的启动一般有两种方式,一种是系统开机自启动,另一个是系统开机后用户手动启动。

              [root@initroot ~]# systemctl [command] [unit]
              command选项:
                start: 启动unit;
                stop: 关闭unit;
                restart: 重启unit;
                reload: 不关闭unit的情况下,重载配置文件,使新配置生效;
                enable: 设置开机自启动unit;
                disable: 设置禁止开机自启动unit;
                status: unit的运行状态,会列出有没有正在运行、是否开机自启动、日志状态信息等;
                is-active: unit是否正在运作中;
                is-enable: 是否开机自启动unit;
            
查看atd服务的状态:
              [root@initroot ~]# systemctl status atd.service
              ● atd.service - Job spooling tools
                Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
                Active: active (running) since Wed 2019-10-30 21:35:36 CST; 4 months 2 days ago
              Main PID: 506 (atd)
                CGroup: /system.slice/atd.service
                        └─506 /usr/sbin/atd -f

              Oct 30 21:35:36 izm5e94e7bypr5rhnhbvq9z systemd[1]: Started Job spooling tools.
            
上面各行的含义如下:
Loaded:是否开机自启动unit,enabled为开机启动,disabled为开机不启动;
Active:unit的运行状态,正在运行(running)或没有运行(dead);
后面两行说明unit的PID信息;
最后一行显示服务的日志信息,信息格式为:时间 产生日志的主机 产生日志的服务 日志信息内容,如果unit曾经出错过,该日志信息可以提供一些重要的线索!
可以看到atd服务默认开机启动,正在运行中!
关闭atd服务:
              [root@initroot ~]# systemctl stop atd.service
            
再次查看atd服务的状态:
              [root@initroot ~]# systemctl status atd.service
              ● atd.service - Job spooling tools
                Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
                Active: inactive (dead) since Tue 2020-03-03 13:54:46 CST; 8s ago
                Process: 506 ExecStart=/usr/sbin/atd -f $OPTS (code=exited, status=0/SUCCESS)
              Main PID: 506 (code=exited, status=0/SUCCESS)

              Oct 30 21:35:36 izm5e94e7bypr5rhnhbvq9z systemd[1]: Started Job spooling tools.
              Mar 03 13:54:46 izm5e94e7bypr5rhnhbvq9z systemd[1]: Stopping Job spooling tools...
              Mar 03 13:54:46 izm5e94e7bypr5rhnhbvq9z systemd[1]: Stopped Job spooling tools.
            
unit运行状态为inactive (dead)没有运行。开机默认启动。最后两行为新增的日志信息.
再次启动atd服务:
              [root@initroot ~]# systemctl start atd.service
            
系统服务进程的管理一定要使用systemctl,尽量不要使用kill来关闭服务进程,这样会使服务进程脱离systemd的监控,后续就无法使用systemctl命令来管理了。
服务的运行状态除了上面的running和dead之外,还有如下几个常见的状态:
systemd服务运行状态
运行状态 状态说明
active (running) 表示unit正在运行中。常驻内存的系统守护进程一般都是这种状态.
active (exited) 无须常驻内存,仅执行一次就正常结束的服务。例如开机或者挂载时才会执行的quotaon功能, quotaon不用一直运行,只须执行一次,就交给文件系统去自行处理!通常用bash shell编写的小型服务,大多是这种状态。
active (waiting) 正在运行等待中,等待其他的事件才会继续。 例如打印队列相关服务就是这种状态,虽然正在运行中,但只有队列进来(打印作业)才会唤醒打印服务进行下一步的打印。
inactive 服务没有运行。
系统服务的开机默认状态除了enable和disable之外,还有如下几种状态:
systemd服务默认启动状态
启动状态 状态说明
enabled 开机时自启动
disabled 开机时不启动
static 默认不启动(disabled),但可能会被依赖它的其他enabled的服务启动
mask 无论如何都无法被启动,因为已经被强制注销(非删除)。可通过systemctl unmask方式恢复原本状态

观察chronyd服务的状态,将此服务设置为开机不启动并关闭该服务:
1. 观察chronyd服务的状态:

              [root@initroot ~]# systemctl status chronyd.service
              ● chronyd.service - NTP client/server
                Loaded: loaded (/usr/lib/systemd/system/chronyd.service; disabled; vendor preset: enabled)
                Active: inactive (dead)
                  Docs: man:chronyd(8)
                        man:chrony.conf(5)
            
2. 服务正在运行中,关闭该服务:
              [root@initroot ~]# systemctl stop chronyd.service
            
3. 设置开机不启动:
              [root@initroot ~]# systemctl disable chronyd.service
              rm '/etc/systemd/system/multi-user.target.wants/chronyd.service'
            
设置开机不启动,其实就是删除/etc/systemd/system目录下的链接文件.
              [root@initroot ~]# systemctl status chronyd.service
              chronyd.service - NTP client/server
              Loaded: loaded (/usr/lib/systemd/system/chronyd.service; disabled)
              Active: inactive (dead)
            
这样chronyd服务就完全关闭了,开机后也不会运行。

1. cups为打印服务进程,查看cups服务的状态:

              [root@initroot ~]# systemctl status cups.service
              ● cups.service - CUPS Scheduler
                Loaded: loaded (/lib/systemd/system/cups.service; enabled; vendor preset: enabled)
                Active: active (running) since Tue 2020-03-03 12:17:41 CST; 2h 12min ago
                  Docs: man:cupsd(8)
              Main PID: 2487 (cupsd)
                  Tasks: 1 (limit: 4915)
                CGroup: /system.slice/cups.service
                        └─2487 /usr/sbin/cupsd -l

              Mar 03 12:17:41 peter-VirtualBox systemd[1]: Started CUPS Scheduler.
            
默认启动状态为enable,运行状态为running.
2. 关闭并设置开机不启动:
              [root@initroot ~]# systemctl stop cups.service
              [root@initroot ~]# systemctl disable cups.service
              Synchronizing state of cups.service with SysV service script with /lib/systemd/systemd-sysv-install.
              Executing: /lib/systemd/systemd-sysv-install disable cups
              Removed /etc/systemd/system/sockets.target.wants/cups.socket.
              Removed /etc/systemd/system/multi-user.target.wants/cups.path.
              Removed '/etc/systemd/system/printer.target.wants/cups.service'
            
上面删除了三个链接文件,这三个文件都是和cups.service服务相关的文件.
我们彻底关闭了cups.service,使用netstat应该观察不到该服务:
              [root@initroot ~]# netstat -tlunp | grep cups
            
3. 启动cups.socket监听客户端的请求:
              [root@initroot ~]# systemctl start cups.socket
              [root@initroot ~]# systemctl status cups.service cups.socket cups.path
              Failed to dump process list, ignoring: No such file or directory
              ● cups.service - CUPS Scheduler
                Loaded: loaded (/lib/systemd/system/cups.service; disabled; vendor preset: enabled)
                Active: inactive (dead) since Tue 2020-03-03 14:31:07 CST; 2min 46s ago
                  Docs: man:cupsd(8)
              Main PID: 2487 (code=exited, status=0/SUCCESS)

              Mar 03 12:17:41 peter-VirtualBox systemd[1]: Started CUPS Scheduler.
              Mar 03 14:31:07 peter-VirtualBox systemd[1]: Stopping CUPS Scheduler...
              Mar 03 14:31:07 peter-VirtualBox systemd[1]: Stopped CUPS Scheduler.

              ● cups.socket - CUPS Scheduler
                Loaded: loaded (/lib/systemd/system/cups.socket; disabled; vendor preset: enabled)
                Active: active (listening) since Tue 2020-03-03 14:33:41 CST; 11s ago
                Listen: /run/cups/cups.sock (Stream)
                CGroup: /system.slice/cups.socket

              Mar 03 14:33:41 peter-VirtualBox systemd[1]: Listening on CUPS Scheduler.

              ● cups.path - CUPS Scheduler
                Loaded: loaded (/lib/systemd/system/cups.path; disabled; vendor preset: enabled)
                Active: inactive (dead)

              Mar 03 12:12:39 peter-VirtualBox systemd[1]: Started CUPS Scheduler.
              Mar 03 12:17:41 peter-VirtualBox systemd[1]: Stopped CUPS Scheduler.
              Mar 03 12:17:41 peter-VirtualBox systemd[1]: Stopping CUPS Scheduler.
              Mar 03 12:17:41 peter-VirtualBox systemd[1]: Started CUPS Scheduler.
              Mar 03 14:31:07 peter-VirtualBox systemd[1]: Stopped CUPS Scheduler.
            
只有cups.socket启动了,其他服务都没有启动.
4. 使用lp命令打印:
              [root@initroot ~]# echo "testing" | lp
              lp: Error - no default destination available. 没有打印机,所以报错
            
再次观察cups.service服务状态:
              [root@initroot ~]# systemctl status cups.service
              ● cups.service - CUPS Scheduler
                Loaded: loaded (/lib/systemd/system/cups.service; disabled; vendor preset: enabled)
                Active: active (running) since Tue 2020-03-03 14:35:11 CST; 28s ago
                  Docs: man:cupsd(8)
              Main PID: 6213 (cupsd)
                  Tasks: 1 (limit: 4915)
                CGroup: /system.slice/cups.service
                        └─6213 /usr/sbin/cupsd -l

              Mar 03 14:35:11 peter-VirtualBox systemd[1]: Started CUPS Scheduler.
            
cups.service服务的状态竟然变成running了,cups.service和cups.socket之间是有依赖关系的。 cups打印服务使用cups.socket文件监听port 631来提供网络打印机的打印功能。
其实不需要cups服务一直监听cups.socket文件,在用户需要打印时,即cups.socket有数据时,才会主动唤醒cups.service.
因此如果只是 disable/stop cups.service 而忘记了其他两个服务的话,那么当有用户向其他两个cups.path, cups.socket提出请求时, cups.service就会被唤醒.
如果想要彻底关闭打印服务,常规作法是关闭 cups.service 时,将cups.socket 与cups.path也关闭.
还可以通过mask方式强制注销cups.service!
1. 保持刚刚的状态,关闭cups.service,启动cups.socket,然后注销cups.servcie:
              [root@initroot ~]# systemctl stop cups.service
              [root@initroot ~]# systemctl mask cups.service
              ln -s '/dev/null' '/etc/systemd/system/cups.service'
            
mask将cups服务的配置文件cups.service变成空设备/dev/null的符号链接!
              [root@initroot ~]# systemctl status cups.service
              ● cups.service
                Loaded: masked (/dev/null; bad)
                Active: active (running) since Tue 2020-03-03 14:35:11 CST; 1min 32s ago
              Main PID: 6213 (cupsd)
                  Tasks: 1 (limit: 4915)
                CGroup: /system.slice/cups.service
                        └─6213 /usr/sbin/cupsd -l

              Mar 03 14:35:11 peter-VirtualBox systemd[1]: Started CUPS Scheduler.
              Mar 03 14:36:11 peter-VirtualBox systemd[1]: cups.service: Current command vanished from the unit file, execution of the command list won't be resumed.
            
整个启动的配置文件被连结到/dev/null空设备文件,无论如何也无法启动cups.service了.
通过mask,就不用担心其他服务可能会启动想要关闭的服务了.虽然是非常规方法,不过很有效.
使用unmask取消注销:
              [root@initroot ~]# systemctl unmask cups.service
              rm '/etc/systemd/system/cups.service'
              [root@initroot ~]# systemctl status cups.service
              ● cups.service - CUPS Scheduler
                Loaded: loaded (/lib/systemd/system/cups.service; disabled; vendor preset: enabled)
                Active: active (running) since Tue 2020-03-03 14:35:11 CST; 2min 30s ago
                  Docs: man:cupsd(8)
              Main PID: 6213 (cupsd)
                  Tasks: 1 (limit: 4915)
                CGroup: /system.slice/cups.service
                        └─6213 /usr/sbin/cupsd -l

              Mar 03 14:35:11 peter-VirtualBox systemd[1]: Started CUPS Scheduler.
              Mar 03 14:36:11 peter-VirtualBox systemd[1]: cups.service: Current command vanished from the unit file, execution of the command list won't be resumed.
            

上面我们遇到了socket类型的unit,cups.socket。linux系统中还有很多socket文件,systemctl list-sockets可以列出系统中的正在被监听的socket file:

              [root@initroot ~]# systemctl list-sockets
              LISTEN                          UNIT                            ACTIVATES
              /dev/rfkill                     systemd-rfkill.socket           systemd-rfkill.service
              /run/acpid.socket               acpid.socket                    acpid.service
              /run/avahi-daemon/socket        avahi-daemon.socket             avahi-daemon.service
              /run/cups/cups.sock             cups.socket                     cups.service
              /run/dmeventd-client            dm-event.socket                 dm-event.service
              /run/dmeventd-server            dm-event.socket                 dm-event.service
              /run/lvm/lvmetad.socket         lvm2-lvmetad.socket             lvm2-lvmetad.service
              /run/lvm/lvmpolld.socket        lvm2-lvmpolld.socket            lvm2-lvmpolld.service
              /run/systemd/coredump           systemd-coredump.socket        
              /run/systemd/fsck.progress      systemd-fsckd.socket            systemd-fsckd.service
              /run/systemd/initctl/fifo       systemd-initctl.socket          systemd-initctl.service
              /run/systemd/journal/dev-log    systemd-journald-dev-log.socket systemd-journald.service
              /run/systemd/journal/socket     systemd-journald.socket         systemd-journald.service
              /run/systemd/journal/stdout     systemd-journald.socket         systemd-journald.service
              /run/systemd/journal/syslog     syslog.socket                   rsyslog.service
              /run/udev/control               systemd-udevd-control.socket    systemd-udevd.service
              /run/uuidd/request              uuidd.socket                    uuidd.service
              /var/run/dbus/system_bus_socket dbus.socket                     dbus.service
              audit 1                         systemd-journald-audit.socket   systemd-journald.service
              kobject-uevent 1                systemd-udevd-kernel.socket     systemd-udevd.service

              20 sockets listed.
              Pass --all to see loaded but inactive sockets, too.
            
第一列为socket文件所在的目录,第二列为管理该socket文件的unit,第三列为依赖该socket文件的service。
可以看到cups.socket管理的socket文件为/run/cups/cups.sock,cups.service依赖该socket文件。

systemd daemon运行相关的目录

回到顶部

systemd管理的对象不止系统服务进程,还包括socket文件、系统快照、操作环境(运行等级)target等,几乎涉及到系统的每个角落。
这也是systemd一开始并不为人接受的地方,违反了unix系统KISS(keep it simple, stupid)的哲学原则。
systemd将管理的对象称为服务单元(unit),这些服务单元又分为不同的类型(type),例如上面提到的socket、target等,而系统服务进程的unit类型为service。
我们通过配置文件进行定义和配置unit,可以通过unit配置文件的后缀名识别unit类型,这些配置文件分布在多个目录下:
/usr/lib/systemd/system/:每个服务最主要的启动脚本设置,有点类似/etc/init.d目录下的文件;
/run/systemd/system/:系统执行过程中所产生的服务脚本,这些脚本的优先级比/usr/lib/systemd/system/高;
/etc/systemd/system/:管理员依据主机系统的需求所建立的执行脚本,其实这个目录有点类似/etc/rc.d/rc5.d/Sxx的功能,执行优先级比/run/systemd/system/高!
系统开机会不会执行某些服务主要是看 /etc/systemd/system/目录下的设置,该目录下是一堆链接文件, 实际执行的systemd启动脚本配置文件放在/usr/lib/systemd/system/目录下!
要查看和修改某个服务启动的设置,应该去/usr/lib/systemd/system/目录下!
和系统服务进程运行有关的目录基本上有下面这些:
/usr/lib/systemd/system/:
CentOS官方提供的软件,默认的启动脚本配置文件都放在这里,这里的数据尽量不要修改,可到/etc/systemd/system目录下修改;
/run/systemd/system/:
系统执行过程中所产生的服务脚本,这些脚本的优先级比/usr/lib/systemd/system/高;
/etc/systemd/system/:
管理员依据主机系统的需求所建立的执行脚本,有点类似以前的/etc/rc.d/rc5.d/Sxx,执行优先级又比 /run/systemd/system/ 高!
/etc/sysconfig/*:
这个目录内的文件非常重要,几乎所有的服务配置文件都在这个目录下,例如mandb 所要更新的 man page索引中,需要加入的参数就写入到此目录下的 man-db中! 网络设置则写在/etc/sysconfig/network-scripts/目录小;
/var/lib/:
一些会产生数据的服务都会将数据写入到/var/lib/目录中。例如数据库管理系统Mariadb默认就是写入/var/lib/mysql/这个目录下!
/run/:
存放daemon运行中的临时文件,包括 lock file 以及 PID file等。

systemd服务单元unit的类型分类

回到顶部

systemd将管理的对象称为unit,unit又分为多种服务类型type,每个unit都有对应的配置文件,通过配置文件的扩展名可以看出unit的类型。
可以统计下/usr/lib/systemd/system/目录下的unit配置文件都有哪些后缀扩展名:

              [root@initroot ~]# ls -l /usr/lib/systemd/system/ | grep -E '(vsftpd|multi|cron)'
              -rw-r--r--  1 root root  284 Nov 20  2018 crond.service
              -rw-r--r--. 1 root root  567 Jul  6  2018 multipathd.service
              -rw-r--r--  1 root root  492 Jul 31  2019 multi-user.target
              drwxr-xr-x. 2 root root 4096 Aug  6  2019 multi-user.target.wants
              lrwxrwxrwx  1 root root   17 Aug  6  2019 runlevel2.target -> multi-user.target
              lrwxrwxrwx  1 root root   17 Aug  6  2019 runlevel3.target -> multi-user.target
              lrwxrwxrwx  1 root root   17 Aug  6  2019 runlevel4.target -> multi-user.target
              -rw-r--r--. 1 root root  171 Nov 10  2018 vsftpd.service
              -rw-r--r--. 1 root root  184 Nov 10  2018 vsftpd@.service
              -rw-r--r--. 1 root root   89 Nov 10  2018 vsftpd.target
            
可以看到vsftpd与crond的unit类型为系统服务service,multi-user的类型为target,target类似init的运行级别。
根据这些扩展名, 大概可以找到几种比较常见的systemd服务unit类型:
systemd unit类型
unit类型 类型说明
1.service 配置文件后缀.service,用于定义系统服务,这是最常见的unit类型,平时的管理也主要是针对service;
2.socket 配置文件后缀.socket,用于标识unix域进程间通信使用的socket文件,通常本地服务之间的通信会用到socket文件,例如x window server; 当通过socket文件传递信息时,信息被传递到监听该socket文件的服务进程daemon, 如果daemon尚未启动,则启动该daemon后再传送数据。 有点类似早期的super daemon xinetd,监听socket文件的服务一般是不会立刻用到的服务,因此在开机时通常会延迟启动。
3.target 配置文件后缀.target,是一群unit的集合,用于实现该target环境, 执行该target就需要执行该target下的所有unit,用于模拟传统的运行级别概念;
4.snapshot 配置文件后缀.snapshot,用于管理系统快照;
5.device 配置文件后缀.device,用于定义内核识别的设备;
6.mount 配置文件后缀.mount,用于定义文件系统挂载点,例如来自网络的自动挂载、NFS文件系统挂载等;
7.automount 配置文件后缀.automount,用于定义文件系统的自动挂载点;
8.swap 配置文件后缀.swap,用于标识swap设备;
9.timer 配置文件后缀.timer,用于管理计划任务,类似anacrontab;
10.path 配置文件后缀.path,为侦测特定文件或目录类型,用于根据文件系统上特定对象的变化来启动其他服务。 某些服务需要侦测某些特定的目录来提供队列服务, 例如最常见的打印服务,就是通过侦测打印队列目录来启动打印功能! 这时就得要.path的服务类型支持了!
11.slice 配置文件后缀.slice,用于资源管理;
12.scope 配置文件后缀.scope,用于外部创建的进程;

查看系统上所有的服务

回到顶部

通过systemctl的list-units和list-unit-files选项查看系统上的所有服务:

              [root@initroot ~]# systemctl [command] [--type=TYPE] [--all]         
              选项和参数:
                command选项:
                list-units: 为systemctl默认选项,列出所有已启动的unit;
                list-unit-files: 依据/usr/lib/systemd/system/内的文件,将所有文件列表说明;
                --all列出所有的unit,启动和没启动的;
                --type=TYPE: 即unit type,只列出指定type的unit,主要有service, socket, target等;
              
            
systemctl默认列出系统上启动的所有unit:
              [root@initroot ~]# systemctl
              UNIT                                                                                     LOAD   ACTIVE SUB       DESCRIPTION                              
              proc-sys-fs-binfmt_misc.automount                                                        loaded active waiting   Arbitrary Executable File Formats File Sys
              sys-devices-pci0000:00-0000:00:01.1-ata2-host1-target1:0:0-1:0:0:0-block-sr0.device      loaded active plugged   VBOX_CD-ROM                              
              sys-devices-pci0000:00-0000:00:03.0-net-enp0s3.device                                    loaded active plugged   82540EM Gigabit Ethernet Controller (PRO/1
              sys-devices-pci0000:00-0000:00:05.0-sound-card0.device                                   loaded active plugged   82801AA AC'97 Audio Controller           
              sys-devices-pci0000:00-0000:00:0d.0-ata3-host2-target2:0:0-2:0:0:0-block-sda-sda1.device loaded active plugged   VBOX_HARDDISK 1                          
              sys-devices-pci0000:00-0000:00:0d.0-ata3-host2-target2:0:0-2:0:0:0-block-sda.device      loaded active plugged   VBOX_HARDDISK                            
              sys-devices-platform-serial8250-tty-ttyS0.device                                         loaded active plugged   /sys/devices/platform/serial8250/tty/ttyS0
              sys-devices-platform-serial8250-tty-ttyS1.device                                         loaded active plugged   /sys/devices/platform/serial8250/tty/ttyS1
              sys-devices-platform-serial8250-tty-ttyS10.device                                        loaded active plugged   /sys/devices/platform/serial8250/tty/ttyS1
              ...
              fstrim.timer                                                                             loaded active waiting   Discard unused blocks once a week        
              motd-news.timer                                                                          loaded active waiting   Message of the Day                       
              systemd-tmpfiles-clean.timer                                                             loaded active waiting   Daily Cleanup of Temporary Directories   

              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.

              161 loaded units listed. Pass --all to see loaded but inactive units, too.
              To show all installed unit files use 'systemctl list-unit-files'.
              
                各字段的含义:
                UNIT: unit名称,可以通过后缀扩展名看出每个unix的类别;
                LOAD: 开机时是否会被加载,systemctl默认显示的是有加载的项目;
                ACTIVE: 目前的状态,与后续的SUB搭配!就是我们用systemctl status观察时,active的项目;
                DESCRIPTION: 详细描述;
            
列出所有已经安装的unit:
              [root@initroot ~]# systemctl list-unit-files
              UNIT FILE                                  STATE          
              proc-sys-fs-binfmt_misc.automount          static         
              -.mount                                    generated      
              dev-hugepages.mount                        static         
              dev-mqueue.mount                           static         
              proc-sys-fs-binfmt_misc.mount              static         
              sys-fs-fuse-connections.mount              static         
              sys-kernel-config.mount                    static         
              sys-kernel-debug.mount                     static         
              acpid.path                                 enabled        
              cups.path                                  enabled        
              systemd-ask-password-console.path          static         
              systemd-ask-password-plymouth.path         static         
              systemd-ask-password-wall.path             static         
              session-c2.scope                           transient      
              accounts-daemon.service                    enabled        
              acpid.service                              disabled       
              alsa-restore.service                       static  
              ...省略...
              systemd-tmpfiles-clean.timer               static         
              ureadahead-stop.timer                      static         

              331 unit files listed.
            
systemctl list-unit-files会扫描/usr/lib/systemd/system目录,将系统上所有的服务都列出来,而list-units仅以unit分类作大致的说明。 STATE状态指开机是否会默认加载!主要有enabled、disabled、mask、static等。
使用--type指定要查看的unit类型,例如只想知道service类别的daemon,不论是否启动都列出来:
              [root@initroot ~]# systemctl list-units --type=service --all
            
查询系统上以cpu为名的服务:
              [root@initroot ~]# systemctl list-units --type=service --all | grep cpu
              cpupower.service loaded inactive dead Configure CPU power related settings
            
确实有个cpupower.service,可以改变CPU电源管理机制的服务!

systemctl分析各unit间的依赖关系

回到顶部

unit之间具有依赖关系,systemctl list-dependencies可以看出unit之间的依赖关系。

              [root@initroot ~]# systemctl list-dependencies [unit] [--reverse]
              --reverse :反向追踪unit的依赖!
            
观察cups.service所的依赖unit:
              [root@initroot ~]# systemctl list-dependencies cups.service
            
可以查看一下运行级别target所依赖的unit,例如graphical.target会依赖multi-user.target。 列出当前target环境下依赖的所有unit:
              [root@initroot ~]# systemctl get-default
              multi-user.target
              [root@initroot ~]# systemctl list-dependencies
              default.target
              ├─abrt-ccpp.service
              ├─abrt-oops.service
              ├─vsftpd.service
              ├─basic.target
              │ ├─alsa-restore.service
              │ ├─alsa-state.service
              ...
              │ ├─sockets.target
              │ │ ├─avahi-daemon.socket
              │ │ ├─dbus.socket
              ...
              │ ├─sysinit.target
              │ │ ├─dev-hugepages.mount
              │ │ ├─dev-mqueue.mount
              ...
              │ └─timers.target
              │
              └─systemd-tmpfiles-clean.timer
              ├─getty.target
              │ └─getty@tty1.service
              └─remote-fs.target
            
上面清楚的显示了unit之间的依赖关系。 默认的环境为multi-user.target,list-dependencies列出的default.target就是multi-user.target! multi-user.target还会依赖 basic.target + getty.target + remote-fs.target三大项, 而basic.target又用到了 sockets.target + sysinit.target + timers.target等.
查出依赖multi-user.target的unit:
              [root@initroot ~]# systemctl list-dependencies --reverse
              default.target
              └─graphical.target
            
reverse意为反向,该选项列出依赖这个服务的unit,multi-user.target 主要是被 graphical.target 所依赖. graphical.target又依赖以下服务:
              [root@initroot ~]# systemctl list-dependencies graphical.target
              graphical.target
              ├─accounts-daemon.service
              ├─gdm.service
              ├─network.service
              ├─rtkit-daemon.service
              ├─systemd-update-utmp-runlevel.service
              └─multi-user.target
              ├─abrt-ccpp.service
              ├─abrt-oops.service
              ...
            
graphical.target 就是在 multi-user.target的基础上加上 accounts-daemon, gdm, network, rtkit-deamon, systemd-update-utmp-runlevel等服务!

systemctl配置文件相关目录简介

回到顶部

传统的systemv init进程环境下,如果想要建立系统服务,就需要将管理服务的脚本文件放入/etc/init.d/目录下。 在systemd环境下, 就是通过编辑unit的配置文件。

服务的管理通过systemd,systemd 的配置文件大部分放置于/usr/lib/systemd/system/目录内。 但是 Red Hat 官方文件指出, 该目录的文件主要是原本软件所提供的设置,建议不要修改!而要修改的位置应该放置于 /etc/systemd/system/ 目录内。
举例来说,如果你想要额外修改 vsftpd.service 的话, 他们建议要放置到哪些地方呢? /usr/lib/systemd/system/vsftpd.service:官方释出的预设配置文件; /etc/systemd/system/vsftpd.service.d/custom.conf:在 /etc/systemd/system 底下建立与配置文件相同文件名的目录,但是要加上 .d 的扩展名。 然后在该目录下建立配置文件即可。 另外,配置文件最好附文件名取名为.conf较佳! 在这个目录下的文件会累加其他设置进入 /usr/lib/systemd/system/vsftpd.service 内喔!
/etc/systemd/system/vsftpd.service.wants/*:此目录内的文件为链接档,设置相依服务的连结。 意思是启动了vsftpd.service 之后,最好再加上这目录底下建议的服务。
/etc/systemd/system/vsftpd.service.requires/*:此目录内的文件为链接档,设置相依服务的连结。 意思是在启动 vsftpd.service 之前,需要事先启动哪些服务的意思。
基本上,在配置文件里面你都可以自由设置相依服务的检查,并且设置加入到哪些 target 里头去。 但是如果是已经存在的配置文件,或者是官方提供的配置文件, Red Hat 是建议你不要修改原设置, 而是到上面提到的几个目录去进行额外的客制化设置比较好!当然,这见仁见智~如果你硬要修改原 始的 /usr/lib/systemd/system 底下的配置文件,那也是 OK 没问题的!并且也能够减少许多配置文件 的增加~自己认为,这样也不错!反正,就完全是个人喜好啰~

systemctl 配置文件的设置项目简介

回到顶部

现在来了解一下配置文件的内容!我们以sshd.service为例:

              [root@initroot ~]# cat /usr/lib/systemd/system/sshd.service
              [Unit] 这个项目与此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] 这个项目说明此unit挂载在哪个target下
              WantedBy=multi-user.target
            
配置文件大概分为三个部份:
[Unit]: unit本身的说明,以及与其他unit的依赖关系;
[Service]或[Socket]或[Timer]或[Mount]或[Path]..:不同的unit type对应不同的设置项目.
service就是[Service]。[Service]内主要规范服务启动的脚本、环境配置文件名、重启服务的方式等;
[Install]:unit会在哪个运行模式target下启动!
设置项目是可以重复的,例如可以重复设置两个After,后面的设置会覆盖前面的! 如果要将设置复位,可以使用类似After=的设置,等号后面什么都没有,就将该设置复位了(reset)。
如果设置参数需要有是/否的项目(布尔值, boolean),你可以使用1, yes, true, on代表启动,用 0, no, false, off代表关闭!
空白行、开头为 # 或 ; 的那一行,都代表注释!
每个部份里面还有很多的设置细项,我们使用一个简单的表格来说明每个项目好了!
[Unit]部份设置参数
参数 参数意义
Description systemctl list-units输出的简易说明,systemctl status输出的服务说明也取自这里! 这个项目可以提供管理员进一步的文件查询的功能!提供的文件可以是如下的资料:
Documentation
Documentation=http://www....
Documentation=man:sshd(8)
Documentation=file:/etc/ssh/sshd_config
After 说明此unit是在哪个unit启动之后才启动的意思!基本上仅是说明服务启动的顺序,并没有强制要求服务一定要启动后此unit才能启动。 以 sshd.service 的内容为例,该文件提到After后面有network.target以及sshd-keygen.service,但是若这两个unit没有启动而强制启动sshd.service, sshd.service应该还是能够启动的!这与Requires的设置是有差异!
Before Before与After的意义相反,是在什么服务启动前最好启动这个服务。不过这仅是规范服务启动的顺序,并非强制要求的意思。
Requires Requires 明确定义此unit需要在哪个unit启动后才能够启动!就是设置依赖服务!如果在此项设置的服务没有启动,那么此unit就不会被启动!
Wants Wants 与 Requires 刚好相反,规范的是这个 unit 之后最好还要启动什么服务比较好!不过,并没有明确的规范!主要的目的是希望建立让使用者比较好操作的环境。 因此,Wants后面接的服务即使没有启动,也不会影响到这个unit!
Conflicts Conflicts 代表冲突的服务!亦即这个项目后面接的服务如果有启动,那么我们这个unit就不能启动!该unit启动,则此项目后的服务就不能启动! 就是冲突性的检查!
[Service]部份设置参数
参数 参数意义
Type Type 说明unit启动的方式,会影响到ExecStart!这里unit的类型为service,所以这里所说的unit其实就是我们经常提到的守护进程了!
一般来说,有底下几种类型:
simple:默认值,daemon主要由ExecStart接的指令串来启动,启动后常驻于内存中。
forking:由ExecStart启动的程序通过spawns延伸出其他子程序来作为此daemon的主要服务。原生的父程序在启动结束后就会终止运作。传统的unit服务大多属于这种项目, 例如 httpd 这个 WWW 服务,当 httpd 的程序因为运作过久因此即将终结了,则 systemd 会再重新生出另一个子程序持续运作后, 再将父程序删除。据说这样的效能比较好!
oneshot:与simple类似,不过进程在工作完毕后就结束了,不会常驻在内存中。
dbus:与simple类似,但这个daemon必须要在取得一个D-Bus的名称后,才会继续运作!因此设置这个项目时,通常也要设置 BusName=!
idle:与simple类似,意思是,要执行这个daemon必须要所有的工作都顺利执行完毕后才会执行。这类的daemon通常是开机到最后才执行的服务!
比较重要的项目大概是 simple, forking 与 oneshot 了!
毕竟很多服务需要子进程(forking),而有更多的动作只需要在开机的时候执行一次(oneshot),例如文件系统的检查与挂载等。
EnvironmentFile EnvironmentFile 可以指定启动脚本的环境配置文件!例如sshd.service的配置文件写入到/etc/sysconfig/sshd当中! 也可以使用Environment=后面接多个不同的Shell变量来给予设置!
Before ExecStart就是实际执行此daemon的指令或脚本程序 。 也可以使用ExecStartPre(之前)以及ExecStartPost(之后)两个设置项目来在实际启动服务前,进行额外的指令行为。 指令串仅接受指令 参数 参数...的格式,不能接受 <, >, >>, |, & 等特殊字符,很多的bash语法也不支持! 要使用这些特殊的字符时,最好直接写入到指令脚本里面去!不过,上述的语法也不是完全不能用,亦即,若要支持比较完整的bash语法,那你得要使用Type=oneshot才行! 其他的Type不能支持这些字符。
ExecStop ExecStop 与systemctl stop的执行有关,关闭此服务时所进行的指令。
ExecReload ExecReload 与 systemctl reload有关的指令行为
Restart Restart 当设置Restart=1时,则当此daemon服务终止后,会再次的启动此服务。
举例来说,在tty2使用文字界面登入,操作完毕后注销,基本上,这个时候tty2就已经结束服务了。
但是你会看到屏幕又立刻产生一个新的tty2的登入画面等待你的登入!
那就是 Restart 的功能!
除非使用systemctl强制将此服务关闭,否则这个服务会源源不绝的一直重复产生!
RemainAfterExit RemainAfterExit 当设置为RemainAfterExit=1时,则当这个daemon所属的所有程序都终止之后,此服务会再尝试启动。这对于Type=oneshot的服务很有帮助!
TimeoutSec TimeoutSec 若这个服务在启动或者是关闭时,因为某些缘故导致无法顺利正常启动或正常结束的情况下,则我们要等多久才进入强制结束的状态!
KillMode KillMode 可以是process, control-group, none其中一种,如果是process则daemon终止时,只会终止主要的程序(ExecStart接的后面那串指令), 如果是control-group时, 则由此daemon所产生的其他control-group的程序,也都会被关闭。
如果是none的话,则没有程序会被关闭喔!
RestartSec RestartSec与Restart有点相关性,如果这个服务被关闭,然后需要重新启动时,大概要sleep多少时间再重新启动的意思。预设是100ms(毫秒)。
TimeoutSec TimeoutSec 若这个服务在启动或者是关闭时,因为某些缘故导致无法顺利正常启动或正常结束的情况下,则我们要等多久才进入强制结束的状态!
TimeoutSec KillMode 可以是process, control-group, none其中一种,如果是process则daemon终止时,只会终止主要的程序(ExecStart接的后面那串指令), 如果是control-group时, 则由此daemon所产生的其他control-group的程序,也都会被关闭。
如果是none的话,则没有程序会被关闭喔!
RestartSec RestartSec与Restart有点相关性,如果这个服务被关闭,然后需要重新启动时,大概要sleep多少时间再重新启动的意思。预设是100ms(毫秒)。
[Install]部份设置参数
参数 参数意义
WantedBy WantedBy 这个设置后面接的大部分是*.target unit!意思是,这个unit本身是附挂在哪一个target unit底下的! 一般来说,大多的服务性质的unit都是附挂在multi-user.target底下!
Also Also 当目前这个unit本身被enable时,Also后面接的unit也请enable的意思!也就是具有相依性的服务可以写在这里呢!
Alias Alias 进行一个连结的别名的意思!当systemctl enable相关的服务时,则此服务会进行连结档的建立! 以multi-user.target为例,这个家伙是用来作为预设操作环境default.target的规划, 因此当你设置用成default.target时 , 这个/etc/systemd/system/default.target就会连结到/usr/lib/systemd/system/multi-user.target!

通过systemctl管理不同的操作环境(target unit)

回到顶部

最新的linux发行版已经取消了linux运行级别的概念,取而代之的是target unit。
target可以理解为系统的运行模式,我们在linux启动运行模式中说过linux分为文本模式和图形模式,这两种模式就是用target unit来表示。
target可以用来模拟运行级别。
当然了除了文本模式和图形模式外,linux下可不止只有这两种运行模式。
通过list-units观察系统中有哪些target:

              [root@initroot ~]# systemctl list-units --type=target --all
              UNIT                   LOAD      ACTIVE   SUB    DESCRIPTION                  
              ● all.target             not-found inactive dead   all.target                   
              basic.target           loaded    active   active Basic System                 
              cryptsetup.target      loaded    active   active Local Encrypted Volumes      
              emergency.target       loaded    inactive dead   Emergency Mode               
              getty-pre.target       loaded    inactive dead   Login Prompts (Pre)          
              getty.target           loaded    active   active Login Prompts                
              graphical.target       loaded    active   active 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    inactive dead   Network is Online            
              network-pre.target     loaded    inactive dead   Network (Pre)                
              network.target         loaded    active   active Network                      
              nss-lookup.target      loaded    active   active Host and Network Name Lookups
              nss-user-lookup.target loaded    active   active User and Group Name Lookups  
              paths.target           loaded    active   active Paths                        
              remote-fs-pre.target   loaded    inactive dead   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    active   active Sound Card                   
              swap.target            loaded    active   active Swap                         
              sysinit.target         loaded    active   active System Initialization        
              time-sync.target       loaded    active   active 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.

              28 loaded units listed.
              To show all installed unit files use 'systemctl list-unit-files'.
            
在linuxmint下就有28 个target unit!
和操作界面相关性较高的target主要关注下面几个:
graphical.target:就是图形界面模式,当然我们以前提到过图形界面模式其实就是在文本模式的基础上开启了x window以及一些窗口管理器, 所以graphical.target首先依赖的就是下面的multi-user.target!
multi-user.target:纯文本模式!
rescue.target:rescue救援模式。在无法使用root登入的情况下,systemd在开机时会多加一个额外的暂时系统,与你原本的系统无关。 这时你可以取得root的权限来维护你的系统。但这是额外系统,因此可能需要用到chroot来取得你原有的系统!
emergency.target:emergency紧急救援模式。紧急处理系统的错误,还是需要使用root登入的情况,在无法使用rescue.target时,可以尝试使用这种模式!
shutdown.target:就是关机的流程。
getty.target:可以设置你需要几个tty之类的,如果想要降低tty的数目,可以修改这个东西的配置文件!
正常的模式是multi-user.target以及graphical.target两个,也是最经常使用的两种模式了。救援方面的模式主要是rescue.target以及更严重的emergency.target。 如果要修改可提供登入的tty数量,则修改getty.target。
              [root@initroot ~]# systemctl [command] [unit.target]
            
和target有关的选项与参数:
command:
get-default :获取当前target
set-default :设置后面接的target成为默认的操作模式
isolate :切换到后面接的模式
上面三个选项我们在讲解linux运行模式的时候就已经使用过了。这里再象征性的复习了解一下: 查看当前系统的默认的启动运行模式:
              [root@initroot ~]# systemctl get-default
              graphical.target  # 果然是图形界面喔!
            
可以看到当前系统默认启动运行模式为graphical.target,即图形模式。
也就是说每次linux系统在开机后默认就会进入图形模式。
我们将系统启动模式设置为纯文本模式:
              [root@initroot ~]# systemctl set-default multi-user.target
              [root@initroot ~]# systemctl get-default
                multi-user.target
            
这样下次再系统重启开机的时候就会进入纯文本模式。
上面设置的是系统默认启动模式,如果不想重启就使设置生效,那就使用isolate直接切换当前系统的运行模式:
              [root@initroot ~]# systemctl isolate multi-user.target
            
这样立刻就会变为纯文本模式,但是下次重启的时候还是会进入图形界面模式。 将运行模式切换回图形界面模式:
              [root@initroot ~]# systemctl isolate graphical.target
            
注意这里的systemctl的start/stop/restart命令选项无法应用于target,只能使用这里介绍的set-default、get-default和isolate。
除了上面介绍的图形模式和文本模式的切换,systemd也提供了几个简单的命令用于切换操作模式:
              [root@initroot ~]# systemctl poweroff #系统关机
              [root@initroot ~]# systemctl reboot #重新启动
              [root@initroot ~]# systemctl suspend #进入暂停模式
              [root@initroot ~]# systemctl hibernate #进入休眠模式
              [root@initroot ~]# systemctl rescue #强制进入救援模式
              [root@initroot ~]# systemctl emergency #强制进入紧急救援模式
            
suspend:暂停模式会将系统的状态数据保存到内存中,然后关闭掉大部分的系统硬件,并没有实际关机! 当用户按下唤醒机器的按钮,系统数据会重内存中回复,然后重新驱动被大部分关闭的硬件,就 开始正常运作!唤醒的速度较快。
hibernate:休眠模式则是将系统状态保存到硬盘当中,保存完毕后,将计算机关机。当用户尝试唤醒系统时,系统会开始正常运作, 然后将保存在硬盘中的系统状态恢复回来。因为数据是由硬盘读出,因此唤醒的效 能与你的硬盘速度有关。

网络服务与端口对应简介

回到顶部

系统的某些服务功能都是由对应的进程提供,进程则是由运行对应的程序而产生。 系统提供的网络服务也是有对应的进程提供! 只不过网络牵涉到TCP/IP概念,相对比较复杂。IP代表主机在因特网(Internet)上的门牌号码。
一般主机上会同时运行着多个网络服务进程, 但是主机只有一个ip,那么客户端是怎么找到对应的服务进程的呢?
其实每个网络服务进程会绑定一个端口号(port number),ip和端口号的组合就唯一标识了网络中的一个服务进程。
所以网络服务简单的理解为绑定网络端口的服务就是网络服务。
例如我的主机上同时运行着提供www服务的http进程,和提供ftp服务的ftp进程,
在浏览器中分别通过如下方式访问http服务进程和ftp服务进程:

http://192.168.1.121 ftp://192.168.1.121
这里仅以局域网为例,如果是internet,只需要把局域网ip改成对应的域名即可。
同样都是访问192.168.1.121这台主机,但是这两种方式访问的是同一台主机上面的两个不同的进程。
怎么找到对应的进程呢?就是通过端口号,http进程绑定在80端口,ftp进程绑定在21端口, 这样通过http://192.168.1.121访问主机的时候,就直接找到80端口即可,找到80端口也就找到了对应的服务进程了。ftp也同样如此。
每个提供网络服务的进程都会绑定一个网络端口,那么这些端口可以随便绑定吗? 是可以随便绑定的,只要服务器和客户端双方商量好即可,即双方协商好通信协议。
但是随着网络服务越来越多,如果每个服务进程都随便占用网络端口,就会出现混乱。
比如http服务进程在这台主机占用了80端口,在另一台主机占用了21端口,即使服务端事先和客户端商量好了,也会把客户端烦死。
为了统一整个因特网的端口号对应的网络服务,让所有的主机都能够使用相同的机制来请求或提供服务, 于是大家坐在一起商量,干脆约定好以后http就只占用80端口,ftp就只占用21端口。
这些约定放在一个文件中,这就是/etc/services文件:
              [root@initroot ~]# cat /etc/services
              ...省略...
              ftp 21/tcp ftp 21/udp ssh 22/tcp # The Secure Shell (SSH) Protocol
              ssh		22/tcp				# SSH Remote Login Protocol
              fsp fspd
              ...省略...
              http 80/tcp www www-http # WorldWideWeb HTTP
              http 80/udp www www-http # HyperText Transfer Protocol
              ...省略...

              # <daemon name> <port/封包协议> <该服务的说明>
            
第一栏为daemon名称、第二栏为该daemon所使用的端口号与网络数据封包协议, 封包协议主要分为可靠连接的TCP封包以及较快速但为非面向连接的UDP封包。 例如提供远程连接服务的ssh,使用的端口号就是22!使用数据传输协议为tcp
切记尽量不要修改/etc/services文件中的端口设置, 除非你要架设一个地下网站。

关闭网络服务

回到顶部

除了使用systemctl观察提供Linux系统基础操作环境的本地服务,网络服务才是在系统运维中要重点关注的。一般本地服务都不想要更改设置,保持默认的即可。
/etc/services文件是对服务和端口的一个约定性文件,如果查看当前系统中开启了哪些端口呢?通过netstat命令查看:

              [root@initroot ~]# netstat -tlunp
              Active Internet connections (only servers)
              Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
              tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      337/nginx: master p 
              tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      1193/mysqld         
              tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      337/nginx: master p 
              tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      337/nginx: master p 
              tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1242/sshd           
              tcp        0      0 0.0.0.0:3000            0.0.0.0:*               LISTEN      26447/node          
              tcp6       0      0 :::80                   :::*                    LISTEN      337/nginx: master p 
              udp        0      0 0.0.0.0:68              0.0.0.0:*                           717/dhclient  
              udp        0      0 0.0.0.0:5353            0.0.0.0:*                           750/avahi-daemon: r
              udp        0      0 0.0.0.0:36540           0.0.0.0:*                           750/avahi-daemon: r      
              udp        0      0 172.31.47.31:123        0.0.0.0:*                           492/ntpd            
              udp        0      0 127.0.0.1:123           0.0.0.0:*                           492/ntpd            
              udp        0      0 0.0.0.0:123             0.0.0.0:*                           492/ntpd            
              udp6       0      0 :::123                  :::*                                492/ntpd            
            
如上表所示,系统至少开启了22, 443, 3000, 80, 8080,3306,5353, 36540这些端口。
5353和36540是由avahi-daemon进程开启! 使用systemctl观察一下avahi-daemon服务:
              [root@initroot ~]# systemctl list-units --all | grep avahi-daemon
              avahi-daemon.service loaded active running Avahi mDNS/DNS-SD Stack
              avahi-daemon.socket loaded active running Avahi mDNS/DNS-SD Stack Activation Socket
            
avahi-daemon的目的是在局域网络进行类似网芳的搜寻,这个服务可以协助你在局域网内随时了解即插即用的设备! 包括笔记本电脑等,只要连上你的区网,你就能够知道谁进来了。 可能不太需要这个服务,关闭吧:
              [root@initroot ~]# systemctl stop avahi-daemon.service
              [root@initroot ~]# systemctl stop avahi-daemon.socket
              [root@initroot ~]# systemctl disable avahi-daemon.service avahi-daemon.socket
              [root@initroot ~]# netstat -tlunp
              Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
              tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1340/sshd
              tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 2387/master
              tcp6 0 0 :::555 :::* LISTEN 29113/vsftpdtcp6 0 0 :::22 :::* LISTEN 1340/sshd
              tcp6 0 0 ::1:25 :::* LISTEN 2387/master
            
一般来说,本地服务器至少需要25号端口,22号端口最好加上防火墙来管理远程联机登入。

两个 vsftpd 运作的实例

回到顶部

上面将vsftpd服务的 port 改成 555 号了。有时可能需要使用两个端口,分别是正常的 21 以及特殊的 555 ! 就得要使用到两个配置文件以及两个启动脚本了!现在假设是这样:
预设的 port 21:使用 /etc/vsftpd/vsftpd.conf 配置文件,以及 /usr/lib/systemd/system/vsftpd.service 设置脚本;
特殊的 port 555:使用 /etc/vsftpd/vsftpd2.conf 配置文件,以及 /etc/systemd/system/vsftpd2.service 设置脚本。
我们可以这样作:
1. 先建立好所需要的配置文件

              [root@initroot ~]# cd /etc/vsftpd
              [root@initroot vsftpd]# cp vsftpd.conf vsftpd2.conf
              [root@initroot vsftpd]# vim vsftpd.conf
              #listen_port=555
              [root@initroot vsftpd]# diff vsftpd.conf vsftpd2.conf
              128c128
              < #listen_port=555
              ---
              > listen_port=555
            
注意这两个配置文件的差别喔!只有这一行不同而已!
2. 开始处理启动脚本设置
              [root@initroot vsftpd]# cd /etc/systemd/system
              [root@initroot system]# cp /usr/lib/systemd/system/vsftpd.service vsftpd2.service
              [root@initroot system]# vim vsftpd2.service
              [Unit]
              Description=Vsftpd second ftp daemon
              After=network.target
              [Service]
              Type=forking
              ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd2.conf
              [Install]
              WantedBy=multi-user.target# 重点在改了 vsftpd2.conf 这个配置文件喔!
            
3. 重载 systemd 的脚本配置文件内容
              [root@initroot system]# systemctl daemon-reload
              [root@initroot system]# systemctl list-unit-files --all | grep vsftpd
              vsftpd.service enabled
              vsftpd2.service disabled
              vsftpd@.service disabled
              vsftpd.target disabled
              [root@initroot system]# systemctl status vsftpd2.service
              vsftpd2.service - Vsftpd second ftp daemon
              Loaded: loaded (/etc/systemd/system/vsftpd2.service; disabled)
              Active: inactive (dead)
              [root@initroot system]# systemctl restart vsftpd.service vsftpd2.service
              [root@initroot system]# systemctl enable vsftpd.service vsftpd2.service
              [root@initroot system]# systemctl status vsftpd.service vsftpd2.service
              vsftpd.service - Vsftpd ftp daemon
              Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled)
              Active: active (running) since Wed 2015-08-12 22:00:17 CST; 35s ago
              Main PID: 12670 (vsftpd)
              CGroup: /system.slice/vsftpd.service
              └─12670 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
              Aug 12 22:00:17 study.centos.initroot systemd[1]: Started Vsftpd ftp daemon.
              vsftpd2.service - Vsftpd second ftp daemon
              Loaded: loaded (/etc/systemd/system/vsftpd2.service; enabled)
              Active: active (running) since Wed 2015-08-12 22:00:17 CST; 35s ago
              Main PID: 12672 (vsftpd)
              CGroup: /system.slice/vsftpd2.service
              └─12672 /usr/sbin/vsftpd /etc/vsftpd/vsftpd2.conf
              [root@initroot system]# netstat -tlnp
              Active Internet connections (only servers)
              Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
              tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1340/sshd
              tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 2387/master
              tcp6 0 0 :::555 :::* LISTEN 12672/vsftpd
              tcp6 0 0 :::21 :::* LISTEN 12670/vsftpd
              tcp6 0 0 :::22 :::* LISTEN 1340/sshd
              tcp6 0 0 ::1:25 :::* LISTEN 2387/master
            
很简单的将你的 systemd 所管理的 vsftpd 做了另一个服务!未来如果有相同的需求,同样的方法作一遍即可!

多重的重复设置方式:以 getty 为例

回到顶部

我们的 CentOS 7 开机完成后,不是说有 6 个终端机可以使用吗?就是那个 tty1~tty6 的啊!那个东西是由 agetty 这个指令达成的。 OK!那么这个终端机的功能又是从哪个项目所提供的呢?其实,那个东东涉及很多层面,主要管理的是 getty.target 这个 target unit , 不过,实际产生 tty1~tty6 的 则是由 getty@.service 所提供的!咦!那个 @ 是啥东西?
先来查阅一下 /usr/lib/systemd/system/getty@.service 的内容好了:

              [root@initroot ~]# cat //usr/lib/systemd/system/getty@.service
              [Unit]
              Description=Getty on %I
              Documentation=man:agetty(8) man:systemd-getty-generator(8)
              Documentation=http://0pointer.de/blog/projects/serial-console.html
              After=systemd-user-sessions.service plymouth-quit-wait.service
              After=rc-local.service
              Before=getty.target
              ConditionPathExists=/dev/tty0
              [Service]
              ExecStart=-/sbin/agetty --noclear %I $TERM
              Type=idle
              Restart=always
              RestartSec=0
              UtmpIdentifier=%I
              TTYPath=/dev/%I
              TTYReset=yes
              TTYVHangup=yes
              TTYVTDisallocate=yes
              KillMode=process
              IgnoreSIGPIPE=no
              SendSIGHUP=yes
              [Install]
              WantedBy=getty.target
            
比较重要的当然就是 ExecStart 项目啰!那么我们去 man agetty 时,发现到它的语法应该是 agetty --noclear tty1 之类的字样, 因此,我们如果要启动六个 tty 的时候,基本上应该要有六个启动配 置文件。亦即是可能会用到 getty1.service, getty2.service...getty6.service 才对! 哇!这样控管很麻烦 啊~所以,才会出现这个 @ 的项目啦!咦!这个 @ 到底怎么回事呢?我们先来看看 getty@.service 的上游,亦即是 getty.target 这个东西的内容好了!
              [root@initroot ~]# systemctl show getty.target
              # 那个 show 的指令可以将 getty.target 的默认设置值也取出来显示!
              Names=getty.target
              Wants=getty@tty1.service
              WantedBy=multi-user.target
              Conflicts=shutdown.target
              Before=multi-user.target
              After=getty@tty1.service getty@tty2.service getty@tty3.service getty@tty4.service
              getty@tty6.service getty@tty5.service
              .....(后面省略).....
            
你会发现,咦!怎么会多出六个怪异的 service 呢?我们拿 getty@tty1.service 来说明一下好了!当 我们执行完 getty.target 之后, 他会持续要求 getty@tty1.service 等六个服务继续启动。那我们的 systemd 就会这么作:
先看 /usr/lib/systemd/system/, /etc/systemd/system/ 有没有 getty@tty1.service 的设置,若有就执行,若没有 则执行下一步;
找 getty@.service 的设置,若有则将 @ 后面的数据带入成 %I 的变量,进入 getty@.service 执行! 这也就是说,其实 getty@tty1.service 实际上是不存在的!他主要是通过 getty@.service 来执行~也 就是说, getty@.service 的目的是为了要简化多个执行的启动设置, 他的命名方式是这样的:
源文件:执行服务名称@.service 执行文件:执行服务名称@范例名称.service 因此当有范例名称带入时,则会有一个新的服务名称产生出来!你再回头看看 getty@.service 的启动 脚本:
ExecStart=-/sbin/agetty --noclear %I $TERM
上表中那个 %I 指的就是范例名称!根据 getty.target 的信息输出来看,getty@tty1.service 的 %I 就是 tty1 啰!因此执行脚本就会变成 /sbin/agetty --noclear tty1 ! 所以我们才有办法以一个配 置文件来启动多个 tty1 给用户登入啰!
将 tty 的数量由 6 个降低到 4 个 现在你应该要感到困扰的是,那么 6 个 tty 是谁规定的为什么不是 5 个还是 7 个?这是因为 systemd 的登入配置文件 /etc/systemd/logind.conf 里面规范的啦! 假如你想要让 tty 数量降低到剩 下 4 个的话,那么可以这样实验看看:
# 1. 修改预设的 logind.conf 内容,将原本 6 个虚拟终端机改成 4 个
              [root@initroot ~]# vim /etc/systemd/logind.conf
              [Login]NAutoVTs=4
              ReserveVT=0
            
# 原本是 6 个而且还注释,请取消注释,然后改成 4 吧!
# 2. 关闭不小心启动的 tty5, tty6 并重新启动 getty.target 啰!
              [root@initroot ~]# systemctl stop getty@tty5.service
              [root@initroot ~]# systemctl stop getty@tty6.service
              [root@initroot ~]# systemctl restart systemd-logind.service
            
现在你再到桌面环境下,按下 [ctrl]+[alt]+[F1]~[F6] 就会发现,只剩下四个可用的 tty 啰!后面的 tty5, tty6 已经被放弃了!不再被启动喔! 好!那么我暂时需要启动 tty8 时,又该如何处理呢?需要重 新建立一个脚本吗?不需要啦!可以这样作!
              [root@initroot ~]# systemctl start getty@tty8.service
            
无须额外建立其他的启动服务配置文件喔!
暂时新增 vsftpd 到 2121 端口
不知道你有没有发现,其实在 /usr/lib/systemd/system 底下还有个特别的 vsftpd@.service 喔!来看看 他的内容:
              [root@initroot ~]# cat /usr/lib/systemd/system/vsftpd@.service
              [Unit]
              Description=Vsftpd ftp daemon
              After=network.target
              PartOf=vsftpd.target
              [Service]
              Type=forking
              ExecStart=/usr/sbin/vsftpd /etc/vsftpd/%i.conf
              [Install]
              WantedBy=vsftpd.target
            
根据前面 getty@.service 的说明,我们知道在启动的脚本设置当中, %i 或 %I 就是代表 @ 后面 接的范例文件名的意思! 那我能不能建立 vsftpd3.conf 文件,然后通过该文件来启动新的服务呢? 就来玩玩看!
# 1. 根据 vsftpd@.service 的建议,于 /etc/vsftpd/ 底下先建立新的配置文件
              [root@initroot ~]# cd /etc/vsftpd
              [root@initroot vsftpd]# cp vsftpd.conf vsftpd3.conf
              [root@initroot vsftpd]# vim vsftpd3.conflisten_port=2121
            
# 2. 暂时启动这个服务,不要永久启动他!
              [root@initroot vsftpd]# systemctl start vsftpd@vsftpd3.service
              [root@initroot vsftpd]# systemctl status vsftpd@vsftpd3.service
              vsftpd@vsftpd3.service - Vsftpd ftp daemon
              Loaded: loaded (/usr/lib/systemd/system/vsftpd@.service; disabled)
              Active: active (running) since Thu 2015-08-13 01:34:05 CST; 5s ago
              [root@initroot vsftpd]# netstat -tlnp
              Active Internet connections (only servers)
              Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
              tcp6 0 0 :::2121 :::* LISTEN 16404/vsftpd
              tcp6 0 0 :::555 :::* LISTEN 12672/vsftpd
              tcp6 0 0 :::21 :::* LISTEN 12670/vsftpd
            
因为我们启用了 vsftpd@vsftpd3.service ,代表要使用的配置文件在 /etc/vsftpd/vsftpd3.conf 的意思! 所以可以直接通过 vsftpd@.service 而无须重新设置启动脚本! 这样是否比前几个小节的方法还要简 便呢? ^_^。通过这个方式,你就可以使用到新的配置文件啰!只是你得要注意到 @ 这个东西就是 了! ^_^
聪明的读者可能立刻发现一件事,为啥这次 FTP 增加了 2121 端口却不用修改 SELinux 呢?这是因为默认启动小于 1024 号码以下的端口口时, 需要使用到 root 的权限,因此小于 1024 以下 端口的启动较可怕。而这次范例中,我们使用 2121 端口口,他对于系统的影响可能小一些 (其实一样可怕!), 所 以就忽略了 SELinux 的限制了!

自己的服务自己作

回到顶部

我们来模拟自己作一个服务吧!假设我要作一只可以备份自己系统的服务,这只脚本我放在 /backups 底下,内容有点像这样:

              [root@initroot ~]# vim /backups/backup.sh
              #!/bin/bash
              source="/etc /home /root /var/lib /var/spool/{cron,at,mail}"
              target="/backups/backup-system-$(date +%Y-%m-%d).tar.gz"
              [ ! -d /backups ] && mkdir /backups
              tar -zcvf ${target} ${source} &> /backups/backup.log
              [root@initroot ~]# chmod a+x /backups/backup.sh
              [root@initroot ~]# ll /backups/backup.sh
              -rwxr-xr-x. 1 root root 220 Aug 13 01:57 /backups/backup.sh
            
# 记得要有可执行的权限才可以喔!
接下来,我们要如何设计一只名为 backup.service 的启动脚本设置呢?可以这样做喔!
              [root@initroot ~]# vim /etc/systemd/system/backup.service
              [Unit]
              Description=backup my server
              Requires=atd.service
              [Service]
              Type=simple
              ExecStart=/bin/bash -c " echo /backups/backup.sh | at now"
              [Install]
              WantedBy=multi-user.target
            
# 因为 ExecStart 里面有用到 at 这个指令,因此, atd.service 就是一定要的服务!
              [root@initroot ~]# systemctl daemon-reload
              [root@initroot ~]# systemctl start backup.service
              [root@initroot ~]# systemctl status backup.service
              backup.service - backup my server
              Loaded: loaded (/etc/systemd/system/backup.service; disabled)
              Active: inactive (dead)
              Aug 13 07:50:31 study.centos.initroot systemd[1]: Starting backup my server...
              Aug 13 07:50:31 study.centos.initroot bash[20490]: job 8 at Thu Aug 13 07:50:00 2015
              Aug 13 07:50:31 study.centos.initroot systemd[1]: Started backup my server.
            
# 为什么 Active 是 inactive 呢?这是因为我们的服务仅是一个简单的 script 啊!
# 因此执行完毕就完毕了,不会继续存在内存中喔!
完成上述的动作之后,以后你都可以直接使用 systemctl start backup.service 进行系统的备份了!而且
会直接丢进 atd 的管理中, 你就无须自己手动用 at 去处理这项任务了~好像还不赖喔! ^_^
这样自己做一个服务好像也不难啊! ^_^!自己动手玩玩看吧!

systemctl timer的配置

回到顶部

有时候,某些服务你想要定期执行,或者是开机后执行,或者是什么服务启动多久后执行等等的。在 过去,我们大概都是使用 crond 这个服务来定期处理, 不过,既然现在有一直常驻在内存当中的 systemd 这个好用的东西,加上这 systemd 有个协力服务,名为 timers.target 的家伙,这家伙可以协助定期处理各种任务! 那么, 除了 crond 之外,如何使用 systemd 内建的 time 来处理各种任务呢?
这就是本小节的重点啰!

在 archlinux 的官网 wiki 上面有提到,为啥要使用 systemd.timer 呢? 由于所有的 systemd 的服务产生的信息都会被纪录 (log),因此比 crond 在 debug 上面要更清楚方便的多;
各项 timer 的工作可以跟 systemd 的服务相结合;
各项 timer 的工作可以跟 control group (cgroup,用来取代 /etc/secure/limit.conf 的功能) 结合,来限制该工 作的资源利用 虽然还是有些弱点啦~例如 systemd 的 timer 并没有 email 通知的功能 (除非自己写一个),也没有 类似 anacron 的一段时间内的随机取样功能 (random_delay), 不过,总体来说,还是挺不错的!此 外,相对于 crond 最小的单位到分, systemd 是可以到秒甚至是毫秒的单位哩!相当有趣!
任务需求
基本上,想要使用 systemd 的 timer 功能,你必须要有几个要件:
系统的 timer.target 一定要启动
要有个 sname.service 的服务存在 (sname 是你自己指定的名称)
要有个 sname.timer 的时间启动服务存在
满足上面的需求就 OK 了!有没有什么案例可以来实作看看?这样说好了,我们上个小节不是才自 己做了个 backup.service 的服务吗?那么能不能将这个 backup.service 用在定期执行上面呢?好啊!
那就来测试看看!
sname.timer 的设置值
你可以到 /etc/systemd/system 底下去建立这个 *.timer 档,那这个文件的内容要项有哪些东西呢? 基本设置主要有底下这些: (man systemd.timer & man systemd.time)
[Timer] 部份设置参数 参数意义说明
OnActiveSec 当 timers.target 启动多久之后才执行这只unit
OnBootSec 当开机完成后多久之后才执行
OnStartupSec 当 systemd 第一次启动之后过多久才执行
OnUnitActiveSec 这个 timer 配置文件所管理的那个 unit 服务在最后一次启动后,隔多久后再执行一次的意思
OnUnitInactiveSec 这个 timer 配置文件所管理的那个 unit 服务在最后一次停止后,隔多久再执行一次的意思。
OnCalendar 使用实际时间 (非循环时间) 的方式来启动服务的意思!至于时间的格式后续再来谈。
Unit 一般 来说不太 需要设置,因 此如同上 面刚刚提到的 ,基本上 我们设置都是 sname.service + sname.timer,那如果你的 sname 并不相同时, 那在 .timer 的文件中, 就得要指定是哪一个service unit 啰!
Persistent 当使用 OnCalendar 的设置时,指定该功能要不要持续进行的意思。通常是设置为 yes ,比较能够满足类似 anacron 的功能喔!
基本的项目仅有这些而已,在设置上其实并不困难啦!
使用于 OnCalendar 的时间
如果你想要从 crontab 转成这个 timer 功能的话,那么对于时间设置的格式就得要了解了解~基本上的格式如下所示:
语法:英文周名 YYYY-MM-DD HH:MM:SS
范例:Thu 2015-08-13 13:40:00
上面谈的是基本的语法,你也可以直接使用间隔时间来处理!常用的间隔时间单位有:
us 或 usec:微秒 (10 -6 秒)
ms 或 msec:毫秒 (10 -3 秒)
s, sec, second, seconds
m, min, minute, minutes
h, hr, hour, hours
d, day, days
w, week, weeks
month, months
y, year, years
常见的使用范例有:
隔 3 小时: 3h 或 3hr 或 3hours
隔 300 分钟过 10 秒: 10s 300m
隔 5 天又 100 分钟: 100m 5day
# 通常英文的写法,小单位写前面,大单位写后面~所以先秒、再分、再小时、再天数等~ 此外,你也可以使用英文常用的口语化日期代表,例如 today, tomorrow 等!假设今天是 2015-08-13 13:50:00 的话,那么:
英文口语 实际的时间格式代表
now Thu 2015-08-13 13:50:00
today Thu 2015-08-13 00:00:00
tomorrow Thu 2015-08-14 00:00:00
hourly *-*-* *:00:00
daily *-*-* 00:00:00
weekly Mon *-*-* 00:00:00
monthly *-*-01 00:00:00
+3h10m Thu 2015-08-13 17:00:00
2015-08-16 Sun 2015-08-16 00:00:00
一个循环时间运作的案例
现在假设这样:
开机后 2 小时开始执行一次这个 backup.service
自从第一次执行后,未来我每两天要执行一次 backup.service
好了,那么应该如何处理这个脚本呢?可以这样做喔!

              [root@initroot ~]# vim /etc/systemd/system/backup.timer
              [Unit]
              Description=backup my server timer
              [Timer]
              OnBootSec=2hrs
              OnUnitActiveSec=2days
              [Install]
              WantedBy=multi-user.target
            
# 只要这样设置就够了!储存离开吧!
              [root@initroot ~]# systemctl daemon-reload
              [root@initroot ~]# systemctl enable backup.timer
              [root@initroot ~]# systemctl restart backup.timer
              [root@initroot ~]# systemctl list-unit-files | grep backup
              backup.service disabled
              backup.timer enabled
            
# 这个不需要启动!只要 enable backup.timer 即可!
              [root@initroot ~]# systemctl show timers.targetConditionTimestamp=Thu 2015-08-13 14:31:11 CST
              # timer 这个 unit 启动的时间!
              [root@initroot ~]# systemctl show backup.service
              ExecMainExitTimestamp=Thu 2015-08-13 14:50:19 CST
              # backup.service 上次执行的时间
              [root@initroot ~]# systemctl show backup.timer
              NextElapseUSecMonotonic=2d 19min 11.540653s
            
# 下一次执行距离 timers.target 的时间 如上表所示,我上次执行 backup.service 的时间是在 2015-08-13 14:50 ,由于设置两个小时执行一 次,因此下次应该是 2015-08-15 14:50 执行才对! 由于 timer 是由 timers.target 这个 unit 所管理 的,而这个 timers.target 的启动时间是在 2015-08-13 14:31 , 要注意,最终 backup.timer 所纪录的 下次运行时间,其实是与 timers.target 所纪录的时间差!因此是 2015-08-15 14:50 - 2015-08-13 14:31 才对! 所以时间差就是 2d 19min 啰!
一个固定日期运作的案例
上面的案例是固定周期运作一次,那如果我希望不管上面如何运作了,我都希望星期天凌晨 2 点运 作这个备份程序一遍呢?请注意,因为已经存在 backup.timer 了! 所以,这里我用 backup2.timer 来 做区隔喔!
              [root@initroot ~]# vim /etc/systemd/system/backup2.timer
              [Unit]
              Description=backup my server timer2
              [Timer]
              OnCalendar=Sun *-*-* 02:00:00
              Persistent=true
              Unit=backup.service
              [Install]
              WantedBy=multi-user.target
              [root@initroot ~]# systemctl daemon-reload
              [root@initroot ~]# systemctl enable backup2.timer
              [root@initroot ~]# systemctl start backup2.timer
              [root@initroot ~]# systemctl show backup2.timer
              NextElapseUSecRealtime=45y 7month 1w 6d 10h 30min
            
与循环时间运作差异比较大的地方,在于这个 OnCalendar 的方法对照的时间并不是 times.target 的启动时间,而是 Unix 标准时间!
亦即是 1970-01-01 00:00:00 去比较的!因此,当你看到最后出现的 NextElapseUSecRealtime 时,哇!
下一次执行还要 45 年 + 7 个月 + 1 周 + 6 天 + 10 小时过30 分~刚看到的时候,确实因此揉了揉眼睛~确定没有看错...这才了解原来比对的是日历时间而不是某个 unit 的启动时间啊!
呵呵!通过这样的方式,你就可以使用 systemd 的 timer 来制作属于你的时程规划服务啰!

早期的服务管理使用 systemV 的机制,通过 /etc/init.d/*, service, chkconfig, setup 等指令来管理服务的启动 /关闭/预设启动;
从 CentOS 7.x 开始,采用 systemd 的机制,此机制最大功能为平行处理,并采单一指令管理 (systemctl), 开机速度加快!
systemd 将各服务定义为 unit,而 unit 又分类为 service, socket, target, path, timer 等不同的类别,方便管理 与维护
启动/关闭/重新启动的方式为: systemctl [start|stop|restart] unit.service
设置预设启动/预设不启动的方式为: systemctl [enable|disable] unit.service
查询系统所有启动的服务用 systemctl list-units --type=service 而查询所有的服务 (含不启动) 使用 systemctl list-unit-files --type=service
systemd 取消了以前的 runlevel 概念 (虽然还是有兼容的 target),转而使用不同的 target 操作环境。常见 操作环境为 multi-user.targer 与 graphical.target。 不重新启动而转不同的操作环境使用 systemctl isolate unit.target,而设置预设环境则使用 systemctl set-default unit.target
systemctl 系统默认的配置文件主要放在 /usr/lib/systemd/system,管理员若要修改或自行设计时,则建议放 在 /etc/systemd/system/ 目录下。
管理员应使用 man systemd.unit, man systemd.service, man systemd.timer 查询 /etc/systemd/system/ 底下配置 文件的语法, 并使用 systemctl daemon-reload 加载后,才能自行撰写服务与管理服务喔!
除了 atd 与 crond 之外,可以 通过 systemd.timer 亦即 timers.target 的功能,来使用 systemd 的时间管 理功能。
一些不需要的服务可以关闭喔!
17.7 本章习题
( 要看答案请将鼠标移动到答:
底下的空白处,按下左键圈选空白处即可察看 )
情境模拟题:通过设置、启动、观察等机制,完整的了解一个服务的启动与观察现象。
o 目标:了解 daemon 的控管机制,以 sshd daemon 为例;o 前提:需要对本章已经了解,尤其是 systemd 的管理 部分; o 需求:已经有 sshd 这个服务,但没有修改过端口!
在本情境中,我们使用 sshd 这个服务来观察,主要是假设 sshd 要开立第二个服务,这个第二个服务的 port 放行于 222 ,那该如何处理? 可以这样做看看:
1. 基本上 sshd 几乎是一定会安装的服务!只是我们还是来确认看看好了!

              [root@initroot ~]# systemctl status sshd.service
              sshd.service - OpenSSH server daemon
              Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled)
              Active: active (running) since Thu 2015-08-13 14:31:12 CST; 20h ago
              [root@initroot ~]# 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
            
2. 通过观察 man sshd,我们可以查询到 sshd 的配置文件位于 /etc/ssh/sshd_config 这个文件内!再 man sshd_config 也能知道原来端口是使用 Port 来规范的! 因此,我想要建立第二个配置文件,文件名假设为 /etc/ssh/sshd2_config 这样!
              [root@initroot ~]# cd /etc/ssh
              [root@initroot ssh]# cp sshd_config sshd2_config
              [root@initroot ssh]# vim sshd2_config
              Port 222
            
# 随意找个地方加上这个设置值!你可以在文件的最下方加入这行也 OK 喔!3. 接下来开始修改启动脚本服务档!
              [root@initroot ~]# cd /etc/systemd/system
              [root@initroot system]# cp /usr/lib/systemd/system/sshd.service sshd2.service
              [root@initroot system]# vim sshd2.service
              [Unit]
              Description=OpenSSH server daemon 2
              After=network.target sshd-keygen.service
              Wants=sshd-keygen.service
              [Service]
              EnvironmentFile=/etc/sysconfig/sshd
              ExecStart=/usr/sbin/sshd -f /etc/ssh/sshd2_config -D $OPTIONS
              ExecReload=/bin/kill -HUP $MAINPID
              KillMode=process
              Restart=on-failure
              RestartSec=42s
              [Install]
              WantedBy=multi-user.target
              [root@initroot system]# systemctl daemon-reload
              [root@initroot system]# systemctl enable sshd2
              [root@initroot system]# systemctl start sshd2
              [root@initroot system]# tail -n 20 /var/log/messages
              # semanage port -a -t PORT_TYPE -p tcp 222
              where PORT_TYPE is one of the following: ssh_port_t, vnc_port_t, xserver_port_t.
            
# 认真的看!你会看到上面这两句!也就是 SELinux 的端口问题!请解决!
              [root@initroot system]# semanage port -a -t ssh_port_t -p tcp 222
              [root@initroot system]# systemctl start sshd2
              [root@initroot system]# netstat -tlnp | grep ssh
              tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1300/sshd
              tcp 0 0 0.0.0.0:222 0.0.0.0:* LISTEN 15275/sshd
              tcp6 0 0 :::22 :::* LISTEN 1300/sshd
              tcp6 0 0 :::222 :::* LISTEN 15275/sshd
            
简答题部分: 使用 netstat -tul 与 netstat -tunl 有什么差异?为何会这样?
使用 n 时, netstat 就不会使用主机名与服务名称 (hostname & service_name) 来显示, 取而代之的则是以 IP 及 port number 来显示的。 IP 的分析与 /etc/hosts 及 /etc/resolv.conf 有关, 这个在未来服务器篇才会提到。至于 port number 则与 /etc/services 有关,请自行参考喔! ^_^
你能否找出来,启动 port 3306 这个端口的服务为何? 通过搜寻 /etc/services 内容,得到 port 3306 为 mysql 所启动的端口喔!查询 google, 可得到 mysql 为一种网络数据库系统 软件。
你可以通过哪些指令查询到目前系统默认开机会启动的服务?
systemctl list-units 以及 systemctl list-unit-files
承上,那么哪些服务目前是在启动的状态?
结果同上!只是若要进一步的信息,应该使用 systemctl status [unit.service] 一项一项查询!

initroot编辑整理,转载请注明www.initroot.com