systemd 服务管理
在你部署的任何稍正式的 Linux 服务器上,后台跑的程序(Nginx、MySQL、Docker、你自己的应用)几乎都是 systemd 管理的。它是现代 Linux(PID 1)的标准服务管理器,负责启动、停止、监控、开机自启、收集日志。掌握 systemd 是从"会用 Linux"到"会部署"的关键一步。
1. 什么是 systemd
systemd 是 2010 年后逐渐取代传统 SysV init 的初始化系统。开机时它是第一个跑的进程(PID 1),负责启动所有其他系统服务。它管理的对象叫 unit(单元),最常见的是 service(服务),还有 timer(定时器)、socket、mount 等。
对开发者来说,systemd 解决一个核心问题:怎么让自己的程序像 Nginx 一样在后台稳定运行、开机自启、崩溃自动重启、日志统一收集。答案是写一个 service unit 文件,用 systemctl 管理。
2. systemctl:基本操作
systemctl 是操作 systemd 的命令。最常用的就是 start/stop/restart/status 四件套:
# systemd:现代 Linux 的服务管理器(PID 1)
# 服务(service / daemon):长期运行的后台程序
# nginx、mysql、sshd、docker 都是服务
# systemctl 是操作服务的命令
sudo systemctl start nginx # 启动
sudo systemctl stop nginx # 停止
sudo systemctl restart nginx # 重启(改完配置后常用)
sudo systemctl reload nginx # 重新加载配置(不断连接,比 restart 温和)
sudo systemctl status nginx # 查看状态(最常用)
# status 输出示例:
# nginx.service - The nginx HTTP and reverse proxy server
# Loaded: loaded (/lib/systemd/system/nginx.service; enabled)
# Active: active (running) since ... <- 运行中
# Main PID: 1234 (nginx)
# Tasks: 2
# Memory: 5.2M
# CPU: 100msstatus 是最高频的——看服务在不在运行、有没有报错。关键看 Active: active (running)(正常)还是 failed(出错)。reload 比 restart 温和:不停服务就重新读配置,适合 Nginx 改配置后不希望断开连接的场景。
3. enable:开机自启
区别两个概念:start 是"现在启动一次",关机后就没了;enable 是"注册开机自启",下次开机自动启动。两者是独立的——可以 enable 但不 start(下次开机才起),也可以 start 但不 enable(只这次启动)。
# 开机自启管理
# enable:注册开机自启(创建符号链接到启动目录)
sudo systemctl enable nginx # 下次开机自动启动
sudo systemctl disable nginx # 取消开机自启
# enable 不会立刻 start,要分开做
sudo systemctl enable --now nginx # --now:同时启动(enable + start)
# 查看开机自启的服务
systemctl list-unit-files --type=service --state=enabled
# nginx.service enabled
# docker.service enabled
# ssh.service enabled
# 查看所有服务(含未启用的)
systemctl list-units --type=service
systemctl list-units --type=service --state=running # 正在运行的
systemctl list-units --type=service --state=failed # 失败的装完数据库、Web 服务器后,标准做法是 sudo systemctl enable --now 服务名——同时启动并设置开机自启。--now 是 enable/start 二合一,很方便。
4. journalctl:统一日志
传统 Linux 各服务的日志散落在 /var/log 各处,systemd 把它们统一收集到 journal 里,用 journalctl 一个命令查所有。这是排查问题最强工具。
# journalctl:查看 systemd 收集的日志(统一日志系统)
# 看某个服务的日志
sudo journalctl -u nginx # nginx 所有日志
sudo journalctl -u nginx -f # -f 实时跟随(等于 tail -f)
sudo journalctl -u nginx --since today # 今天的
sudo journalctl -u nginx --since "1 hour ago" # 最近 1 小时
sudo journalctl -u nginx -n 100 # 最后 100 条
# 看所有日志
sudo journalctl # 全部(很多)
sudo journalctl --since "2024-08-05" # 某天起
sudo journalctl -p err # 只看错误级别(priority)
# 级别:emerg alert crit err warning notice info debug
# 看内核日志(类似 dmesg)
sudo journalctl -k
# 看本次启动的日志
sudo journalctl -b
sudo journalctl -b -1 # 上一次启动的(系统崩溃后排查)
# 输出不分页(管道用)
sudo journalctl -u nginx --no-pager | tail -n 50高频组合:journalctl -u 服务名 -f 实时跟随日志(等于 tail -f 但不用知道日志文件在哪)。系统出问题先 journalctl -p err 看所有错误。
5. 写一个自己的 service
这是 systemd 最实用的部分。把你的应用(一个 Node.js 服务、Python 脚本、Go 二进制)做成 systemd service,就拥有了和 Nginx 一样的待遇——后台运行、开机自启、崩溃重启、统一日志。
# 编写自己的 service:unit 文件
# 示例:把一个 Node.js 应用做成服务
# 创建文件:/etc/systemd/system/myapp.service
[Unit]
Description=My Node.js App # 描述
After=network.target # 在网络服务之后启动(依赖)
[Service]
Type=simple # 简单类型(forking/oneshot 等)
User=deploy # 以 deploy 用户身份运行
WorkingDirectory=/opt/myapp # 工作目录
ExecStart=/usr/bin/node server.js # 启动命令(必须绝对路径)
Restart=on-failure # 崩溃后自动重启
RestartSec=5 # 重启间隔 5 秒
Environment=NODE_ENV=production # 环境变量
Environment=PORT=3000
[Install]
WantedBy=multi-user.target # 在多用户模式下启用(开机自启)几个关键字段:
- ExecStart:启动命令,必须是绝对路径(systemd 不走 PATH)。
- User:以哪个用户跑(别用 root)。
- Restart=on-failure:崩溃后自动重启,生产必备。
- After=network.target:声明依赖,网络起来后再启动。
- WantedBy=multi-user.target:决定 enable 时在哪个启动级别注册。
6. 管理自定义服务的完整流程
# 管理自定义服务
# 1. 写完 unit 文件后,让 systemd 重新加载
sudo systemctl daemon-reload # 通知 systemd 配置变了
# 2. 启动并设置开机自启
sudo systemctl enable --now myapp
# 3. 查看状态
sudo systemctl status myapp
# Active: active (running) 即正常
# 4. 看日志
sudo journalctl -u myapp -f
# 5. 修改 unit 文件后(改完配置)
sudo systemctl daemon-reload # 先 reload 配置
sudo systemctl restart myapp # 再重启服务
# 6. 卸载服务
sudo systemctl disable --now myapp # 停止并取消自启
sudo rm /etc/systemd/system/myapp.service
sudo systemctl daemon-reload最常被忘的一步是 systemctl daemon-reload。每次修改 unit 文件后必须执行,否则 systemd 还在用旧配置。这是新手最常见的"我改了为啥没生效"的原因。
7. 实战:部署一个 Node.js 应用
把前面的知识串起来,完整流程:
- 把代码放到
/opt/myapp,npm install装好依赖。 - 创建用户
sudo useradd -r -s /bin/false deploy(专用账号,不能登录)。 - 改所有者
sudo chown -R deploy:deploy /opt/myapp。 - 写
/etc/systemd/system/myapp.service(参考上面的模板)。 sudo systemctl daemon-reload && sudo systemctl enable --now myapp。sudo systemctl status myapp确认 active (running)。sudo journalctl -u myapp -f看启动日志。- 更新代码后:
git pull && sudo systemctl restart myapp。
这套流程对所有语言通用——Python 换 ExecStart 为 /usr/bin/python3 app.py,Go 换成编译好的二进制路径即可。
8. systemd timer:替代 cron(进阶)
传统定时任务用 cron,systemd 提供了更强的 timer 单元,有依赖管理、错误日志、错过补跑等优势:
# systemd timer:替代 cron 的定时任务(进阶)
# 写一个 timer unit,定时触发对应 service
# /etc/systemd/system/backup.service
[Unit]
Description=Backup Service
[Service]
ExecStart=/opt/scripts/backup.sh
# /etc/systemd/system/backup.timer
[Unit]
Description=Daily Backup
[Timer]
OnCalendar=daily # 每天(也支持 *-*-* 03:00:00)
Persistent=true # 错过了开机后补跑
[Install]
WantedBy=timers.target
# 启用 timer(不是 service)
sudo systemctl enable --now backup.timer
systemctl list-timers # 看所有定时任务timer 在现代发行版里越来越流行,但 cron 简单够用,日常两者都行。
9. 常见问题
- 状态是 failed:看
systemctl status 服务名末尾的日志,或journalctl -u 服务名 -n 50。常见原因是配置文件语法错、端口被占、权限不对。 - 改了 unit 文件不生效:忘了
daemon-reload。 - 服务停了又起来:Restart=on-failure 在工作,看 journalctl 找崩溃原因。
- start 卡住没响应:可能是 Type=forking 的服务等待子进程,加
--no-block或检查配置。 - 查看依赖关系:
systemctl list-dependencies nginx。
小结
这一篇你学会了 systemd 服务管理:systemctl 启停重启查状态、enable --now 开机自启、journalctl 查日志、写 service unit 文件把自己的程序做成服务。这是 Linux 工程化的核心——掌握它,你就能像专业运维一样部署和管理任何服务。恭喜你完成了 Linux 入门系列!
下一步学什么?
- 实战:租一台云服务器(阿里云、腾讯云轻量几十块一年),把一个网站部署上去。
- Docker:用容器打包应用,免去手动配环境的麻烦。我们有专门的 Docker 教程。
- 网络工具:netstat、ss、tcpdump、curl、wget。
- 性能分析:strace、perf、iostat、sar。
- 经典书:《鸟哥的 Linux 私房菜》(中文最好的入门书)、《Linux 命令行与 Shell 脚本编程大全》。
Linux 命令行的特点是"入门陡、精通后无敌"。坚持用一周,你会发现它比图形界面快十倍,而且一旦学会,在任何发行版、任何服务器、任何容器里都能用——这是一辈子的技能。
← 上一篇 SSH 远程连接
← 返回 Linux 教程目录