在 Linux 中通过 systemctl 管理 Python 脚本作为系统服务 运行,核心是创建 systemd 服务配置文件(.service),让系统以守护进程方式启动 / 管理你的 Python 代码。以下是详细步骤,包含完整示例和避坑要点:
一、核心原理
systemd 是 Linux 系统的初始化 / 服务管理工具,systemctl 是其命令行工具。通过编写 .service 配置文件,定义 Python 脚本的运行指令、运行用户、工作目录、重启策略等,systemd 会将脚本作为系统服务托管(支持开机自启、异常重启、日志记录等)。
二、完整实现步骤
步骤 1:准备 Python 脚本
先确保 Python 脚本能在命令行手动运行(无路径、依赖问题),示例脚本 my_script.py:
python
# /root/data1/u-net/my_script.py(示例路径,替换为你的脚本路径)
import time
import logging
# 配置日志(建议输出到文件,方便排查)
logging.basicConfig(
filename='/root/data1/u-net/script.log', # 日志文件路径
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
if __name__ == '__main__':
logging.info("Python 服务已启动")
try:
while True: # 模拟持续运行的服务(如后台任务、接口服务等)
logging.info("服务运行中...")
time.sleep(10) # 每10秒输出一次
except Exception as e:
logging.error(f"服务异常: {str(e)}", exc_info=True)
raise
步骤 2:创建 systemd 服务配置文件
systemd 服务文件默认存放在 /etc/systemd/system/(系统级)或 ~/.config/systemd/user/(用户级),推荐用系统级(需 root 权限)。
创建服务文件(命名规范:xxx.service,比如 python-u-net.service):
vim /etc/systemd/system/python-u-net.service
写入以下配置(关键参数需根据你的环境修改):
bash
[Unit]
Description=Python U-Net Service # 服务描述(自定义)
After=network.target # 依赖:网络启动后再启动该服务(无网络依赖可删)
Wants=network.target # 可选:弱依赖网络服务
[Service]
# 核心配置
Type=simple # 服务类型(simple:前台运行,适合脚本;forking:后台进程)
User=root # 运行用户(建议用非root用户,如ubuntu,需确保该用户有脚本/日志权限)
Group=root # 运行用户组
WorkingDirectory=/root/data1/u-net # 脚本工作目录(脚本中相对路径的基准)
Environment="PYTHONPATH=/root/data1/u-net/envs/u-net-v0/lib/python3.10/site-packages" # 虚拟环境PYTHONPATH(可选,若用虚拟环境)
ExecStart=/root/data1/u-net/envs/u-net-v0/bin/python3 /root/data1/u-net/my_script.py # 启动指令(绝对路径!)
# 重启策略(异常崩溃自动重启)
Restart=on-failure # 失败时重启(可选值:always/on-abnormal/on-failure/on-watchdog)
RestartSec=5 # 重启间隔5秒
# 日志配置(默认输出到systemd日志,也可自定义)
StandardOutput=append:/root/data1/u-net/service_stdout.log # 标准输出重定向(可选)
StandardError=append:/root/data1/u-net/service_stderr.log # 标准错误重定向(可选)
[Install]
WantedBy=multi-user.target # 开机自启的目标级别(多用户模式)
配置参数关键说明:
| 参数 | 作用 |
|---|---|
ExecStart |
服务启动指令(必须用绝对路径 !):虚拟环境:/path/to/venv/bin/python3 /path/to/script.py系统 Python:/usr/bin/python3 /path/to/script.py |
WorkingDirectory |
脚本的工作目录(脚本中若用相对路径读取文件,基于此目录) |
User |
运行用户(避免用 root,若必须用需确认权限) |
Restart |
重启策略:on-failure(脚本报错 / 崩溃时重启),always(始终重启) |
Environment |
环境变量(如虚拟环境、CUDA 路径、自定义变量),多个变量用空格分隔 |
步骤 3:重载 systemd 配置并管理服务
bash
# 1. 重载systemd配置(修改服务文件后必须执行)
systemctl daemon-reload
# 2. 启动服务(替换为你的服务名,如python-u-net)
systemctl start python-u-net
# 3. 设置开机自启(可选,建议开启)
systemctl enable python-u-net
# 4. 查看服务状态(验证是否启动成功)
systemctl status python-u-net
步骤 4:验证与排查
(1)查看服务状态
正常启动会显示 active (running)
bash
systemctl status python-u-net
# 输出示例:
# ● python-u-net.service - Python U-Net Service
# Loaded: loaded (/etc/systemd/system/python-u-net.service; enabled; vendor preset: enabled)
# Active: active (running) since Wed 2025-12-10 10:00:00 CST; 10s ago
# Main PID: 12345 (python3)
# Tasks: 10 (limit: 4915)
# Memory: 100.0M
# CGroup: /system.slice/python-u-net.service
# └─12345 /root/data1/u-net/envs/u-net-v0/bin/python3 /root/data1/u-net/my_script.py
(2)查看服务日志(关键排错手段)
bash
# 实时查看日志(-f 跟踪最新输出)
journalctl -u python-u-net -f
# 查看最近100行日志
journalctl -u python-u-net -n 100
# 按时间筛选日志(比如今天的)
journalctl -u python-u-net --since "today"
(3)其他常用命令
bash
# 停止服务
systemctl stop python-u-net
# 重启服务
systemctl restart python-u-net
# 禁用开机自启
systemctl disable python-u-net
# 检查服务文件语法错误
systemd-analyze verify /etc/systemd/system/python-u-net.service
三、关键避坑要点
1. 绝对路径!绝对路径!绝对路径!
ExecStart中的 Python 解释器路径:用which python3(系统 Python)或~/venv/bin/python3(虚拟环境)确认绝对路径,禁止用python3或python(可能指向错误版本)。- 脚本路径、日志路径、工作目录均用绝对路径(避免相对路径导致找不到文件)。
2. 虚拟环境适配
若你的 Python 脚本依赖虚拟环境,ExecStart 必须用虚拟环境内的 Python 解释器(如示例中的 /root/data1/u-net/envs/u-net-v0/bin/python3),而非系统 Python。
3. 权限问题
- 运行用户(
User=)需有:脚本文件的读权限 、日志文件 / 目录的写权限 、虚拟环境目录的读权限。 - 若用非 root 用户,避免脚本 / 日志路径在
/root/下(普通用户无权限)。
4. 脚本持续运行
若你的 Python 脚本是 "一次性执行"(而非循环 / 后台服务),systemd 会启动后立即退出。解决方法:
- 脚本中加无限循环(如示例中的
while True); - 若需一次性执行,修改
Service段:
bash
Type=oneshot
RemainAfterExit=yes # 执行完后仍标记为active
5. CUDA/GPU 环境适配
若脚本依赖 GPU,需在 Environment 中配置 CUDA 环境变量(避免服务启动时找不到 CUDA):
bash
Environment="CUDA_HOME=/usr/local/cuda-11.6"
Environment="PATH=/usr/local/cuda-11.6/bin:$PATH"
Environment="LD_LIBRARY_PATH=/usr/local/cuda-11.6/lib64:$LD_LIBRARY_PATH"
四、示例:完整的服务文件
bash
[Unit]
Description=U-Net Python Service
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/root/data1/u-net
Environment="PYTHONPATH=/root/data1/u-net/envs/u-net-v0/lib/python3.10/site-packages"
Environment="CUDA_HOME=/usr/local/cuda-11.6"
Environment="LD_LIBRARY_PATH=/usr/local/cuda-11.6/lib64:$LD_LIBRARY_PATH"
ExecStart=/root/data1/u-net/envs/u-net-v0/bin/python3 /root/data1/u-net/your_u_net_script.py
Restart=on-failure
RestartSec=5
StandardOutput=append:/root/data1/u-net/u-net.log
StandardError=append:/root/data1/u-net/u-net_error.log
[Install]
WantedBy=multi-user.target