服务是在后台运行的程序,提供系统功能或网络服务。Linux使用systemd作为系统和服务管理器,通过systemctl命令管理服务。本章将深入讲解Linux服务管理的概念和实践。
systemd:Linux系统的初始化系统和服务管理器。
systemd特点:
东巴文观点:systemd是现代Linux系统的核心,管理着系统启动和服务运行。
systemd主要组件:
| 组件 | 说明 |
|---|---|
| systemd | 系统和服务管理器 |
| systemctl | 服务管理命令 |
| journalctl | 日志管理命令 |
| systemd-analyze | 启动分析工具 |
| hostnamectl | 主机名管理 |
| localectl | 区域设置管理 |
| timedatectl | 时间日期管理 |
| loginctl | 登录会话管理 |
systemd单元类型:
| 单元类型 | 扩展名 | 说明 |
|---|---|---|
| Service | .service | 服务单元 |
| Socket | .socket | 套接字单元 |
| Device | .device | 设备单元 |
| Mount | .mount | 挂载点单元 |
| Automount | .automount | 自动挂载单元 |
| Swap | .swap | 交换分区单元 |
| Path | .path | 路径单元 |
| Timer | .timer | 定时器单元 |
| Target | .target | 目标单元 |
| Snapshot | .snapshot | 快照单元 |
| Slice | .slice | 资源控制单元 |
东巴文理解:systemd通过不同类型的单元管理系统资源,service是最常用的单元类型。
# 查看systemd版本
systemctl --version
# 输出示例:
# systemd 245 (245.4-4ubuntu3)
# +PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP
# 查看启动时间
systemd-analyze
# 输出示例:
# Startup finished in 5.123s (kernel) + 10.456s (userspace) = 15.579s
# 查看各服务启动时间
systemd-analyze blame
# 输出示例:
# 5.123s NetworkManager-wait-online.service
# 2.456s apt-daily.service
# 1.789s snapd.service
# 查看启动关键链
systemd-analyze critical-chain
# 输出示例:
# graphical.target @10.456s
# └─multi-user.target @10.456s
# └─NetworkManager.service @8.123s +2.333s
# └─network-pre.target @8.123s
东巴文技巧:使用systemd-analyze blame可以找出启动慢的服务。
# 查看默认目标
systemctl get-default
# 输出示例:
# graphical.target
# 查看所有目标
systemctl list-units --type=target
# 输出示例:
# UNIT LOAD ACTIVE SUB DESCRIPTION
# basic.target loaded active active Basic System
# graphical.target loaded active active Graphical Interface
# multi-user.target loaded active active Multi-User System
常用目标:
| 目标 | 说明 |
|---|---|
| poweroff.target | 关机 |
| rescue.target | 救援模式 |
| multi-user.target | 多用户模式(无图形界面) |
| graphical.target | 图形界面模式 |
| reboot.target | 重启 |
# 查看服务状态
systemctl status nginx
# 输出示例:
# ● nginx.service - A high performance web server and a reverse proxy server
# Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
# Active: active (running) since Mon 2024-01-01 10:00:00 CST; 1h 30min ago
# Docs: man:nginx(8)
# Main PID: 1234 (nginx)
# Tasks: 3 (limit: 4915)
# Memory: 5.2M
# CGroup: /system.slice/nginx.service
# ├─1234 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
# ├─1235 nginx: worker process
# └─1236 nginx: worker process
#
# Jan 01 10:00:00 server systemd[1]: Starting A high performance web server...
# Jan 01 10:00:00 server systemd[1]: Started A high performance web server...
# 查看服务是否运行
systemctl is-active nginx
# 输出示例:
# active
# 查看服务是否开机启动
systemctl is-enabled nginx
# 输出示例:
# enabled
# 查看服务是否失败
systemctl is-failed nginx
# 输出示例:
# inactive
服务状态说明:
| 状态 | 说明 |
|---|---|
| active (running) | 正在运行 |
| active (exited) | 已成功执行完成 |
| active (waiting) | 等待中 |
| inactive | 未运行 |
| activating | 正在启动 |
| deactivating | 正在停止 |
| failed | 启动失败 |
# 启动服务
sudo systemctl start nginx
# 启动多个服务
sudo systemctl start nginx mysql
# 启动服务并显示详细输出
sudo systemctl start nginx --verbose
东巴文提示:启动服务需要root权限。
# 停止服务
sudo systemctl stop nginx
# 停止多个服务
sudo systemctl stop nginx mysql
# 强制停止服务
sudo systemctl kill nginx
# 重启服务
sudo systemctl restart nginx
# 重载服务配置(不中断服务)
sudo systemctl reload nginx
# 重载或重启(如果服务不支持reload,则restart)
sudo systemctl reload-or-restart nginx
东巴文理解:
# 设置开机启动
sudo systemctl enable nginx
# 输出示例:
# Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /lib/systemd/system/nginx.service.
# 取消开机启动
sudo systemctl disable nginx
# 输出示例:
# Removed /etc/systemd/system/multi-user.target.wants/nginx.service.
# 启用并立即启动
sudo systemctl enable --now nginx
# 禁用并立即停止
sudo systemctl disable --now nginx
# 查看是否开机启动
systemctl is-enabled nginx
东巴文最佳实践:使用enable --now可以一步完成启用和启动。
# 掩码服务(禁止启动)
sudo systemctl mask nginx
# 输出示例:
# Created symlink /etc/systemd/system/nginx.service → /dev/null.
# 取消掩码
sudo systemctl unmask nginx
# 输出示例:
# Removed /etc/systemd/system/nginx.service.
东巴文理解:掩码服务比disable更彻底,服务完全无法启动。
# 列出所有已加载的服务
systemctl list-units --type=service
# 输出示例:
# UNIT LOAD ACTIVE SUB DESCRIPTION
# accounts-daemon.service loaded active running Accounts Service
# cron.service loaded active running Regular background program processing daemon
# nginx.service loaded active running A high performance web server
# 列出所有服务(包括未加载的)
systemctl list-unit-files --type=service
# 输出示例:
# UNIT FILE STATE
# accounts-daemon.service enabled
# cron.service enabled
# nginx.service enabled
# 列出运行中的服务
systemctl list-units --type=service --state=running
# 列出失败的服务
systemctl list-units --type=service --state=failed
# 列出已启用的服务
systemctl list-unit-files --type=service --state=enabled
# 列出已禁用的服务
systemctl list-unit-files --type=service --state=disabled
# 列出所有状态的服务
systemctl list-units --all --type=service
# 列出指定状态的服务
systemctl list-units --type=service --state=active
systemctl list-units --type=service --state=running
systemctl list-units --type=service --state=exited
systemctl list-units --type=service --state=failed
# 列出最近失败的服务
systemctl --failed
# 查看服务依赖
systemctl list-dependencies nginx
# 输出示例:
# nginx.service
# ● ├─system.slice
# ● └─basic.target
# ├─paths.target
# ├─slices.target
# └─sockets.target
# 查看反向依赖(哪些服务依赖此服务)
systemctl list-dependencies nginx --reverse
# 查看服务依赖树
systemctl list-dependencies nginx --plain
# 查看服务配置文件内容
systemctl cat nginx
# 输出示例:
# /lib/systemd/system/nginx.service
# [Unit]
# Description=A high performance web server and a reverse proxy server
# After=network.target
#
# [Service]
# Type=forking
# PIDFile=/run/nginx.pid
# ExecStartPre=/usr/sbin/nginx -t
# ExecStart=/usr/sbin/nginx
# ExecReload=/bin/kill -s HUP $MAINPID
# ExecStop=/bin/kill -s QUIT $MAINPID
# PrivateTmp=true
#
# [Install]
# WantedBy=multi-user.target
# 查看服务配置文件路径
systemctl show nginx -p FragmentPath
# 输出示例:
# FragmentPath=/lib/systemd/system/nginx.service
# 查看所有属性
systemctl show nginx
# 查看指定属性
systemctl show nginx -p MainPID
# 输出示例:
# MainPID=1234
# 查看多个属性
systemctl show nginx -p MainPID,ExecStart
# 输出示例:
# MainPID=1234
# ExecStart={ path=/usr/sbin/nginx ; argv[]=/usr/sbin/nginx ; ignore_errors=no ; start_time=[Mon 2024-01-01 10:00:00 CST] ; stop_time=[n/a] ; pid=1234 ; code=(null) ; status=0/0 }
常用属性:
| 属性 | 说明 |
|---|---|
| MainPID | 主进程PID |
| ExecStart | 启动命令 |
| ExecStop | 停止命令 |
| ExecReload | 重载命令 |
| ActiveState | 活动状态 |
| SubState | 子状态 |
| LoadState | 加载状态 |
| UnitFileState | 单元文件状态 |
# 设置服务属性(临时)
sudo systemctl set-property nginx MemoryLimit=512M
# 设置服务属性(永久)
sudo systemctl set-property nginx MemoryLimit=512M --runtime=no
# 查看设置
systemctl show nginx -p MemoryLimit
# 重载systemd配置
sudo systemctl daemon-reload
# 重载所有服务
sudo systemctl daemon-reload --no-reload
# 重置失败状态
sudo systemctl reset-failed
# 重置指定服务的失败状态
sudo systemctl reset-failed nginx
东巴文提示:修改服务配置文件后,需要执行systemctl daemon-reload。
服务文件存放位置:
| 位置 | 优先级 | 说明 |
|---|---|---|
| /etc/systemd/system/ | 最高 | 管理员自定义 |
| /run/systemd/system/ | 中 | 运行时创建 |
| /lib/systemd/system/ | 低 | 软件包安装 |
| /usr/lib/systemd/system/ | 低 | 软件包安装 |
东巴文理解:优先级高的会覆盖优先级低的同名服务文件。
服务文件示例:
[Unit]
Description=Nginx HTTP Server
Documentation=man:nginx(8)
After=network.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
[Unit]部分配置:
| 配置项 | 说明 |
|---|---|
| Description | 服务描述 |
| Documentation | 文档地址 |
| After | 在哪些服务之后启动 |
| Before | 在哪些服务之前启动 |
| Wants | 依赖的服务 |
| Requires | 强依赖的服务 |
| Conflicts | 冲突的服务 |
| ConditionPathExists | 文件存在时才启动 |
| ConditionPathIsDirectory | 目录存在时才启动 |
示例:
[Unit]
Description=MySQL Database Server
Documentation=man:mysqld(8)
Documentation=https://dev.mysql.com/doc/refman/en/
After=network.target
After=syslog.target
Wants=network-online.target
Requires=network.target
[Service]部分配置:
服务类型:
| Type | 说明 |
|---|---|
| simple | 默认类型,ExecStart启动的进程是主进程 |
| forking | ExecStart启动的进程会fork子进程,父进程退出 |
| oneshot | 执行一次就退出 |
| notify | 服务启动完成后发送通知 |
| dbus | 服务启动后获取D-Bus名称 |
执行命令:
| 配置项 | 说明 |
|---|---|
| ExecStart | 启动命令 |
| ExecStartPre | 启动前执行的命令 |
| ExecStartPost | 启动后执行的命令 |
| ExecStop | 停止命令 |
| ExecStopPost | 停止后执行的命令 |
| ExecReload | 重载命令 |
重启策略:
| Restart | 说明 |
|---|---|
| no | 不重启(默认) |
| on-success | 成功退出时重启 |
| on-failure | 失败退出时重启 |
| on-abnormal | 异常退出时重启 |
| on-watchdog | 看门狗超时时重启 |
| on-abort | 未捕获信号退出时重启 |
| always | 总是重启 |
资源限制:
| 配置项 | 说明 |
|---|---|
| LimitNOFILE | 最大文件描述符数 |
| LimitNPROC | 最大进程数 |
| LimitCORE | 核心转储大小 |
| MemoryLimit | 内存限制 |
| CPUShares | CPU权重 |
| BlockIOWeight | IO权重 |
安全设置:
| 配置项 | 说明 |
|---|---|
| PrivateTmp | 使用私有/tmp目录 |
| NoNewPrivileges | 禁止提升权限 |
| ProtectSystem | 保护系统目录 |
| ProtectHome | 保护用户主目录 |
| ReadOnlyPaths | 只读路径 |
| ReadWritePaths | 读写路径 |
示例:
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
Restart=on-failure
RestartSec=5s
LimitNOFILE=65535
[Install]部分配置:
| 配置项 | 说明 |
|---|---|
| WantedBy | 服务被哪个target依赖 |
| RequiredBy | 服务被哪个target强依赖 |
| Also | 同时安装的服务 |
| Alias | 服务别名 |
示例:
[Install]
WantedBy=multi-user.target
创建服务文件:
sudo vim /etc/systemd/system/myapp.service
服务文件内容:
[Unit]
Description=My Application
After=network.target
[Service]
Type=simple
User=dbw
Group=dbw
WorkingDirectory=/home/dbw/myapp
ExecStart=/home/dbw/myapp/myapp
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
启用服务:
# 重载systemd配置
sudo systemctl daemon-reload
# 启用并启动服务
sudo systemctl enable --now myapp
# 查看服务状态
systemctl status myapp
服务文件:
[Unit]
Description=Python Flask Application
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
Environment="PATH=/var/www/myapp/venv/bin"
ExecStart=/var/www/myapp/venv/bin/python app.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
服务文件:
[Unit]
Description=Node.js Application
After=network.target
[Service]
Type=simple
User=node
Group=node
WorkingDirectory=/home/node/myapp
ExecStart=/usr/bin/node /home/node/myapp/app.js
Restart=on-failure
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=nodejs-app
[Install]
WantedBy=multi-user.target
创建覆盖配置:
# 创建服务配置目录
sudo mkdir -p /etc/systemd/system/nginx.service.d/
# 创建覆盖配置文件
sudo vim /etc/systemd/system/nginx.service.d/override.conf
覆盖配置内容:
[Service]
LimitNOFILE=65535
Restart=always
RestartSec=10s
应用配置:
# 重载systemd配置
sudo systemctl daemon-reload
# 重启服务
sudo systemctl restart nginx
# 查看合并后的配置
systemctl cat nginx
东巴文最佳实践:使用override.conf修改服务配置,不直接修改原始服务文件。
# 编辑服务配置(自动创建override.conf)
sudo systemctl edit nginx
# 编辑完整服务文件
sudo systemctl edit --full nginx
# 输出示例:
# [Service]
# LimitNOFILE=65535
# Restart=always
# 查看所有日志
journalctl
# 查看最近的日志
journalctl -n 100
# 实时查看日志
journalctl -f
# 查看今天的日志
journalctl --since today
# 查看指定时间范围的日志
journalctl --since "2024-01-01 10:00:00" --until "2024-01-01 11:00:00"
# 查看最近一小时的日志
journalctl --since "1 hour ago"
# 查看昨天的日志
journalctl --since yesterday
# 查看指定服务的日志
journalctl -u nginx
# 查看多个服务的日志
journalctl -u nginx -u mysql
# 实时查看服务日志
journalctl -u nginx -f
# 查看服务最近的日志
journalctl -u nginx -n 100
# 查看服务今天的日志
journalctl -u nginx --since today
# 查看服务启动失败的日志
journalctl -u nginx -p err
# 查看内核日志
journalctl -k
# 查看内核日志(实时)
journalctl -k -f
日志优先级:
| 优先级 | 说明 |
|---|---|
| 0 | emerg - 紧急 |
| 1 | alert - 警报 |
| 2 | crit - 严重 |
| 3 | err - 错误 |
| 4 | warning - 警告 |
| 5 | notice - 通知 |
| 6 | info - 信息 |
| 7 | debug - 调试 |
查看指定优先级的日志:
# 查看错误日志
journalctl -p err
# 查看警告及以上级别的日志
journalctl -p warning
# 查看指定优先级范围的日志
journalctl -p warning..err
# 按PID过滤
journalctl _PID=1234
# 按UID过滤
journalctl _UID=1000
# 按GID过滤
journalctl _GID=1000
# 查看指定用户的日志
journalctl _UID=1000
# 查看当前用户的日志
journalctl --user
# 查看指定设备的日志
journalctl /dev/sda1
# 查看指定可执行文件的日志
journalctl /usr/sbin/nginx
# 默认格式
journalctl -u nginx -n 10
# JSON格式
journalctl -u nginx -n 10 -o json
# JSON-pretty格式
journalctl -u nginx -n 10 -o json-pretty
# 简洁格式
journalctl -u nginx -n 10 -o verbose
# 猫格式(只显示消息)
journalctl -u nginx -n 10 -o cat
# 导出格式
journalctl -u nginx -n 10 -o export
# 查看日志大小
journalctl --disk-usage
# 输出示例:
# Archived and active journals take up 128.0M on disk.
# 清理日志(保留最近100MB)
sudo journalctl --vacuum-size=100M
# 清理日志(保留最近7天)
sudo journalctl --vacuum-time=7d
# 清理日志(保留最近10个日志文件)
sudo journalctl --vacuum-files=10
编辑journald配置:
sudo vim /etc/systemd/journald.conf
配置内容:
[Journal]
# 存储模式:auto、volatile、persistent
Storage=persistent
# 日志最大大小
SystemMaxUse=500M
# 日志最大文件数
SystemMaxFileSize=100M
# 日志保留时间
MaxRetentionSec=1month
# 是否转发到syslog
ForwardToSyslog=yes
# 是否转发到控制台
ForwardToConsole=no
重启journald服务:
sudo systemctl restart systemd-journald
东巴文提示:设置Storage=persistent后,日志会保存到/var/log/journal/目录。
service命令:传统的SysVinit服务管理命令。
# 启动服务
sudo service nginx start
# 停止服务
sudo service nginx stop
# 重启服务
sudo service nginx restart
# 重载服务
sudo service nginx reload
# 查看服务状态
sudo service nginx status
# 查看所有服务状态
sudo service --status-all
东巴文提示:service命令实际上是调用systemctl,建议直接使用systemctl。
chkconfig命令:传统的SysVinit服务开机启动管理命令。
# 查看服务开机启动状态
chkconfig --list
# 设置服务开机启动
sudo chkconfig nginx on
# 取消服务开机启动
sudo chkconfig nginx off
# 添加服务
sudo chkconfig --add nginx
# 删除服务
sudo chkconfig --del nginx
东巴文提示:chkconfig命令在新系统中已不推荐使用,建议使用systemctl。
✅ 理解systemd的概念和组成 ✅ 掌握systemctl命令的使用 ✅ 学会创建和管理服务 ✅ 熟练使用journalctl查看日志
完成本章学习后,请确认您能够:
东巴文(db-w.cn) - 让Linux学习更简单