Linux 服务管理有两种方式service和systemctl,而systemd是Linux系统最新的初始化系统(init),systemctl是systemd的一个命令行工具,用于管理systemd服务。
systemd 取代了initd,成为内核加载完之后启动的第一个进程(PID为1),其他进程都是它的子进程。
如下所示:
ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.3 168872 13400 ? Ss Jul27 0:16 /sbin/init
......
ls /sbin/init -l
lrwxrwxrwx 1 root root 20 Feb 28 19:15 /sbin/init -> /lib/systemd/systemd
通过systemctl命令,可以启动、停止、重启、查看、设置和管理系统中的各种服务和进程,包括系统初始化、进程管理、日志管理、网络管理等。
自定义服务常用目录: /usr/lib/systemd/system/
systemctl命令兼容了service。
# 启动,停止,重启(先stop后再start),查看状态
service redis start|stop|restart|status
systemctl start httpd.service
# 查看所有已启动服务列表,以及每个服务的运行级别。
chkconfig --list
systemctl list-units --type=service
# 设置开机启动,不开机启动
chkconfig httpd on|off
systemctl enable|disable httpd.service
/usr/lib/systemd/system/: 存放系统级脚本,开机不登录就能运行。启动脚本的配置主要放这,类似 /etc/init.d/
/usr/lib/systemd/user/: 存放用户级脚本,登录后才可运行
/run/systemd/system/:保存系统执行产生的服务脚本,优先级比 /usr/lib/systemd/system/ 高。
/lib/systemd/system/: 文件从 /usr/lib/systemd/system/ 拷贝而来,故存放文件基本相同。
/etc/systemd/system/: 存放文件和目录最少,为 /lib/systemd/system/ 目录下的软连接。优先级最高。
修改某个服务启动的设置,应该去 /usr/lib/systemd/system/ 下面修改。
在 systemd 管理体系中,被管理的 deamon (守护进程)称作 unit (单元),通过 systemctl 命令控制。
target 取代了initd的RunLevel(运行等级), target (服务组)就是一组unit(服务),当启动某个target时就会启动里面的所有 unit。
unit的常见类型:
常见 service 单元:
添加自定义服务的话,一般在 /usr/lib/systemd/system/ 目录,添加service类型的unit单元文件。
例:
cat /usr/lib/systemd/system/ssh.service
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
# Wants=sshd-keygen.service
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
# RestartSec=42s
[Install]
WantedBy=multi-user.target
Alias=sshd.service
[Unit]
Description=服务描述
Documentation=文档地址
After=说明本服务是在哪个 daemon 启动之后才启动
Before=在什么服务启动前最好启动本服务
Requies=依赖到其它的units;强依赖,被依赖的units无法激活时,当前的unit即无法激活;
Wants=依赖到其它的units;弱依赖;
Confilcts=定义units 的冲突关系;
[Service]
Type=simple #服务类型
User=用户名 #服务执行的用户,默认为root,其他用户管理systemd需经过root同意
Environment="ENV_KEY=ENV_VALUE" #定义环境变量
# 执行的命令必须是绝对路径(脚本或进程),不能执行shell的内部命令
ExecStart=启动服务执行的命令
ExecReload=重启服务执行的命令
ExecStop=停止服务执行的命令
ExecStartPre=启动服务之前执行的命令
ExecStartPost字段:启动服务之后执行的命令
ExecStopPost=停止服务之后执行的命令
TimeoutSec=若这个服务在启动或者是关闭时,因为某些缘故导致无法顺利完成,设置一个超时。
# RestartSec: 自动重启服务需要间隔的时间(单位: 秒)。默认100ms
RestartSec=42
StandardOutput=file:/root/qddns/output.log # 定义日志文件路径
Type字段定义启动类型。它可以设置的值如下:
> simple(默认值):ExecStart字段启动的进程为主进程
> forking:ExecStart字段将以fork()方式启动,此时父进程将会退出,子进程将成为主进程(后台运行)
> oneshot:类似于simple,但只执行一次,Systemd 会等它执行完,才启动其他服务
> dbus:类似于simple,但会等待 D-Bus 信号后启动
> notify:类似于simple,启动结束后会发出通知信号,然后 Systemd 再启动其他服务
> idle:类似于simple,但是要等到其他任务都执行完,才会启动该服务。一种使用场合是为让该服务的输出,不与其他服务的输出相混合
KillMode:定义 Systemd 如何 停止 服务。
ssh(sshd)服务,设置 KillMode=process,表示只停止主进程,不停止子进程,即子进程打开的 SSH session 仍然保持连接。这个设置不太常见,但对 sshd 很重要,否则你停止服务的时候,会连自己打开的 SSH session 一起杀掉。
Restart:定义服务在什么情况下自动重启
Restart=on-failure: 出现任何意外的失败,重启sshd。shd 正常停止(比如执行systemctl stop命令)的情况不重启。
注:对于 守护进程,推荐设为 on-failure。对于那些允许发生错误退出的服务,可以设为 on-abnormal。
定义开机启动
target: 定义了一个含有多个服务的启动目标。 Systemd 有默认的启动 Target。
systemctl enable 命令会在 /etc/systemd/system/multi-user.target.wants/ 目录生成 软连接。
[Install]
# 表示该服务所在的 Target。定义为开机启动项
WantedBy=multi-user.target
RequiredBy=被哪些unit所依赖;
target 相关命令:
# 查看系统默认target。如:输出 multi-user.target, 表示这个组的所有服务,都将开机启动
systemctl get-default
#查看 multi-user.target 包含的所有服务
systemctl list-dependencies multi-user.target
#切换到另一个 target
#shutdown.target 就是关机状态
systemctl isolate shutdown.target
# 查看所有服务
systemctl list-units --type=service
systemctl list-unit-files --type=service
# 查找qddns服务
systemctl list-unit-files --type=service | grep qddns.service
# 查看系统启动模式
systemctl get-default
# 设置系统为图形界面启动
systemctl set-default graphical.target
# 查看系统环境变量
systemctl show-environment
[Service]
StandardOutput=file:/root/qddns/output.log
# 查看某服务的日志
journalctl -u nginx.service
# 查看日志已占用的空间
journalctl --disk-usage
# –vacuum-size=1G #设置日志最大占用空间
# –vacuum-time=1years #设置日志最大保存时间
/etc/systemd/system/default.target: 默认运行等级配置文件
service文件中ExecStart、ExecReload、ExecStop不支持> 、>>等重定向符号,可以用 /bin/sh -c 来实现。
ExecStart=/bin/sh -c '/path/demo/demo >>/path/demo/demo/reload.log 2>&1'
/bin/sh -c 命令fork出两个子进程,进程组的首进程,负责与终端tty交互,其次才是真正的demo进程。当执行reload时,实际上执行 ExecReload=/bin/kill -s HUP $MAINPID ,这个MAINPID其实是首进程,进程如果没做信号量的捕获,默认是执行中断操作,同时会给子进程发送 SIGTREM信号 杀掉子进程,所以systemctl命令报错。
换一种实现方法,就是查到demo进程的真实pid:
ExecReload=/bin/sh -c '/bin/kill -HUP $(pidof /path/demo/demo)'
为什么加入重定向就会循环fork出两个进程?
/bin/sh -c 的原理就是fork+exec来产生一个进程,子进程是无法与tty(控制台)交互的后台进程,重定向需要与tty(控制台)交互,所以先fork出来一个重定向进程,再fork出一个真正的demo进程
[Unit]
Description=DDNS timer
After=network.target
[Service]
WorkingDirectory=/root/qddns
ExecStart=/root/qddns/qddns
User=root
Restart=on-failure
RestartSec=300
TimeoutStopSec=10
StandardOutput=file:/root/qddns/output.log
[Install]
WantedBy=multi-user.target