Linux systemd

systemd 是一种用于 Linux 操作系统的系统和服务管理器。它被广泛应用于许多现代 Linux 发行版中,如 CentOS、Fedora、Ubuntu 等。systemd 旨在替代传统的 SysVLSB init 系统,并提供更强大、灵活的系统启动和服务管理功能。

systemd 的关键概念和组件

  • Unit 文件

    • systemd 使用单元(Unit)文件来描述系统资源。常见的单元类型包括:
      • Service Unit (*.service) : 用于定义和管理服务。
      • Target Unit (*.target) : 用于分组和同步一组单元的启动,如 multi-user.target
      • Timer Unit (*.timer) : 用于定时任务,相当于 cron 的替代品。
      • Socket Unit (*.socket) :用于管理网络或 IPC 套接字。
      • Mount Unit (*.mount) : 用于定义挂载点。
      • Path Unit (*.path) : 监控文件或者目录的变化。当监控的文件或目录发生变化时,可以触发相应的 service 单元。
    • 单元(Unit)文件通常存储在以下目录
      • /etc/systemd/system/ :系统管理员定义的单位文件,优先级较高。
      • /lib/systemd/system/ :发行版提供的单位文件,优先级较低。
      • /run/systemd/system/ :运行时生成的单位文件,临时的。
  • Target 文件

    • systemd 使用 target 取代传统的运行级别(runlevel)。常见的目标包括:
      • multi-user.target : 相当于传统的运行级别 3,支持多用户、无图形界面。
      • graphical.target : 相当于传统的运行级别 5,支持多用户和图形界面。
      • rescue.target : 相当于传统的单用户模式,提供基本的系统恢复环境。
  • 日志管理

    • systemd 使用 `journald` 来管理系统日志。你可以使用 journalctl 命令查看日志
  • 服务间的依赖关系

    • systemd 处理服务间的依赖关系。你可以通过 After=Before=Requires= 等指令在单元文件中定义这些依赖。

systemd 的优势:

  • 并行启动systemd 可以并行启动服务,减少启动时间。
  • 依赖管理 : 能够自动处理服务间的依赖关系,保证系统按需启动服务。
  • 日志记录systemd 的日志管理功能强大,提供了统一的接口查看和分析日志。
  • 定时任务管理 : 通过 timer 单元文件可以灵活地配置定时任务,作为 cron 的替代方案。
  • 性能统计数据systemd 启动过程中记录了性能(如服务启动时间)相关的统计数据,可以使用命令 systemd-analyze 查看。

systemd unit 配置文件

service unit 配置文件说明

systemdservice 单元文件用于定义和管理系统中的服务。每个 service 单元文件描述了一个服务的启动、停止、重启等操作。以下是 systemd service 单元文件的各个部分和常见选项的详细说明。

一个典型的 service 单元文件的结构包含三个部分

  • [Unit]
  • [Service]
  • [Install]
  1. [Unit] 部分包含有关单元的 通用信息,例如描述、依赖关系等

    • Description= :对该单元的简短描述。例如:
      Description=My Custom Service
    • Documentation= : 指定与该服务相关的文档的 URL。例如:
      Documentation=https://www.example.com/docs

    • After= :指定该单元启动时需要在其他单元启动后执行。例如:
      After=network.target

    • Requires= :指定该单元启动时需要的其他单元。如果这些单元未能启动,则本单元也会失败。
      Requires=network.target
    • Wants= :类似于 Requires,但不要求依赖的单元必须启动成功。例如:
      Wants=network.target
    • Conflicts= : 指定与该单元有冲突的单元。如果这些单元启动,则当前单元必须停止。例如:
      Conflicts=another.service
  2. [Service] 部分定义了服务的行为和启动方式

    • Type= : 指定服务的启动类型。常见值包括:

      • simple(默认) : 启动进程,ExecStart 进程保持在前台。
      • forkingExecStart 进程会派生一个子进程,然后父进程退出。
      • oneshot : 适用于一次性任务,执行完 ExecStart 后就退出。
      • notify : 服务启动后会通知 systemd,适用于需要通知机制的服务。
      • idleExecStart 进程在其他任务执行完后才开始。
        例如:
        Type=simple
    • WorkingDirectory= : 指定程序运行时的工作目录
      WorkingDirectory=/opt/project/

    • ExecStart= : 指定服务启动时执行的命令。必须指定 完整路径。例如:

      ExecStart=/usr/bin/my-service -arg1 parameter1 -arg2 parameter
    • ExecStop= : 指定服务停止时执行的命令。例如:

      ExecStop=/usr/bin/my-service-stop
    • ExecReload= : 指定服务重新加载配置时执行的命令。例如:

      ExecReload=/usr/bin/my-service-reload

    • User= : 指定服务以哪个用户的身份运行。例如:

      User=myuser
    • Group= :指定服务以哪个组的身份运行。例如

      Group=mygroup
    • Restart= : 指定服务何时自动重启。常见值包括:

      • no : 不重启(默认)。
      • on-failure : 如果进程以非零状态码退出,则重启。
      • always : 无论服务如何退出,都会重启。
      • on-abnormal : 仅在非正常退出(如信号)时重启。
        Restart=on-failure
    • RestartSec= : 指定重启前的等待时间(以秒为单位)。例如:

      RestartSec=5
    • Environment= :设置环境变量。例如:

      Environment="MY_VAR=my_value"
  3. [Install] 部分定义该服务的安装行为,即在 systemctl enable 时的行为。

    • WantedBy= :指定该服务所关联的目标(Target)。如果要让服务在多用户模式下启动,可以设置为 multi-user.target
      WantedBy=multi-user.target
    • RequiredBy= : 指定哪些目标必须依赖此服务。一般用在其他单元文件中。
    • Alias= : 为该单元创建别名。

systemd 使用案例

使用 systemd 的 Path Unit 监控文件和目录的变化

systemd 中,你可以使用 Path Unit (*.path) 来监控文件和目录的变化。当监控的文件或目录发生变化时,可以触发相应的 service 单元。

注意: 只能监控指定目录本身属性的变化以及此目录下面的文件内容的变化,不支持递归监控

如果目录结构较为简单,可以将所有的目录都写入 .path 配置中实现简单的递归监控,如下示例可监控多个目录:

[Unit]
Description=Monitor Python Project ops for changes

[Path]
PathModified=/path/to/file_or_directory1
PathModified=/path/to/file_or_directory1/sub_dir1
PathModified=/path/to/file_or_directory1/sub_dir2
PathModified=/path/to/file_or_directory1/sub_dir1/dir

Unit=sync-to-server.service

[Install]
WantedBy=multi-user.target

一个 Path Unit (*.path) 的基本结构如下:

[Unit]
Description=Monitor a file or directory

[Path]
PathExists=/path/to/file_or_directory # 监控文件或目录的路径
PathChanged=/path/to/file_or_directory # 当文件或目录内容变化时触发
PathModified=/path/to/file_or_directory # 当文件或目录属性修改时触发
DirectoryNotEmpty=/path/to/directory # 当目录非空时触发
MakeDirectory=true # 在启动时确保目录存在

[Install]
WantedBy=multi-user.target

假设你要监控 /etc/myconfig/ 目录,当其中的任何文件发生变化时,触发一个重新加载配置的服务。以下步骤演示如何配置 systemd

  1. 创建 path 单元文件,如 /etc/systemd/system/myconfig.path

    /etc/systemd/system/myconfig.path
    [Unit]
    Description=Monitor /etc/myconfig/ for changes

    [Path]
    PathModified=/etc/myconfig/

    [Install]
    WantedBy=multi-user.target

    在这个示例中,PathModified 指定了要监控的目录 /etc/myconfig/,当该目录中任何文件的内容或属性发生变化时,将触发对应的服务。

  2. 创建对应的 service 单元文件 /etc/systemd/system/myconfig.service

    /etc/systemd/system/myconfig.service
    [Unit]
    Description=Reload My Config

    [Service]
    ExecStart=/usr/bin/myconfig-reload.sh # 执行脚本或命令以处理变化

    [Install]
    WantedBy=multi-user.target

    在这个例子中,ExecStart 指定了当监控的目录变化时要执行的脚本 /usr/bin/myconfig-reload.sh

  3. 启用并启动 path 单元

    sudo systemctl daemon-reload
    sudo systemctl enable myconfig.path
    sudo systemctl start myconfig.path

    这将启用并启动 myconfig.pathsystemd 将开始监控 /etc/myconfig/ 目录的变化。

使用 systemd 启动 Django 项目

可以参考以下内容创建一个 Systemd 服务文件:

/etc/systemd/system/my_project.service
[Unit]
Description=My Project Service
After=network.target

[Service]
# 指定工作目录
WorkingDirectory=/opt/ops

# 使用 bash 启动服务来加载虚拟环境
ExecStart=/bin/bash -c "source /opt/ops/bin/activate && python3 manage.py runserver 0.0.0.0:80"

# 环境变量 (可选)
Environment="PYTHONUNBUFFERED=1"

# 允许服务重启
Restart=always

# 指定用户和组 (确保其有权限访问 /opt/ops)
User=your_user
Group=your_group

[Install]
WantedBy=multi-user.target

如果使用了 Python3 虚拟环境,需要使用 bash 命令启动程序 /bin/bash -c "source /opt/ops/bin/activate && python3 manage.py runserver 0.0.0.0:80"