Linux 系统服务管理
Chen Kai BOSS

在操作系统中,"服务"指后台常驻的进程或守护程序( daemon)——它们在系统启动时自动运行,在后台默默工作,提供各种功能(如时间同步、防火墙、计划任务、 Web 服务器、数据库等)。现代 Linux 使用 systemd 统一管理这些服务,提供了强大的依赖管理、并行启动、日志集成等功能。本文会从 systemd 的核心概念讲起,深入 systemctl 命令的使用,讲解常见服务(时间同步、防火墙、计划任务、 SSH)的配置与排障,并教你如何自定义服务、让自己的程序开机自启。如果你是运维人员或需要管理 Linux 服务器,这篇文章会让你从"会启停服务"升级到"能写自定义服务、能排障、能优化启动顺序"。

systemd 核心概念:为什么要用它、它解决了什么问题

为什么需要服务管理器

在操作系统中,"服务"( Service)是指那些长期运行在后台、对系统或用户提供某种功能的进程或守护程序( daemon)。例如:

  • 时间同步服务( ntpd / ntpsec):定期与时间服务器同步,确保系统时钟准确
  • 防火墙服务( firewalld / iptables):控制网络流量,保护系统安全
  • SSH 服务( sshd):允许远程登录
  • Web 服务器( nginx / apache):处理 HTTP 请求,提供网站访问
  • 数据库服务( mysql / postgresql):存储和查询数据
  • 计划任务服务( crond):按时间表自动执行脚本

这些服务通常需要: 1. 开机自动启动(不需要手动启动) 2. 崩溃后自动重启(提高可用性) 3. 依赖关系管理(例如 Web 服务依赖网络服务,网络服务依赖网卡驱动) 4. 日志集成(方便排障) 5. 资源限制(防止某个服务占用过多 CPU/内存)

服务管理器就是用来统一管理这些服务的工具。

systemd vs SysV init(旧系统)

在 systemd 出现之前, Linux 使用 SysV init 作为服务管理器( CentOS 6 、 Ubuntu 14.04 及更早版本)。它的特点是:

  • 服务脚本放在 /etc/init.d/ 目录下
  • 使用 service <service> start/stop/restart 管理服务
  • 使用 chkconfig 配置开机自启
  • 串行启动:服务按顺序一个一个启动,慢(尤其是服务很多时)
  • 依赖关系靠脚本手动处理:容易出错

systemd 是现代 Linux 发行版的服务管理器( CentOS 7+、 Ubuntu 16.04+、 Debian 8+),它的优点是:

  • 并行启动:多个服务同时启动,快很多
  • 依赖关系自动处理: systemd 知道服务之间的依赖关系,自动按顺序启动
  • 统一的日志系统( journald):所有服务的日志都集中管理,方便查询
  • Socket 激活:某些服务可以按需启动(有连接时才启动,节省资源)
  • Cgroup 集成:可以限制服务的 CPU/内存使用
  • 统一的命令systemctl 一个命令管理所有服务

兼容性: systemd 向下兼容 SysV init 的命令(servicechkconfig 在 systemd 系统上仍然可用,但底层调用的是 systemctl)。

systemd 的核心概念: unit

在 systemd 中,一切皆 unit(单元)。 Unit 是 systemd 管理的最小单位,常见的 unit 类型有:

Unit 类型 说明 示例
service 最常见的类型,代表一个后台服务(进程) sshd.servicenginx.service
socket 代表一个 IPC 或网络套接字,用于按需激活服务 sshd.socketdocker.socket
target 代表一组 unit 的集合(类似 SysV 的 runlevel) multi-user.targetgraphical.target
mount 代表一个挂载点(文件系统) home.mounttmp.mount
timer 代表一个定时任务(替代 cron) logrotate.timerapt-daily.timer
device 代表一个设备(如 USB 、网卡) dev-sda.device
path 监控文件/目录变化,触发服务启动 systemd-tmpfiles-clean.path

最常用的是 service 类型.service 后缀),所以我们通常说的"服务"就是指 service unit 。

systemd 启动流程简述

  1. 内核启动:内核加载完成后,启动 systemd( PID 1,第一个用户空间进程)
  2. systemd 读取配置:读取 /etc/systemd/system//usr/lib/systemd/system/ 下的 unit 文件
  3. 确定启动目标:通常是 multi-user.target(多用户文本模式)或 graphical.target(图形界面)
  4. 解析依赖关系:根据 unit 文件中的 RequiresAfterBefore 等字段,确定启动顺序
  5. 并行启动服务:同时启动多个没有依赖关系的服务(提高启动速度)
  6. 进入目标状态:所有依赖的服务都启动完成后,系统进入目标状态(如登录提示符)

systemctl 命令:日常使用的"肌肉记忆"

systemctl 是 systemd 的主要命令行工具,用于管理服务。这部分是你日常操作最常用的命令。

基本操作(启动、停止、重启、查看状态)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 启动服务(立即生效,但重启后失效)
systemctl start <service>

# 停止服务
systemctl stop <service>

# 重启服务(停止后再启动)
systemctl restart <service>

# 重新加载配置文件(不停止服务,适用于支持热重载的服务如 nginx)
systemctl reload <service>

# 查看服务状态(是否运行、 PID 、最近的日志、开机是否自启)
systemctl status <service>

示例

1
2
3
systemctl start sshd       # 启动 SSH 服务
systemctl status sshd # 查看 SSH 服务状态
systemctl reload nginx # 重新加载 nginx 配置(不停止服务)

开机自启管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 设置开机自启(创建符号链接到 /etc/systemd/system/multi-user.target.wants/)
systemctl enable <service>

# 取消开机自启(删除符号链接)
systemctl disable <service>

# 查看服务是否设置为开机自启
systemctl is-enabled <service>

# 一步到位:启动服务 + 设置开机自启
systemctl enable --now <service>

# 一步到位:停止服务 + 取消开机自启
systemctl disable --now <service>

示例

1
2
3
systemctl enable sshd      # 设置 SSH 服务开机自启
systemctl is-enabled sshd # 输出: enabled
systemctl disable firewalld # 取消防火墙开机自启

查看服务列表

1
2
3
4
5
6
7
8
9
10
11
# 列出所有正在运行的服务
systemctl list-units --type=service --state=running

# 列出所有服务(包括未运行的)
systemctl list-units --type=service --all

# 列出所有失败的服务
systemctl list-units --type=service --state=failed

# 搜索特定服务(如包含 ssh 的服务)
systemctl list-units --type=service --all | grep ssh

示例输出

1
2
● sshd.service    loaded active running OpenBSD Secure Shell server
● nginx.service loaded active running A high performance web server

查看服务详细信息

1
2
3
4
5
6
7
8
9
# 查看服务的 unit 文件内容
systemctl cat <service>

# 查看服务的依赖关系
systemctl list-dependencies <service>

# 查看服务的启动时间(性能分析)
systemd-analyze blame
systemd-analyze critical-chain <service>

示例

1
2
3
systemctl cat sshd.service  # 查看 sshd 的 unit 文件
systemctl list-dependencies sshd.service # 查看 sshd 依赖哪些服务
systemd-analyze blame # 查看所有服务的启动耗时(按耗时排序)


自定义服务:让你的程序开机自启

假设你有一个 Python 脚本或编译好的二进制程序,想让它开机自启、崩溃后自动重启,怎么做?写一个 systemd unit 文件即可。

最小可用示例

假设你有一个脚本 /usr/local/bin/myapp.sh

1
2
3
4
5
#!/bin/bash
while true; do
echo "MyApp is running..."
sleep 10
done

创建 unit 文件 /etc/systemd/system/myapp.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Unit]
Description=My Custom Application
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/myapp.sh
Restart=always
RestartSec=10
User=nobody
Group=nogroup

[Install]
WantedBy=multi-user.target

然后启动并启用:

1
2
3
4
sudo systemctl daemon-reload  # 重新加载 systemd 配置
sudo systemctl start myapp
sudo systemctl enable myapp
sudo systemctl status myapp

unit 文件详解

[Unit] 部分(描述和依赖关系)

1
2
3
4
5
6
[Unit]
Description=My Custom Application # 描述(会显示在 systemctl status 里)
After=network.target # 在网络服务之后启动
Before=another.service # 在另一个服务之前启动
Requires=some.service # 强依赖(如果依赖的服务启动失败,这个服务也失败)
Wants=some.service # 弱依赖(如果依赖的服务失败,这个服务仍然尝试启动)

[Service] 部分(服务的启动方式和行为)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[Service]
Type=simple # 最常用的类型(启动后就认为服务已准备好)
# Type=forking # 适用于 fork 后台运行的服务(如传统的 daemon)
# Type=oneshot # 适用于一次性执行的任务(如初始化脚本)

ExecStart=/usr/local/bin/myapp.sh # 启动命令(必须是绝对路径)
ExecReload=/bin/kill -HUP $MAINPID # 重新加载配置(可选)
ExecStop=/bin/kill -TERM $MAINPID # 停止命令(可选,默认发送 SIGTERM)

Restart=always # 崩溃后自动重启( always / on-failure / no)
RestartSec=10 # 重启前等待 10 秒

User=nobody # 以哪个用户运行(安全考虑,不要用 root)
Group=nogroup # 以哪个用户组运行

# 资源限制
LimitNOFILE=65536 # 最大打开文件数
LimitNPROC=4096 # 最大进程数
MemoryLimit=512M # 内存限制(需要 cgroup v2 支持)
CPUQuota=50% # CPU 限制( 50% 表示最多占用 0.5 个核心)

# 工作目录
WorkingDirectory=/var/lib/myapp # 启动时的工作目录

# 环境变量
Environment="VAR1=value1"
Environment="VAR2=value2"
EnvironmentFile=/etc/myapp/env # 从文件加载环境变量

[Install] 部分(开机自启配置)

1
2
3
[Install]
WantedBy=multi-user.target # 在多用户模式下启动(文本模式)
# WantedBy=graphical.target # 在图形模式下启动

常见 Type 的区别

Type 说明 适用场景
simple 启动后立即认为服务已准备好(默认) 大部分服务(如 nginx 、 python 脚本)
forking 服务会 fork 一个子进程后退出(父进程退出后,子进程成为主进程) 传统的 daemon 程序(如老版本的 Apache)
oneshot 执行完就退出(不是常驻进程) 一次性初始化任务(如挂载文件系统)
notify 服务启动后会主动通知 systemd "我准备好了"(需要程序支持 sd_notify) 高级服务(如 systemd-networkd)

修改 unit 文件后必须重新加载

1
2
sudo systemctl daemon-reload  # 告诉 systemd 重新读取 unit 文件
sudo systemctl restart myapp

journalctl: systemd 的统一日志系统

systemd 自带了 journald,所有服务的日志都集中存储在 /var/log/journal//run/log/journal/(重启后清空),可以用 journalctl 查询。

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 查看所有日志(从最早到最新)
journalctl

# 查看某个服务的日志
journalctl -u <service>

# 实时查看日志(类似 tail -f)
journalctl -u <service> -f

# 查看最近的 N 行日志
journalctl -u <service> -n 50

# 查看最近 1 小时的日志
journalctl -u <service> --since "1 hour ago"

# 查看某个时间段的日志
journalctl -u <service> --since "2025-02-01 00:00:00" --until "2025-02-01 23:59:59"

# 查看开机日志
journalctl -b # -b 0 表示当前这次开机,-b -1 表示上一次开机

# 查看内核日志
journalctl -k

高级用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看日志并显示详细信息(包括 PID 、 UID 等)
journalctl -u <service> -o verbose

# 查看日志并只显示错误和更严重的消息
journalctl -u <service> -p err

# 查看某个用户的所有日志
journalctl _UID=1000

# 查看某个可执行文件的日志
journalctl /usr/bin/python3

# 清理日志(保留最近 7 天)
journalctl --vacuum-time=7d

# 清理日志(保留最近 1GB)
journalctl --vacuum-size=1G

日志持久化

默认情况下, journald 的日志存储在 /run/log/journal/(内存中,重启后清空)。如果要持久化日志:

  1. 创建目录:

    1
    2
    sudo mkdir -p /var/log/journal
    sudo systemd-tmpfiles --create --prefix /var/log/journal

  2. 重启 journald:

    1
    sudo systemctl restart systemd-journald

之后日志会保存在 /var/log/journal/,重启后仍然存在。


常见服务配置与排障

这部分讲解几个最常见的系统服务的配置和排障方法。

时间同步服务( ntpd / ntpsec / timedatectl)

为什么需要时间同步

在分布式系统、集群、日志分析等应用场景下,时间同步至关重要:

  • 定时任务的执行(如 cron 任务):如果时间不一致,任务可能提前或延后执行
  • 日志对比和分析:如果多台服务器时间不一致,日志时间戳会错乱,无法关联
  • 数据同步(如数据库主从复制):时间不一致可能导致数据顺序混乱
  • 安全协议(如 Kerberos 身份认证、 TLS 证书):时间差太大会导致认证失败

方案 1:使用 ntpsec(推荐)

ntpsec 是传统 ntpd 的现代化版本,安全性更高、代码更精简。

安装与启动

1
2
3
sudo apt install ntpsec  # Debian/Ubuntu
sudo yum install ntpsec # CentOS/RHEL
sudo systemctl enable --now ntpsec

配置:编辑 /etc/ntpsec/ntp.conf,添加时间服务器(推荐使用国内服务器,延迟低):

1
2
3
server ntp.aliyun.com iburst prefer
server ntp.tencent.com iburst
server cn.pool.ntp.org iburst

  • iburst:启动时快速同步(发送 8 个包而不是 1 个)
  • prefer:优先使用这个服务器

重启服务:

1
sudo systemctl restart ntpsec

查看同步状态

1
ntpq -p  # 查看当前连接的时间服务器

方案 2:使用 timedatectl(更简单)

timedatectl 是 systemd 自带的时间管理工具,底层使用 systemd-timesyncd 进行 NTP 同步。

启用 NTP 同步

1
sudo timedatectl set-ntp true

查看状态

1
timedatectl

输出示例:

1
2
3
4
5
6
7
               Local time: Mon 2025-02-03 12:00:00 UTC
Universal time: Mon 2025-02-03 12:00:00 UTC
RTC time: Mon 2025-02-03 12:00:00
Time zone: UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no

设置时区(如果需要):

1
sudo timedatectl set-timezone Asia/Shanghai

查看可用时区

1
timedatectl list-timezones | grep Shanghai

ntpdate(一次性同步,不推荐常驻使用)

如果只需要临时同步一次时间(不是常驻服务):

1
sudo ntpdate ntp.aliyun.com

缺点

  • 暴力修改时间(直接跳变),可能导致依赖时序的程序出错(如定时任务、数据库同步)
  • ntpd / ntpsec 采用平滑调整,避免时间跳变

推荐:使用 ntpsec 或 timedatectl 进行长时间运行的同步,避免 ntpdate 的问题。


防火墙服务( firewalld)

基本介绍

防火墙( Firewall)是一种网络安全工具,用于控制和过滤网络流量,防止未经授权的访问。在 Linux 中,常见的防火墙有:

  • iptables(传统,规则是有顺序的,配置复杂)
  • firewalld(现代,动态规则,支持 zone 概念, RHEL/CentOS 默认)
  • ufw( Ubuntu 友好型防火墙,简化了 iptables)

firewalld 是基于 iptables/nftables 的动态防火墙,提供了更友好的命令行接口。

启用与关闭

1
2
3
4
5
6
sudo systemctl start firewalld
sudo systemctl enable firewalld
sudo systemctl status firewalld

sudo systemctl stop firewalld
sudo systemctl disable firewalld

基本规则操作

开放/关闭端口

1
2
3
4
5
6
7
8
9
10
11
# 开放 80 端口( TCP)
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --reload

# 开放 80-90 端口范围
sudo firewall-cmd --permanent --add-port=80-90/tcp
sudo firewall-cmd --reload

# 关闭 80 端口
sudo firewall-cmd --permanent --remove-port=80/tcp
sudo firewall-cmd --reload
  • --permanent:写入永久规则(否则重启后失效)
  • --reload:重新加载规则(使永久规则生效)

开放/关闭服务

1
2
3
4
5
6
# 开放 HTTP 服务(包含 80 端口)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload

# 查看当前开放的服务和端口
sudo firewall-cmd --list-all

常见服务名httphttpssshntpmysqlpostgresql 等。

zone 概念

firewalld 使用 zone(区域)来定义不同的安全级别:

Zone 名称 信任级别 默认策略 典型应用场景
drop 最低 丢弃所有传入流量,不回应 最高安全性,完全隐藏设备
public 默认拒绝所有入站,仅允许 SSH 公共网络(如 WiFi 热点)
work 允许内部可信网络访问,默认允许 SSH 、 Samba 公司内部网络
home 允许家用网络访问 家庭网络
trusted 最高 允许所有流量 完全信任的环境

查看当前默认 zone

1
sudo firewall-cmd --get-default-zone

修改默认 zone

1
sudo firewall-cmd --set-default-zone=work


计划任务( crontab)

计划任务让系统在指定时间自动执行某些脚本或命令,例如:

  • 定时备份数据库(每天凌晨 2 点)
  • 定时清理日志文件或临时文件夹(每周日)
  • 定时同步时间(每小时)

编辑与查看

1
2
3
crontab -e  # 编辑当前用户的计划任务
crontab -l # 查看当前用户的计划任务
crontab -r # 删除当前用户的所有计划任务

格式

1
MIN HOUR DAY MONTH WEEKDAY command
  • MIN:分钟( 0-59)
  • HOUR:小时( 0-23)
  • DAY:日期( 1-31)
  • MONTH:月份( 1-12)
  • WEEKDAY:星期( 0-7, 0 和 7 都表示周日)
  • command:要执行的命令(建议使用绝对路径)

特殊符号

  • *:表示"每"(如 * 在分钟位表示每分钟)
  • -:表示范围(如 1-5 表示 1 到 5)
  • /:表示间隔(如 */10 表示每 10 个单位)
  • ,:表示多个值(如 1,2,6 表示 1 、 2 、 6)

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 每天凌晨 1:30 运行备份脚本
30 1 * * * /usr/local/bin/backup.sh

# 每天凌晨 2:30 同步时间(结果重定向到黑洞,不输出)
30 2 * * * /usr/sbin/ntpdate -u ntp.aliyun.com &> /dev/null

# 每小时的第 5 分钟执行一次
5 * * * * /usr/local/bin/hourly-task.sh

# 每 10 分钟执行一次
*/10 * * * * /usr/local/bin/monitor.sh

# 每周日凌晨 3 点执行
0 3 * * 0 /usr/local/bin/weekly-cleanup.sh

查看日志

1
2
grep CRON /var/log/syslog  # Debian/Ubuntu
grep CRON /var/log/cron # CentOS/RHEL

SSH 服务配置与安全加固

SSH 是远程管理 Linux 服务器的标准方式。在"Linux 使用基础"里已经讲了基本用法(ssh user@host、免密登录),这里讲一些 sshd 配置和安全加固

配置文件

配置文件/etc/ssh/sshd_config

修改后需要重启服务:

1
sudo systemctl restart sshd

常见配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 监听端口(默认 22,建议改成其他端口减少被扫描)
Port 22222

# 是否允许 root 用户直接登录(建议禁止)
PermitRootLogin no

# 是否允许密码登录(建议禁止,只用密钥登录)
PasswordAuthentication no

# 是否允许空密码登录(强烈建议禁止)
PermitEmptyPasswords no

# 允许公钥认证
PubkeyAuthentication yes

# 公钥文件位置
AuthorizedKeysFile .ssh/authorized_keys

# 是否允许 X11 转发(图形界面转发)
X11Forwarding yes

# 最大认证尝试次数(防止暴力破解)
MaxAuthTries 3

# 空闲超时时间(秒)
ClientAliveInterval 300
ClientAliveCountMax 0

安全加固建议

  1. 改端口:把默认端口 22 改成其他端口(如 22222),减少被扫描的概率
  2. 禁止 root 登录PermitRootLogin no,只允许普通用户登录,需要权限时再 sudo
  3. 禁止密码登录PasswordAuthentication no,只允许密钥登录(防止暴力破解)
  4. 安装 fail2ban:自动封禁暴力破解的 IP(连续失败多次后自动封禁)
  5. 配置防火墙:只允许特定 IP 连接 SSH(如果有固定 IP)
  6. 使用 SSH 密钥: 4096 位 RSA 或 Ed25519 密钥(比密码安全得多)

服务排障流程:服务起不来怎么办

当服务起不来时,按这个流程排查:

1. 查看服务状态

1
sudo systemctl status <service>

关注:

  • Active:是否显示 active (running)failed
  • Main PID:主进程 PID(如果是 0 说明进程已退出)
  • 最近的日志:通常会显示最后几行日志,看有没有错误信息

2. 查看详细日志

1
sudo journalctl -u <service> -xe
  • -x:显示额外的解释信息
  • -e:跳到日志末尾(最新的日志)

3. 检查配置文件语法

很多服务提供配置文件语法检查工具:

  • nginxnginx -t
  • apacheapachectl configtest
  • sshdsshd -t

4. 检查端口冲突

1
2
sudo ss -lntp | grep <port>  # 查看端口是否被占用
sudo lsof -i :<port> # 查看哪个进程占用了端口

5. 检查文件权限

服务可能因为权限不足而无法启动:

1
2
ls -l /path/to/config
ls -l /var/log/<service>

确保服务运行的用户(如 www-datanginxnobody)有权限读写相关文件。

6. 检查 SELinux / AppArmor

如果开启了 SELinux( RHEL/CentOS)或 AppArmor( Ubuntu/Debian),可能会阻止服务启动。

临时关闭 SELinux(仅用于排查):

1
sudo setenforce 0  # 设置为 Permissive 模式

查看 SELinux 日志

1
sudo ausearch -m avc -ts recent

临时关闭 AppArmor

1
sudo systemctl stop apparmor

7. 检查依赖关系

1
sudo systemctl list-dependencies <service>

如果依赖的服务没有启动,当前服务也无法启动。


总结与扩展阅读

这篇文章涵盖了 systemd 服务管理的核心内容: 1. ✅ systemd 的核心概念( unit 、依赖关系、启动流程) 2. ✅ systemctl 的日常使用(启停、开机自启、查看状态) 3. ✅ 自定义服务(如何让自己的程序开机自启) 4. ✅ journalctl 日志管理(查询、过滤、清理) 5. ✅ 常见服务配置(时间同步、防火墙、计划任务、 SSH) 6. ✅ 服务排障流程(服务起不来怎么办)

扩展阅读

  • systemd 官方文档: https://www.freedesktop.org/wiki/Software/systemd/
  • systemd for Administrators 系列: http://0pointer.de/blog/projects/systemd-for-admins-1.html
  • journalctl 手册:man journalctl
  • systemd.service 手册:man systemd.service

下一步

  • 《 Linux 软件包管理》:学习如何安装/卸载/更新软件包( apt/yum/dnf/rpm)
  • 《 Linux 进程与资源管理》:学习如何监控和限制进程的 CPU/内存使用
  • 《 Linux 用户管理》:学习如何管理用户/组/权限

到这里,建议已经从"会启停服务"升级到"能写自定义服务、能排障、能优化启动顺序"。服务管理是 Linux 运维的核心技能,掌握了 systemd,你就能更好地管理服务器。

  • 本文标题:Linux 系统服务管理
  • 本文作者:Chen Kai
  • 创建时间:2019-12-13 09:15:00
  • 本文链接:https://www.chenk.top/Linux-%E7%B3%BB%E7%BB%9F%E6%9C%8D%E5%8A%A1%E7%AE%A1%E7%90%86/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论