linux-systemd学习总结
大纲
- 概念
- systemctl 命令详解
- systemctl 脚本配置文件
- 使用systemd管理springboot程序
概念
linux 系统启动流程
linux 系统启动流程
- 1 post 加电
- 2 BISO 进入BIOS
- 3 bootloader(MBR) 加载磁盘主引导记录
- 4 kernel(ramdisk) 加载内核
- 5 rootfs 初始化rootfs
- 6 /sbin/init 系统初始化
Linux下有三个特殊进程:shell
-
idle进程(pid=0)
idle进程其前身是系统建立的第一个进程,0号进程,也惟一一个没有经过fork()或者kernel_thread产生的进程,由系统自动建立,运行在内核态。
0号进程在建立了init进程后,演变成为idle进程。主处理器上的idle进程是由原始进程(0号进程)演变而来,从处理器上的idle进程是由init进程fork获得的,
pid也为0。idle进程的优先级最低,不参与调度,只有在运行队列为空时才调度。 -
init进程(pid=1)
init进程由0号进程建立,完成系统的初始化,是第一个用户进程,是其余全部用户进程的父进程。
-
kthreadd进程(pid=2)
kthreadd进程由idle经过kernel_thread建立,始终运行在内核空间,负责内核进程的调度和管理。
init进程,是一个由内核启动的用户级进程,内核自行启动后,就通过启动init来完成引导进程。所以,init始终是第一个进程(其进程编号始终为1)init进程会做大量的初始化功能,启动其他子进程
这里的 init 在不同系统上还有所不同,CentOS5:Sysv lnit,CentOS6:Upstart,CentOS7:systemd 系统守护进程
现阶段大部分的linux发行版都使用systemd 作为init进程
这是ubuntu上看到的init进程信息**(所有的子进程都是有init进程直接或间接的启动)**
systemd
systemd 是 linux 系统中最新的初始化系统(init),它主要的设计目标是克服 sysvinit 固有的缺点,提高系统的启动速度 (ubuntu也使用systemd)
兼容性
systemd 提供了和 sysvinit 兼容的特性。系统中已经存在的服务和进程无需修改。这降低了系统向 systemd 迁移的成本,使得 systemd 替换现有初始化系统成为可能。
启动速度
systemd 提供了比 upstart 更激进的并行启动能力,采用了 socket / D-Bus activation 等技术启动服务。一个显而易见的结果就是:更快的启动速度。为了减少系统启动时间,systemd 的目标是:
- 尽可能启动更少的进程
- 尽可能将更多进程并行启动
systemd的unit类型
系统初始化需要做的事情非常多。需要启动后台服务,比如启动 ssh 服务;需要做配置工作,比如挂载文件系统。这个过程中的每一步都被 systemd 抽象为一个配置单元,即 unit。
可以认为一个服务是一个配置单元,一个挂载点是一个配置单元,一个交换分区的配置是一个配置单元等等。systemd 将配置单元归纳为以下一些不同的类型。然而,systemd 正在快速发展,新功能不断增加。所以配置单元类型可能在不久的将来继续增加。下面是一些常见的 unit 类型:
- service :代表一个后台服务进程,比如 mysqld。这是最常用的一类。
- socket :此类配置单元封装系统和互联网中的一个套接字 。当下,systemd 支持流式、数据报和连续包的 AF_INET、AF_INET6、AF_UNIX socket 。每一个套接字配置单元都有一个相应的服务配置单元 。相应的服务在第一个"连接"进入套接字时就会启动(例如:nscd.socket 在有新连接后便启动 nscd.service)。
- device :此类配置单元封装一个存在于 Linux 设备树中的设备。每一个使用 udev 规则标记的设备都将会在 systemd 中作为一个设备配置单元出现。
- mount :此类配置单元封装文件系统结构层次中的一个挂载点。Systemd 将对这个挂载点进行监控和管理。比如可以在启动时自动将其挂载;可以在某些条件下自动卸载。Systemd 会将 /etc/fstab 中的条目都转换为挂载点,并在开机时处理。
- automount :此类配置单元封装系统结构层次中的一个自挂载点。每一个自挂载配置单元对应一个挂载配置单元 ,当该自动挂载点被访问时,systemd 执行挂载点中定义的挂载行为。
- swap:和挂载配置单元类似,交换配置单元用来管理交换分区。用户可以用交换配置单元来定义系统中的交换分区,可以让这些交换分区在启动时被激活。
- target :此类配置单元为其他配置单元进行逻辑分组。它们本身实际上并不做什么,只是引用其他配置单元而已。这样便可以对配置单元做一个统一的控制。这样就可以实现大家都已经非常熟悉的运行级别概念。比如想让系统进入图形化模式,需要运行许多服务和配置命令,这些操作都由一个个的配置单元表示,将所有这些配置单元组合为一个目标(target),就表示需要将这些配置单元全部执行一遍以便进入目标所代表的系统运行状态。 (例如:multi-user.target 相当于在传统使用 SysV 的系统中运行级别 5)
- timer:定时器配置单元用来定时触发用户定义的操作,这类配置单元取代了 atd、crond 等传统的定时服务。
- snapshot :与 target 配置单元相似,快照是一组配置单元。它保存了系统当前的运行状态。
- path:文件系统中的一个文件或目录。
- scope:用于 cgroups,表示从 systemd 外部创建的进程。
- slice:用于 cgroups,表示一组按层级排列的单位。slice 并不包含进程,但会组建一个层级,并将 scope 和 service 都放置其中
如果要将程序制作为开机启动服务 就会用到service
systemctl 命令详解
**systemd **相关的绝大多数任务都是通过 systemctl 命令管理的
systemctl 命令有两大类功能:
- 1 控制 systemd 系统
- 2 管理系统上运行的服务
全局控制命令
- systemctl --version #检查 systemd 的版本
- systemctl 或 systemctl list-units #显示所有单元状态
- systemctl list-unit-files #查看系统上一共安装了多少 unit
- sudo systemctl reboot # 重启系统
- sudo systemctl poweroff # 关闭系统,切断电源
- sudo systemctl halt # CPU停止工作
- sudo systemctl suspend # 暂停系统
- sudo systemctl hibernate # 让系统进入冬眠状态
- sudo systemctl hybrid-sleep # 让系统进入交互式休眠状态
- sudo systemctl rescue # 启动进入救援状态(单用户状态)
控制单个unit命令
systemctl 提供了一组子命令来管理单个的 unit,其命令格式为:systemctl 【command】 【unit】
command 主要有:
- start:立刻启动后面接的 unit。
- stop:立刻关闭后面接的 unit。
- restart:立刻关闭后启动后面接的 unit,亦即执行 stop 再 start 的意思。
- reload:不关闭 unit 的情况下,重新载入配置文件,让设置生效。
- enable:设置下次开机时,后面接的 unit 会被启动。
- disable:设置下次开机时,后面接的 unit 不会被启动。
- status:目前后面接的这个 unit 的状态,会列出有没有正在执行、开机时是否启动等信息。
- is-active:目前有没有正在运行中。
- is-enable:开机时有没有默认要启用这个 unit。
- kill :不要被 kill 这个名字吓着了,它其实是向运行 unit 的进程发送信号。
- show:列出 unit 的配置。
- mask:注销 unit,注销后你就无法启动这个 unit 了。
- unmask:取消对 unit 的注销。
例如 (使用sshd.service为例子)
显示sshd服务单元
systemctl status sshd.service
验证sshd服务当前是否活动
systemctl is-active sshd
启动,停止和重启sshd服务
systemctl start sshd.service
systemctl stop sshd.service
systemctl restart sshd.service
重新加载配置
systemctl reload sshd.service
验证sshd服务是否开机启动
systemctl is-enabled sshd
禁用network,使之不能自动启动,但手动可以
systemclt disable sshd.service
启用sshd
systemctl enable sshd.service
禁用sshd,使之不能手动或自动启动
systemclt mask sshd.service
启用sshd
systemctl umask sshd.service
systemctl 脚本配置文件
基础知识
centos系统
** centos系统 systemctl脚本存放在:/usr/lib/systemd/,有系统(system)和用户(user)之分**
- 1)/usr/lib/systemd/system #系统服务,开机不需要登陆就能运行的程序(相当于开启自启)
- 2)/usr/lib/systemd/user #用户服务,需要登录后才能运行的程序
要制作开机启动服务 systemctl脚本需存放在/usr/lib/systemd/system
ubuntu系统
ubuntu系统 systemctl脚本存放在: /etc/systemd/system
在系统启动时时,Systemd只会去执行 /etc/systemd/system目录里面的.service配置文件,每一个配置文件,就是一个需要启动的守护进程。
/usr/lib/systemd/system(/etc/systemd/system)目录下又存在两种类型的文件:
- 1).service # 服务unit文件
- 2).target # 开机级别unit
.service & .target 文件的区别
service 是 Systemd 管理系统资源的基本单元,可以认为每个系统资源就是一个 Unit,并使用一个 Unit 文件定义。在 Unit 文件中需要包含相应服务的描述、属性以及需要运行的命令。
target 是 Systemd 中用于指定系统资源启动组的方式,简单说,Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候,Systemd 就会启动里面所有的 Unit。从这个意义上说,Target 这个概念类似于”状态点”,启动某个 Target 就好比启动到某种状态。
https://www.freedesktop.org/software/systemd/man/systemd.target.html
systemctl 脚本配置文件说明
systemd 服务以 .service 结尾,一般分为3部分:【unit】、【service】、【install】
一个简单的例子:
[Unit] # 主要是服务说明
Description=test # 简单描述服务
After=network.target # 描述服务类别,表示本服务需要在network服务启动后在启动
Before=xxx.service #表示需要在某些服务启动之前启动,After和Before字段只涉及启动顺序,不涉及依赖关系。
[Service] # 核心区域
Type=forking # 表示后台运行模式。
User=user # 设置服务运行的用户
Group=user # 设置服务运行的用户组
KillMode=control-group # 定义systemd如何停止服务
PIDFile=/usr/local/test/test.pid # 存放PID的绝对路径 注意测试发现这个配置不但没有效果还会引发超时
Restart=no # 定义服务进程退出后,systemd的重启方式,默认是不重启
ExecStart=/usr/local/test/bin/startup.sh # 服务启动命令,命令需要绝对路径
PrivateTmp=true # 表示给服务分配独立的临时空间
[Install]
WantedBy=multi-user.target # 服务安装的用户模式 就是指想要使用这个服务的目录是多用户。
systemctl 脚本配置文件字段说明
[Unit]块
Unit 段
Description:描述这个 Unit 文件的信息
Documentation:指定服务的文档,可以是一个或多个文档的 URL 路径
Requires:依赖的其它 Unit 列表,列在其中的 Unit 模板会在这个服务启动时的同时被启动。并且,如果其中任意一个服务启动失败,这个服务也会被终止
Wants:与 Requires 相似,但只是在被配置的这个 Unit 启动时,触发启动列出的每个 Unit 模块,而不去考虑这些模板启动是否成功
After:与 Requires 相似,但是在后面列出的所有模块全部启动完成以后,才会启动当前的服务
Before:与 After 相反,在启动指定的任务一个模块之间,都会首先确证当前服务已经运行
Binds To:与 Requires 相似,失败时失败,成功时成功,但是在这些模板中有任意一个出现意外结束或重启时,这个服务也会跟着终止或重启
Part Of:一个 Bind To 作用的子集,仅在列出的任务模块失败或重启时,终止或重启当前服务,而不会随列出模板的启动而启动
OnFailure:当这个模板启动失败时,就会自动启动列出的每个模块
Conflicts:与这个模块有冲突的模块,如果列出的模块中有已经在运行的,这个服务就不能启动,反之亦然
[Service]块
[Service]块下的Type配置字段:
- simple(默认):#以Execstart字段启动的进程为主进程
- forking:#Execstart 字段以fox()方式启动,此时父进程将退出,子进程将成为主进程(后台运行一般都设置为forking)
- oneshot : #类似于simple,但只执行一次,systemd会等他执行完,才执行其他服务
- dbus: #类似于simple,但会等待D—Bus信号后启动
- notify: #类似与simple ,但结束后会发出通知信号,然后systemd才启动其他服务
- idle: #类似与simple,但要等到其他任务都执行完,才启动该服务
[Service]块下的各种Exec*配置字段
Exec*后面的命令,仅接受‘指令 参数 参数…’格式,不能接受<> |&等特殊字符,很多bash语法也不支持,如果想要支持bash语法,需要设置Tyep=oneshot
- ExecStart: # 启动服务时执行的命令
- ExecReload: # 重启服务时执行的命令
- ExecStop: # 停止服务时执行的命令
- ExecStartPre: # 启动服务前执行的命令
- ExecStartPost:# 启动服务后执行的命令
- ExecStopPost: # 停止服务后执行的命令
- PrivateTmp=True #表示给服务分配独立的临时空间,
注意:[Service]部分的启动、重启、停止命令全部要求使用绝对路径,使用相对路径则会报错
例如:
[Service]
Type=forking
PIDFile=/home/developer/web/gunicorn.pid
ExecStart=/usr/local/bin/forever start
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Service]块下的Environment & EnvironmentFile配置字段:
-
Environment:
后面接多个不同的shell变量例如:
Environment=DATA_DIR=/data/elk
Environment=LOG_DIR=/var/log/elasticsearch
Environment=PID_DIR=/var/run/elasticsearch -
EnvironmentFile=-/etc/sysconfig/elasticsearch
连词号(-):在所有启动设置之前,添加的变量字段,都可以加上连词号
表示抑制错误,即发生错误时,不影响其他命令的执行。
比如EnviromentFile=-/etc/sysconfig/xxx表示即使文件不存在,也不会抛异常
[Service]块下的Killmode配置字段:
- contorl-group (默认) # 当前控制组里所有的子进程都会被杀掉
- process : #只杀主进程
- mixed: #主进程将收到SIGTERM(终止进程)信号,子进程将收到SIGKILL(无条件终止)信号
- none: # 没有进程会被杀掉,只是执行服务的stop命令
[Service]块下的Restart配置字段:
- no (默认):#退出后无操作
- on-success :#只有正常退出时(退出状态码为0),才会重启
- on-failure: #非正常退出时,重启,包括信号终止,和超时 (对于守护进程,推荐使用on-failure)
- on-abnaomal: #只有信号终止或超时,才会重启
- on-abort : #只有在收到没有捕捉到信号终止时,才会重启
- on-watchdog: #超市退出时,才会重启
- always: #不管什么退出原因,都会重启
[Service]块下的RestartSe配置字段:
表示systemd重启服务之前,需要等待的秒数:RestartSec:30
其他配置
- TimeoutStartUSec 配置超时时间 例如TimeoutStartUSec=10s TimeoutStartUSec=0表示永久
[Install]块
[Install]部分是服务安装的相关设置,可设置为多用户的
[Install]
WantedBy=multi-user.target
# WantedBy字段:
# multi-user.target: # 表示多用户命令行状态,这个设置很重要
# graphical.target: # 表示图形用户状体,它依赖于multi-user.target
修改配置文件以后,以754的权限保存在/usr/lib/systemd/system(ubuntu系统 /etc/systemd/system)目录下,需要重新加载配置文件方可生效
$ systemctl daemon-reload
这时就可以利用systemctl进行配置了
首先,使用systemctl start [服务名(也是文件名)]可测试服务是否可以成功运行,如果不能运行则可以使用systemctl status [服务名(也是文件名)]查看错误信息和其他服务信息,然后根据报错进行修改,直到可以start,如果不放心还可以测试restart和stop命令。
接着,只要使用systemctl enable xxxxx就可以将所编写的服务添加至开机启动即可
使用systemd管理springboot程序
本次实验在 ubuntu18 上测试
日常开发中 我们可能需要把对应的springboot服务配置作为service来启动
注意: 前提已经安装好java jdk
step1 准备一个springboot java程序启动脚本
这一步不是必须的 但是由于java项目启动如果要配置很多参数 建议还是创建一个start.sh脚本
#!/bin/bash
nohup /tools/jdk1.8.0_231/bin/java -Xms256m -Xmx512m -jar /data/service/goods.jar &
注意:start.sh 脚本的权限 chmod 755 start.sh
step2 准备.service脚本文件
这里创建一个springboot.service 脚本文件 脚本内容如下
[Unit]
Description=this is springboot service goodsservice #service 描述
[Service]
Type=forking #后台运行
User=root
Group=root
KillMode=control-group
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
Restart=no
ExecStart=/data/service/start.sh #使用脚本启动 注意需要绝对路径
#不使用脚本直接使用命令 注意需要后台启动 否则程序会超时
#ExecStart=/bin/bash -c "nohup /tools/jdk1.8.0_231/bin/java -Xms256m -Xmx512m -jar /data/service/goods.jar &"
PrivateTmp=true
TimeoutStartSec=10s #配置service启动超时时间
[Install]
WantedBy=multi-user.target # 服务安装的用户模式 就是指想要使用这个服务的目录是多用户
注意:springboot.service 脚本的权限 chmod 755 springboot.service
step3 systemd 重新加载
将刚才创建好的springboot.service 移动到 /etc/systemd/system (注意 如果是centos则移动到/usr/lib/systemd/system)
然后重新加载
systemctl daemon-reload
systemctl list-unit-files | grep spring
step4 启动springboot.service
使用 systemctl start springboot.service 启动
systemctl start springboot.service
systemctl stop springboot.service
systemctl restart springboot.service
step5 开机自动启动springboot.service
使用 systemctl enable springboot.service 配置为开启自动启动
step6 service 日志查看
使用 journalctl -u springboot.service -f 查看service 日志
注意事项
- 1 如果配置了 PIDFile=/data/service/springboot.pid 后service一直超时
- 2 启动脚本或者启动命令需要后台运行
- 3 使用 journalctl -u springboot.service -f 查看service 日志