你需要一个 Redis 服务做开发调试,于是你照着教程在一台平平无奇的 Ubunut 安装 Redis 服务并且启动:
sudo apt install redis-server
sudo systemctl start redis-server
接着,你的另一个服务需要用到 6379 端口,但是此时因为 6379 端口被 Redis 服务占用,所以你无法启动另一个服务。
因此你决定要 kill 掉 Redis 服务:
kill -9 $(pidof redis-server)
结果,却怎么也无法 kill 掉 Redis 服务。
一时间,你陷入了一个尴尬的境地,去搜索“我的 Redis 怎么也关不掉”,却发现别人面临的场景总是奇奇怪怪,而你,刚刚只是简单地在本地安装了一个 Redis 服务。
终于,你想到,你是用 systemctl 来 start 你的 Redis 服务的,那么,你可以试试用 systemctl 来 stop 你的 Redis 服务?
sudo systemctl stop redis-server
果然,你又重新“夺回”了 6379 的控制权,你终于可以愉快地启动你的另一个服务了。
于是你下定决心,了解下 systemctl 到底是个什么东西。
首先介绍 systemd
systemd 是一个 Linux 系统基础组件的集合,它提供了一系列强大的功能来管理系统的启动、服务、进程以及资源等。通过 systemd 这些单元的配置和组合,可以灵活地控制系统的各种行为。
人话:systemd 可以理解为大多数 Linux 发行版中用于取代 SysVinit 的初始化系统。如果你去看你 Linux 的第一个进程,你会发现它是 systemd ( sbin/init 是 systemd 的软链接)。
$ ps aux|head -2
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.6 168980 12544 ? Ss 2023 7:02 /sbin/init noibrs
$ ls -lha /sbin/init
lrwxrwxrwx 1 root root 20 Jan 10 2022 /sbin/init -> /lib/systemd/systemd
操作系统中的第一个进程,其作用可以理解为:
- 初始化内存管理系统,确定系统内存的布局与可分配资源
- 启动文件系统的相关服务,还会创建并初始化系统的基础服务进程,像负责网络通信的守护进程等
- 是开机后的第一个进程,负责启动其他进程,是所有进程的父进程
但是人们厌倦了 SysVinit 的复杂,于是就有了 systemd 。
systemctl 则是 systemd 的命令行工具,它提供了一组命令来管理系统服务。通过 systemctl ,你可以启动、停止、重启、查看服务的状态。
与之类似,还有 journalctl ,它是 systemd 的日志管理工具,用于查看系统服务的日志。
systemctl 常用命令
# 查看服务状态
systemctl status redis-server
# 启动服务
systemctl start redis-server
# 停止服务
systemctl stop redis-server
# 重启服务
systemctl restart redis-server
# 查看服务是否开机启动
systemctl is-enabled redis-server
# 开机启动服务
systemctl enable redis-server
# 取消开机启动服务
systemctl disable redis-server
# 查看服务日志
journalctl -u redis-server
# 查看服务依赖关系
systemctl list-dependencies redis-server
服务如何被 systemd 管理
在你 apt install 一个服务的时候,系统会自动帮你创建一个 .service 文件,这个文件就是 systemd 管理的服务的配置文件。
比如 apt install redis-server 之后,你可以看到如下文件。
$ cat /etc/init.d/redis-server
#! /bin/sh
### BEGIN INIT INFO
# Provides: redis-server
# Required-Start: $syslog $remote_fs
# Required-Stop: $syslog $remote_fs
# Should-Start: $local_fs
# Should-Stop: $local_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: redis-server - Persistent key-value db
# Description: redis-server - Persistent key-value db
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/bin/redis-server
DAEMON_ARGS=/etc/redis/redis.conf
...
/etc/init.d/redis-server 是为了兼容 SysVinit 而存在的,并不会被 systemd 所使用。你可以看到其直接书写 shell 脚本,这点为人诟病(不安全、不方便),在 systemd 中,我们可以使用配置文件来管理服务。
$ cat /etc/systemd/system/redis.service
[Unit]
Description=Advanced key-value store
After=network.target
Documentation=http://redis.io/documentation, man:redis-server(1)
[Service]
Type=forking
ExecStart=/usr/bin/redis-server /etc/redis/redis.conf
PIDFile=/run/redis/redis-server.pid
TimeoutStopSec=0
Restart=always
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=2755
UMask=007
PrivateTmp=yes
LimitNOFILE=65535
PrivateDevices=yes
ProtectHome=yes
ReadOnlyDirectories=/
ReadWritePaths=-/var/lib/redis
ReadWritePaths=-/var/log/redis
ReadWritePaths=-/var/run/redis
NoNewPrivileges=true
CapabilityBoundingSet=CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE
MemoryDenyWriteExecute=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
# redis-server can write to its own config file when in cluster mode so we
# permit writing there by default. If you are not using this feature, it is
# recommended that you replace the following lines with "ProtectSystem=full".
ProtectSystem=true
ReadWriteDirectories=-/etc/redis
[Install]
WantedBy=multi-user.target
Alias=redis.service
/etc/systemd/system/redis.service 是 systemd 管理的服务的配置文件,你可以看到其使用了 systemd 的配置语法。
systemd 的相关守护进程们,会根据这些配置文件,达到程序预期的目的。
$ ps aux|grep systemd
root 225 0.0 7.6 211704 154572 ? S<s 2023 4:27 /lib/systemd/systemd-journald
root 253 0.0 0.2 21664 5188 ? Ss 2023 1:31 /lib/systemd/systemd-udevd
systemd+ 406 0.0 0.3 27428 7608 ? Ss 2023 2:42 /lib/systemd/systemd-networkd
systemd+ 422 0.0 0.5 24580 12048 ? Ss 2023 9:48 /lib/systemd/systemd-resolved
message+ 446 0.0 0.2 7424 4260 ? Ss 2023 0:08 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
root 459 0.0 0.3 17532 7868 ? Ss 2023 0:59 /lib/systemd/systemd-logind
root 1572894 0.0 0.4 18824 9048 ? Ss 00:20 0:00 /lib/systemd/systemd --user
root 1573931 0.0 0.0 9032 736 pts/2 S+ 00:39 0:00 grep --color=auto systemd
如果我自己安装的 binary 文件,没有通过 apt install 安装,那怎么办呢?
很简单,根据需求,自己写一个 .service 文件,然后放到 /etc/systemd/system/ 目录下,然后执行 systemctl enable xxx.service 即可。