【笔记】创建systemctl服务

在 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(虚拟环境)确认绝对路径,禁止用 python3python (可能指向错误版本)
  • 脚本路径、日志路径、工作目录均用绝对路径(避免相对路径导致找不到文件)。

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
相关推荐
代码游侠1 天前
学习笔记——GPIO按键与中断系统
c语言·开发语言·arm开发·笔记·嵌入式硬件·学习·重构
bukeyiwanshui1 天前
Nginx 服务器
运维·服务器·nginx
楼田莉子1 天前
Linux学习之库的原理与制作
linux·运维·服务器·c++·学习
市安1 天前
nat模式下lvs规划与部署
服务器·网络·php
浅念-1 天前
C++第一课
开发语言·c++·经验分享·笔记·学习·算法
周公挚友1 天前
2026年单服务器 Ubuntu 24.04 无公网离线部署 MongoDB 8.0.17 三节点副本集(主 / 从 / 仲裁)保姆级教程
linux·mongodb·ubuntu
蓝田生玉1231 天前
PLUTO论文阅读笔记
论文阅读·笔记
HABuo1 天前
【linux进程控制(三)】进程程序替换&自己实现一个bash解释器
linux·服务器·c语言·c++·ubuntu·centos·bash
物理与数学1 天前
Linux 文件系统浅析
linux·linux内核
willhuo1 天前
程序这东西,想的即使在完善,也有想不到的地方。。
linux·服务器·网络