Linux是绝大多数服务器的选择,我曾不屑过。
但随着了解的深入,确实看到了Linux系统上的很多highlight,也愈发有想发扬Linux系统的精神,好在我现在基本上都在Linux上工作,这让我有足够的机会去挖掘它。
你有想过服务器上那么多服务在运行,它们都会怎样工作?服务是独立的个体,每个只管自己的死活,如果某个服务自己偷偷死了,会造成很严重的后果,且一种服务一种管理方式,这堆起来会累死老师傅的。
所以,Linux的管理服务能力是个香馍馍,就一点都不奇怪了。
linux 服务器主要的能力之一就是配置并管理系统上运行的各种服务程序。早初这种管理服务程序的能力就是由启动程序init系统负责的,随着Linux系统的迭代,早先的init系统已经由最初的sysvinit进化到了今天的systemd。
所以,systemd作为init系统的启动程序,负责管理运行在系统上的众多服务,而systemd管理的手段并不难,只需要学会如何编写运行服务的配置文件,就可以轻松管理服务了。
知道systemd能干活,那肯定要先找到这个干活的人。init系统挂载在/lib路径下,所以在/lib/systemd/system可以找到所有由systemd管理的配置文件,在/etc/systemd/system上可以发现其他的配置文件,这往往存放的是systemctl(systemd的可执行命令)enable服务时创建的软链接。
systemd进行任务管理的基本单元是Unit,配置文件有多种不同的类型,我们这只着重说service类型,因为service 类型的 unit 是真实代表一个后台服务进程。
这是一个prometheus的服务进程
[Unit]
Description=Prometheus Server
Documentation=https://prometheus.io/docs/introduction/overview/
After=network.target
[Service]
User=prometheus
Restart=on-failure
WorkingDirectory=/usr/local/share/prometheus/
ExecStart=/usr/local/share/prometheus/prometheus
-config.file=/usr/local/share/prometheus/prometheus.yml
[Install]
WantedBy=multi-user.target
先看下配置文件的内容
三个部分:
[Unit] unit 服务的说明,以及与它有依赖关系的服务设置,上面是在network服务之后才启动此 unit 的设置。
[Service] 是服务类型的 unit 要设置的,此外,timer 类型的 unit 应该是[Timer],socket 类型的 unit 应该是 [Socket],服务类型的 unit 就是 [Service],这个部分主要是配置规范服务启动的脚本、环境配置文件文件名、重新启动的方式等等。
[Install] 这个部分主要设置的是把该 unit 安装在哪个 target上。
systemd配置文件只有简单的三个部分,所以要想管理好后台程序,就必须要熟悉这些部分的脚本规范。
UnitDescription 关于该 unit 的说明。
Documentation 服务的文档
After 说明本unit是在哪个服务后启动。仅是说明服务启动的顺序而已,并没有强制要求。
Before 与After的意义相反。
Requires 本unit需要在哪个服务启动后才能够启动!这里设置服务间的依赖性。如果在此项设置的前导服务没有启动成功,那么本 unit 就不会被启动!
Wants 与Requires 刚好相反,规范的是这个unit之后还会启动什么服务,如果这Wants 后面接的服务如果没有启动成功,不会影响到这个unit本身!
Conflicts 这个项目后面接的服务如果有启动,那么本unit就不能启动!(互斥性) 如果本unit启动了,则指定的服务就不能启动。
Type 旨在说明这个服务的启动方式,会影响到 ExecStart,主要有下面几种类型:
1. simple:默认值,这个服务主要由ExecStart设置的程序来启动,启动后常驻于内存中。
2. forking:由ExecStart指定的启动的程序通过spawns产生子进程提供服务,然后父进程退出。
3. oneshot:与simple类似,不过这个程序在工作完毕后就结束了,不会常驻在内存中。
4. dbus:与simple类似,但这个服务必须要在取得一个D-Bus的名称后,才会继续运行!因此设置这个项目时,通常也要设置 BusName= 才行。
5. idle:与simple类似,意思是,要执行这个服务必须要所有的工作都顺利执行完毕后才会执行。这类的服务通常是开机到最后才执行即可的服务。
6. notify:与simple类似,但这个服务必须要收到一个sd_notify() 函数发送的消息后,才会继续运行。
ExecStart
就是实际执行此服务的程序。接受 “命令 参数 参数…” 的格式,不能接受 <, >, >>, |, & 等特殊字符,很多的 bash语法也不支持。所以,要使用这些特殊的字符时,最好直接写入到脚本里面去!
ExecStartPre和ExecStartPost分别在服务启动前后,执行额外的命令。
ExecStop用来实现systemctl stop命令,关闭服务。
ExecReload用来实现systemctl reload命令,重新加载服务的配置信息。
Restart当设置为 Restart=1 时,如果服务终止,就会自动重启此服务。
RestartSec与Restart配合使用,在服务终止多长时间之后才重新启动它。默认是 100ms。
KillMode
可以是 process, control-group, none 中的一种,如果是 process 则服务终止时,只会终止主要的程序(ExecStart接的后面那串指令),如果是 control-group 时,则由此 daemon 所产生的其他 control-group 的程序,也都会被关闭。如果是 none 的话,则没有程序会被关闭。
TimeoutSec
若这个服务在启动或者是关闭时,因为某些缘故导致无法顺利 “正常启动或正常结束” 的情况下,则我们要等多久才进入 “强制结束” 的状态!
RemainAfterExit
当设置为 RemainAfterExit=1 时,则当这个服务所属的所有程序都终止之后,此服务会再尝试启动。这对于 Type=oneshot 的服务很有帮助!
环境变量的设置对很多程序来说都是十分重要的,下面的配置则可以以不同的方式为服务程序设置环境变量:
一般在Service部分定义Environment=
[Service] Environment="GODEBUG='madvdontneed=1'" Environment="BEAT_LOG_OPTS=-e" Environment="BEAT_CONFIG_OPTS=-c /etc/v_filebeat.yml" Environment="BEAT_PATH_OPTS=-path.home /usr/share/filebeat -path.config /etc/filebeat -path.data /var/lib/data -path.logs /var/log/logs"
EnvironmentFile= 亦可以通过文件的方式设置环境变量。
[Service] EnvironmentFile=/testenv
可以在testenv文件上以shell命令书写变量声明。
GODEBUG='madvdontneed=1' BEAT_LOG_OPTS=-e BEAT_CONFIG_OPTS=-c /etc/v_filebeat.yml BEAT_PATH_OPTS=-path.home /usr/share/filebeat -path.config /etc/filebeat -path.data /var/lib/data -path.logs /var/log/logs
接下来可以在 ExecStart 配置中使用在文件中设置的环境变量。
installWantedBy这个设置后面接的大部分是 *.target unit。意思是,这个unit本身该附挂在哪个 target unit下面。
Also 当目前这个unit被enable时,Also 后面接的unit也要enable的意思。
Alias 当systemctl enable相关的服务时,则此服务会进行链接文件的创建!默认开启!
对了,一个后台服务的管理配置文件,是以.service后缀结尾的。
怎么管理服务如果写完一个服务,你就需要使用systemd的可执行命令systemctl去管理服务的开启和结束,一个完整的生命周期。
这是在写完ExecStart后就可以执行的
systemctl start httpd.service
ExecReload定义后可执行
systemctl reload httpd.service
结束可以定义ExecStop,也可以不定义
systemctl stop httpd.service
如果修改了.service配置文件
systemctl daemon-reload
查看具体的执行细节,就直接systemctl status httpd.service或者journalctl -xc进入日志。
一个例子收尾 通过脚本定时备份文件备份文件的 bash 脚本
#!/bin/bash
mydate()
{
date "+%Y%m%d%H%M%S"
}
backupdate=$(mydate)
tar -zcf /tmp/backup.${backupdate}.tar.gz /home/nick/learn
把上面的代码保存到文件 /usr/local/bin/backupdir.sh,并添加可执行权限:
$ sudo chmod +x /usr/local/bin/backupdir.sh
然后创建 service unit 配置文件:
[Unit] Description=nick backup learn dir service [Service] User=nick Group=nick Type=simple //* 执行可执行脚本 ExecStart=/usr/local/bin/backupdir.sh [Install] WantedBy=multi-user.target
把上面的 unit 配置保存到文件 /etc/systemd/system/nickbak.service。
然后执行下面的命令测试服务的执行情况:
$ sudo systemctl daemon-reload $ sudo systemctl start nickbak.service
上面的备份任务只会在执行 sudo systemctl start nickbak.service 时执行一次。但可以通过 timer unit把它配置为定时执行。
创建 timer unit 配置文件:
[Unit] Description=nick backup learn dir timer [Timer] //* 每15分钟执行一次Unit ‘nickbak.service’ OnCalendar=*:0/15 Persistent=true Unit=nickbak.service [Install] WantedBy=multi-user.target
把上面的 unit 配置保存到文件 /etc/systemd/system/nickbak.timer。配置中 OnCalendar=*:0/15 表示每 15 分钟执行一次 nickbak.service 服务。
执行下面的命令把 nickbak.timer 设置为开机启动,并启动 nickbak.timer:
$ sudo systemctl daemon-reload $ sudo systemctl enable nickbak.timer $ sudo systemctl start nickbak.timer结尾
最后,这篇文章大多是借鉴博客"systemd 编写服务管理脚本" 戳这里!,对此表示感谢!
官方投喂
freedesktop对systemd的百科



