一、什么是 Systemd
Systemd 是 Linux 系统的初始化系统和服务管理器,负责管理系统启动过程中的所有服务(称为"单元")。每个服务对应一个.service单元文件,通过systemctl命令进行管理。
二、创建服务单元文件
服务单元文件通常放在以下两个目录之一:
| 目录 | 说明 |
|---|---|
/etc/systemd/system/ | 推荐,管理员自定义服务,优先级最高 |
/usr/lib/systemd/system/ | 软件包安装时自动放置,不建议手动修改 |
创建命令:
sudovim/etc/systemd/system/myapp.service文件名建议与你的服务名保持一致,后缀必须为
.service
三、编写服务配置
一个标准的.service文件包含三个区块:[Unit]、[Service]、[Install]。
3.1 基本模板
[Unit] Description = My Application Service After = network.target [Service] Type = simple ExecStart = /usr/bin/python3 /opt/myapp/app.py WorkingDirectory = /opt/myapp User = www-data Group = www-data Restart = on-failure RestartSec = 5 StandardOutput = journal StandardError = journal [Install] WantedBy = multi-user.target3.2 字段详解
[Unit] 区块 — 描述与依赖
| 字段 | 说明 | 示例 |
|---|---|---|
Description | 服务描述 | Description=My Web App |
After | 在哪些服务之后启动 | After=network.target |
Requires | 强依赖(依赖失败则本服务也终止) | Requires=postgresql.service |
Wants | 弱依赖(依赖失败不影响本服务) | Wants=network-online.target |
[Service] 区块 — 运行方式
| 字段 | 说明 | 可选值/示例 |
|---|---|---|
Type | 服务类型 | simple(默认,前台进程)、forking(守护进程)、oneshot(一次性任务) |
ExecStart | 启动命令(必须用绝对路径) | ExecStart=/usr/bin/node /opt/app/server.js |
ExecStop | 停止命令(可选,默认发送 SIGTERM) | ExecStop=/bin/kill -SIGTERM $MAINPID |
ExecReload | 重载配置命令 | ExecReload=/bin/kill -HUP $MAINPID |
WorkingDirectory | 工作目录 | WorkingDirectory=/opt/myapp |
User/Group | 运行用户和组(建议非 root) | User=www-data |
Restart | 重启策略 | no、on-failure、always、on-abnormal |
RestartSec | 重启间隔秒数 | RestartSec=5 |
Environment | 环境变量 | Environment="NODE_ENV=production" |
EnvironmentFile | 从文件读取环境变量 | EnvironmentFile=/opt/myapp/.env |
StandardOutput | 标准输出方式 | journal、file:/var/log/myapp.log |
StandardError | 标准错误输出方式 | journal、file:/var/log/myapp-error.log |
LimitNOFILE | 文件描述符限制 | LimitNOFILE=65535 |
[Install] 区块 — 安装目标
| 字段 | 说明 | 示例 |
|---|---|---|
WantedBy | 关联到哪个 target | WantedBy=multi-user.target |
RequiredBy | 强依赖安装目标 | RequiredBy=graphical.target |
常见 target:
multi-user.target:多用户文本模式(服务器常用)graphical.target:图形界面模式
四、注册与启动服务
修改或创建.service文件后,按以下步骤操作:
# 1. 重载 systemd 配置(每次修改 .service 文件后必须执行)sudosystemctl daemon-reload# 2. 启动服务sudosystemctl start myapp# 3. 设置开机自启sudosystemctlenablemyapp# 4. 查看服务状态systemctl status myapp快捷方式:
sudo systemctl enable --now myapp可以一步完成"启用 + 启动"
五、常用管理命令
# 启动服务sudosystemctl start myapp# 停止服务sudosystemctl stop myapp# 重启服务sudosystemctl restart myapp# 重载配置(不重启进程,需要 Service 中配置了 ExecReload)sudosystemctl reload myapp# 设置开机自启sudosystemctlenablemyapp# 取消开机自启sudosystemctl disable myapp# 查看服务状态systemctl status myapp# 重载 systemd 配置sudosystemctl daemon-reload# 查看服务是否已启用systemctl is-enabled myapp# 查看服务是否正在运行systemctl is-active myapp六、日志查看
Systemd 使用journald统一管理日志:
# 实时查看服务日志(类似 tail -f)journalctl-umyapp-f# 查看最近 100 行日志journalctl-umyapp-n100# 查看最近 1 小时的日志journalctl-umyapp--since"1 hour ago"# 查看今天的日志journalctl-umyapp--sincetoday# 查看指定时间范围的日志journalctl-umyapp--since"2024-01-01 00:00:00"--until"2024-01-02 00:00:00"# 查看错误级别以上的日志journalctl-umyapp-perr# 查看上次启动以来的日志journalctl-umyapp-b七、常见问题排查
问题 1:服务启动失败
# 查看详细错误日志journalctl-umyapp-xe# 查看服务状态systemctl status myapp常见原因:
- 路径错误:
ExecStart必须使用绝对路径 - 权限不足:检查
User是否有权限访问工作目录和可执行文件 - 端口占用:检查端口是否已被其他服务占用
- 依赖服务未启动:检查
After和Requires中的依赖服务是否正常运行
问题 2:修改配置不生效
每次修改.service文件后,必须执行:
sudosystemctl daemon-reloadsudosystemctl restart myapp问题 3:脚本无法执行
确保脚本有可执行权限:
chmod+x /opt/myapp/start.sh如果ExecStart中需要使用管道、重定向等shell语法,需要用/bin/bash -c包裹:
ExecStart=/bin/bash-c"/opt/myapp/start.sh | tee /var/log/myapp.log"问题 4:服务反复重启
检查Restart和RestartSec配置,适当增加重启间隔:
Restart=on-failureRestartSec=10八、完整示例
示例 1:Python Flask 应用
[Unit] Description = Flask Web Application After = network.target [Service] Type = simple User = www-data Group = www-data WorkingDirectory = /opt/flask-app Environment = "FLASK_ENV=production" ExecStart = /opt/flask-app/venv/bin/python /opt/flask-app/app.py Restart = on-failure RestartSec = 5 StandardOutput = journal StandardError = journal [Install] WantedBy = multi-user.target示例 2:Node.js 应用
[Unit] Description = Node.js Application After = network.target [Service] Type = simple User = node Group = node WorkingDirectory = /opt/node-app Environment = "NODE_ENV=production" ExecStart = /usr/bin/node /opt/node-app/server.js Restart = on-failure RestartSec = 5 LimitNOFILE = 65535 StandardOutput = journal StandardError = journal [Install] WantedBy = multi-user.target示例 3:Shell 脚本服务
[Unit]Description=My Shell Script ServiceAfter=network.target[Service]Type=simpleUser=rootExecStart=/opt/scripts/backup.shRestart=on-failureRestartSec=10StandardOutput=file:/var/log/backup.logStandardError=file:/var/log/backup-error.log[Install]WantedBy=multi-user.target示例 4:Java Spring Boot 应用
[Unit]Description=Spring Boot ApplicationAfter=network.target[Service]Type=simpleUser=javaGroup=javaWorkingDirectory=/opt/spring-appExecStart=/usr/bin/java-jar/opt/spring-app/app.jarRestart=on-failureRestartSec=10Environment="JAVA_OPTS=-Xms512m -Xmx1024m"StandardOutput=journalStandardError=journal[Install]WantedBy=multi-user.target示例 5:Go 开发的可执行二进制应用
[Unit]Description=Pulse AgentAfter=network.target[Service]Type=simpleExecStart=/usr/local/bin/pulse-agentRestart=on-failureRestartSec=5sEnvironment="PULSE_SERVER=$SERVER_URL"StandardOutput=journalStandardError=journal[Install]WantedBy=multi-user.target快速操作清单
# 1. 创建服务文件sudovim/etc/systemd/system/myapp.service# 2. 重载配置sudosystemctl daemon-reload# 3. 启用并启动sudosystemctlenable--nowmyapp# 4. 查看状态systemctl status myapp# 5. 查看日志journalctl-umyapp-f提示:将上述模板中的
myapp替换为你的实际服务名,将路径和命令替换为你的实际配置即可直接使用。