一、先跑起来
# 1. 准备脚本
sudo tee /usr/local/bin/date_demo.sh <<'EOF'
#!/bin/bash
while :; do echo "[$(date)] Hello systemd" >>/var/log/date_demo.log; sleep 60; done
EOF
sudo chmod +x /usr/local/bin/date_demo.sh
# 2. 写最简 .service
sudo tee /etc/systemd/system/date_demo.service <<'EOF'
[Unit]
Description=Date demo service
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/date_demo.sh
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
# 3. 加载 + 启动 + 开机自启
sudo systemctl daemon-reload
sudo systemctl enable –now date_demo
sudo systemctl status date_demo
# 看日志
sudo journalctl -u date_demo -f
至此,你已经掌握了“脚本→服务→自启→日志”完整闭环 。
二、编写单元文件必知必会
- [Unit] 管“依赖、启动顺序”
- [Service] 管“怎么跑、跑谁、跑挂了怎么办”
- [Install] 管“开机要不要带出来”
| Description= | 一句话说明 | My Web API |
| After= / Before= | 顺序 | After=network-online.target mysql.service |
| Wants= / Requires= | 弱/强依赖 | Wants=redis |
| Type= | 启动方式 | simple(默认) forking(旧守护) oneshot(一次性) |
| ExecStart= | 主进程 | /usr/local/bin/api.sh |
| ExecReload= | 平滑重载 | /bin/kill -HUP $MAINPID |
| Restart= | 自动重启策略 | always on-failure no |
| RestartSec= | 重启间隔 | 10s |
| User= / Group= | 降权运行 | User=app |
| WantedBy= | 开机自启目标 | multi-user.target |
- forking 类型必须配 PIDFile=,否则 systemd 找不到“主进程” 。
- oneshot 类型搭配 RemainAfterExit=yes 才能实现“一次性但保持 active”状态 。
- 降权运行时,工作目录 / 缓存目录要提前赋权,否则频繁报 Permission denied。
三、高频场景模板(直接改路径即可)
[Unit]
Description=Frp Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/frp/frps -c /usr/local/frp/frps.toml
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
[Unit]
Description=My Flask API
After=network-online.target
[Service]
Type=simple
User=app
WorkingDirectory=/opt/myapp
ExecStart=/opt/venv/bin/gunicorn -w 4 -b 0.0.0.0:8000 app:app
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=20s
Environment="PATH=/opt/venv/bin"
[Install]
WantedBy=multi-user.target
rsync-to-win.service
[Unit]
Description=Backup to Windows share
[Service]
Type=oneshot
ExecStart=/usr/local/bin/rsync_to_win.sh
rsync-to-win.timer
[Unit]
Description=Run backup every 10 min
[Timer]
OnCalendar=*:0/10
Persistent=true
[Install]
WantedBy=timers.target
启用:
sudo systemctl daemon-reload
sudo systemctl enable –now rsync-to-win.timer
# 查看下次执行时间
systemctl list-timers
四、日常运维 6 命令
| 修改完 .service 文件 | sudo systemctl daemon-reload |
| 启动/停止/重启 | sudo systemctl start|stop|restart 单元名 |
| 开机自启 / 关闭 | sudo systemctl enable|disable 单元名 |
| 看实时日志 | sudo journalctl -u 单元名 -f |
| 看历史启动耗时 | systemd-analyze blame |
| 看单元依赖图 | systemctl dot | dot -Tsvg > /tmp/tree.svg |
五、排错 3 板斧
状态高亮法
systemctl status 单元名 ➜ 红色关键字 failed / exit-code / signal 直接定位。
日志级别法
sudo journalctl -u 单元名 -o cat -p err..alert 只看错误与告警。
手动跑一遍法
把 ExecStart= 命令原样复制到终端执行,90% 路径/权限/环境变量错误会立即现形。
六、进阶路线(用到再查)
- 资源限制:MemoryMax=、TasksMax=、LimitNOFILE=
- 平滑启动:ExecStartPre=、ExecStartPost=、TimeoutStartSec=
- 多实例模板:@.service 模板 + 实例名
- 用户级服务:systemctl –user enable 单元名(无需 root)
- 网络依赖:systemd-networkd-wait-online.service 与 network-online.target 的区别
七、一句话总结
“写单元文件就是填空题:描述→依赖→怎么跑→跑挂怎么办→要不要自启;
日常运维就是 6 个命令:reload、start、enable、status、journalctl、list-timers。”
掌握以上套路后,任何脚本、二进制、Python 项目、定时任务都能 5 分钟接入 systemd。祝玩得开心!
网硕互联帮助中心





评论前必须登录!
注册