欢迎光临
我们一直在努力

【Linux】Linux 中 .service 文件核心介绍

【Linux】Linux 中 .service 文件核心介绍

  • 一、基本概念
    • 1.1 存放路径
    • 1.2 核心结构
    • 1.3 关键补充说明
  • 二、详细介绍
    • 2.1 [Unit] 节(通用配置)
    • 2.2 [Service] 节(服务运行核心)
    • 2.3 [Install] 节(开机自启配置)
  • 三、如何编写一个 .service 文件?
  • 四、如何使用 .service 文件?

一、基本概念

systemd 是 Linux 操作系统的系统与服务管理器,是现代 Linux 发行版(CentOS 7+、Ubuntu 16.04+、Debian 9+ 等)的默认初始化系统(init system),替代了传统的 SysVinit。

它的核心目标是并行启动系统服务、统一管理系统进程、简化服务配置与运维,提供了进程管理、日志收集(journald)、设备挂载、定时任务、套接字激活等全套系统能力。

1.1 存放路径

  • 系统级服务:/usr/lib/systemd/system/(系统安装的软件自带服务,如 nginx、mysql。 禁止手动修改 )

  • 用户自定义服务:/etc/systemd/system/(优先级更高,推荐 存放自定义 .service 文件)

  • 运行时服务:/run/systemd/system/(仅由 systemd 自动生成, 禁止手动修改 )

  • 核心作用:告诉 systemd 如何启动、停止、重启服务,以及服务的依赖关系、运行环境、日志配置等。

  • 文件格式:纯文本配置文件,采用 INI 风格,由多个节(Section) 组成,每个节包含键值对配置。

1.2 核心结构

.service 文件分为三个核心节,部分可选节:

[Unit] :描述服务的元数据、依赖关系、启动顺序、文档说明等全局配置,是服务与系统服务管理器交互的基础配置。

  • 绝大多数场景下建议保留,即使不写任何配置项,systemd 也会使用默认值;
  • 理论上可以完全省略(空段或不写),但会缺失依赖、描述等信息,不推荐。

# /etc/systemd/system/my-service.service
# 注释推荐独占一行
[Unit]
Description=我的自定义服务 # 服务描述(必写,便于管理)
After=network.target # 依赖:网络启动后再启动本服务
Wants=network-online.target # 弱依赖:有网络更好,没有也没关系,但是我更希望你存在。
Requires=network.target # 强依赖:网络服务失败则本服务也失败(一般不使用)

[Service] :定义服务的 核心运行逻辑 ,包括启动/停止/重启命令、执行用户、工作目录、重启策略、标准输出 / 错误日志等,是服务能正常运行的核心。

  • 必须存在!!!

  • 如果没有这个段,systemd 无法知道如何启动服务,会直接启动失败。

[Service]
Type=simple # 服务类型(simple 为默认,前台进程)
# 启动命令(唯一必填配置, 并且可执行程序必须指定绝对路径,不能使用相对路径,且 Exec* 后面不能跟注释)
ExecStart=/usr/bin/myapp
User=ubuntu # 运行用户
Restart=on-failure # 重启策略:进程异常退出时重启
WorkingDirectory=/opt/myapp # 工作目录

[Install] :定义服务的安装配置,核心用于配置 开机自启 、服务所属的 target(运行级别),是 systemctl enable/disable 命令的核心依赖。

  • 可选,取决于你的需求。
  • 如果你不需要开机自启:可以完全省略 [Install] 段;
  • 如果你需要开机自启:必须添加该段,且至少包含 WantedBy 或 RequiredBy 配置。

[Install]
WantedBy=multi-user.target # 多用户图形/命令行环境下开机自启

可选节 :如 [Install] 之外,还有 [Timer](配合定时器使用)、[Socket](套接字激活服务)等。

如何使用?

sudo systemctl daemon-reload # 重载配置
sudo systemctl start my-service.service # 手动启动
sudo systemctl stop my-service.service # 手动停止

# 设置开机启用并立即启动(如果没有 [Install] 段,则无法使用 enable/disable)
sudo systemctl enable –now my-service.service

# 禁止开机自启
sudo systemctl disable my-service.service

1.3 关键补充说明

  • 默认值机制

    systemd 对未配置的段 / 配置项会使用内置默认值,例如:

    • 省略 [Unit] 段:服务描述为 (unknown),依赖为默认值;
    • [Service] 段省略 Type:默认值为 simple;
    • 省略 User:默认以 root 用户运行。
  • [Install] 段的核心配置

    只有 WantedBy= 和 RequiredBy= 是核心配置,用于指定服务所属的 target,是开机自启的关键。

  • systemd 服务文件的语法规则

    • 配置项为 键=值 格式,等号两侧 不能有空格(老版系统) ;
    • 注释以 # 开头,建议注释独占一行 。Exec 开头的命令行,行尾绝对不能加注释,比如:不可以写在 ExecStart 等执行的指令后面,他会把ExecStart后面的所有值作为参数传递给服务,如果有注释就会引发报错;
    • 配置文件路径:系统服务存 /etc/systemd/system/,第三方服务建议存此目录,而非 /usr/lib/systemd/system/。
  • 注意点

    推荐 等号(=) 前后不能有空格。

    如果有注释,注释单独占一行。不要写在以 Exec 开头的指令的后面,否则会报错。

    自定义的 .service 文件放在 /etc/systemd/system 目录下。

    Exec 指令的后面必须写指令的绝对路径,不能写相对路径,否则会报错。

  • 段名强制要求核心作用适用场景
    [Unit] 推荐保留 元数据、依赖、启动顺序 所有生产环境服务
    [Service] 必须 启动命令、运行配置、重启策略 所有 systemd 服务
    [Install] 可选 开机自启、target 关联 是否需要开机自启 systemctl enable

    二、详细介绍

    2.1 [Unit] 节(通用配置)

    配置项作用示例
    Description 服务的简短描述 Description=My Custom Service
    Documentation 服务文档地址 Documentation=https://example.com/docs
    After 控制我在谁之后启动(仅控制启动顺序,不强制服务启动成功) After=network.target(网络启动后再启动本服务)
    Before 控制我在谁之前启动(仅控制启动顺序,不强制服务启动成功) Before=nginx.service
    Requires 强依赖(依赖的服务启动失败,本服务也会启动失败) Requires=network.target
    Wants 弱依赖(依赖的服务启动失败,不影响本服务启动) Wants=network-online.target
    • Description: 对服务进行简洁描述,可以使用中文,可以有空格。 推荐写上。

    • Documentation: 服务的文档地址,类似于使用说明。可以是man手册(适用于系统自带的服务), 可以是网页URL(适用于自己写的服务),也可以是本地文件路径。文档地址可以写多个,使用空格分开。 自定义的服务一般不用写这个参数。

    • After/Before: 仅控制启动顺序,不控制依赖关系。我必须要在谁之前/之后启动,但是你是否成功启动与我无关, 我只管启动的先后顺序。

    • Requires=/Wants: 仅控制 依赖关系 ,不控制启动顺序。我的启动需要有你这个服务作为依赖,分为强依赖和弱依赖。systemd 默认并行启动服务,除非你使用( Before/After )显示指定启动顺序。两者可以组合使用,形成 “先启动谁、再启动谁、谁失败会影响谁”。

    • Requires 强依赖: 依赖的服务必须存在且成功启动,否则本服务会被停止。如果你添加了强依赖,那么强依赖 必须 成功运行。这个参数一般不使用。

    • Wants 弱依赖: 依赖的服务(是否存在/是否启动成功)不影响本服务,弱依赖只是作为一个辅助参数, 锦上添花 ,有更好,没有也无妨,一点不影响本服务的启动。存在的意义:表达弱依赖关系,让 systemd 知道这个服务对我很重要,但是你启动失败了也没关系,不影响我的启动。

    以 Ubuntu 的防火墙 ufw 为例:

    # /usr/lib/systemd/system/ufw.service
    [Unit]
    # 对 ufw 服务的简洁描述
    Description=Uncomplicated firewall
    # 文档信息
    Documentation=man:ufw(8)
    # 我的服务(ufw)在该服务(local-fs)启动之后启动(仅控制启动顺序,不强制服务启动成功)
    After=local-fs.target
    # 我的服务(ufw)在该服务(network-pre)启动之前启动(仅控制启动顺序,不强制服务启动成功)
    Before=network-pre.target

    # 这个Requires是我自己加的默认没有,这里做演示
    # 表示:"ufw" 服务需要 "local-fs" 服务成功启动,本服务才能启动,是强依赖,本服务的启动强依赖于requires后面的服务。
    # 如果 "local-fs" 服务启动失败,那么"ufw" 服务也不会启动成功。(启动时无先后顺序,本服务和Requires后面跟的服务,并行启动。强调requires后跟的服务是否成功。如果成功,则本服务可能成功,也可能失败,如果失败,则本服务,也启动失败)
    # Requires=local-fs.target

    # 与requires 差不多,这是弱依赖。我需要这两个目标(多个目标用空格分开)达成,但不强求必须成功。即使这两个都是失败了,也不影响我启动。
    # 你有更好,没有也无所谓,也不影响我启动。
    Wants=network-pre.target local-fs.target

    # 是否关掉 systemd 默认给你加的一堆依赖?
    # 这个是系统更底层的基础服务。有的系统服务需要添加这个
    # 个人自己写的服务一定不要加这个,否则可能会启动失败
    DefaultDependencies=no

    2.2 [Service] 节(服务运行核心)

    定义服务的执行方式,包括启动/停止/重启命令、执行用户、工作目录、重启策略、标准输出 / 错误日志等,是服务能正常运行的核心。必须一个服务要想启动必须要有 [Service] 。

    配置项作用示例
    Type 服务类型,决定 systemd 如何判断服务启动成功 – simple(默认):主进程是前台进程,启动后不退出- forking:进程会 fork 子进程,父进程退出,适合守护进程- oneshot:一次性执行(执行完就退出)
    User / Group 服务运行的用户 / 组 User=www-data、Group=www-data
    WorkingDirectory 服务的工作目录 WorkingDirectory=/opt/myapp
    Environment 环境变量 Environment=PATH=/usr/local/bin:/usr/bin
    ExecStart 必须配置:服务启动的命令(绝对路径) ExecStart=/usr/bin/python3 /opt/myapp/app.py
    ExecStop 服务停止时执行的命令 ExecStop=/usr/bin/kill -9 $MAINPID
    ExecReload 服务重启 / 重载时执行的命令 ExecReload=/bin/kill -HUP $MAINPID
    Restart 重启策略(推荐生产环境配置) – no(默认,不重启)- on-failure(异常退出时重启)- always(任何退出都重启)
    RestartSec 重启间隔(秒) RestartSec=5
    StandardOutput/StandardError 日志输出配置 StandardOutput=journal+console(输出到系统日志 + 控制台)

    # /usr/lib/systemd/system/ufw.service
    [Service]
    # 服务只需要执行一次,执行完 → 进程退出 → 服务状态变成 inactive (dead)
    Type=oneshot
    # 与Type=oneshot 组合使用
    RemainAfterExit=yes

    # 服务启动时,执行的指令
    ExecStart=/usr/lib/ufw/ufw-init start quiet

    # 服务关闭时执行的指令(一般不用写)
    ExecStop=/usr/lib/ufw/ufw-init stop

    Type 参数介绍:

    Type类型特点进程状态适用于
    Type=simple 启动后一直运行(如果不写,默认就是simple) 常驻内存 自定义服务一般都是这个。 或者你不写,使用默认值。
    Type=oneshot 跑一次就退出。执行完 → 进程退出 → 服务状态变成 inactive (dead) 执行完就死 初始化脚本、或者一次性脚本/任务
    Type=forking 程序启动后会自己创建子进程,然后父进程会自己退出,子进程再后台运行。 常驻内存 Nginx、MySQL、Apache、 传统老服务

    RemainAfterExit 参数介绍:

    RemainAfterExit=yes 表示:就算进程退出了,systemd 也认为服务是成功的,不会把它标记为失败。一般是执行一次性任务,与 Type=oneshot 组合使用,只要你的服务是一次性任务,执行完就退出,就用它。

    User / Group 参数介绍:

    用来给服务设置权限,保证安全!就是当服务启动时,以哪个用户的身份运行这个服务,启动后该服务是谁(User)在运行?所属哪个组(Group)?如果不写,默认都是 root 用户,权限过大,不安全,生产环境中禁止!!一般自己写的服务就写当前使用的用户名(普通用户)就行,不推荐使用 root 。比如:当前用户是:zzq,以用户 zzq 的身份运行这个服务,你可以写:

    User=zzq
    Group=zzq

    另外,由于每个用户都默认属于一个同名的主组,所以你可以只写一个 User ,systemd 会自动把 Group 设成和 User 一样。

    WorkingDirectory 参数介绍:

    服务的当前工作目录。服务启动前先 cd 进去的目录,所有相对路径,都是相对于它!如果不写,默认是根目录 / 。

    比如:使用 Java 运行 myapp.jar 这个 jar 包,这个jar 包会产生日志文件,日志文件存放的根路径就是你定义的 WorkingDirectory 路径。所有文件都是相对于这个路径存放,如果没设置,那么日志文件就会由 root 用户在根路径创建。

    通常 myapp.jar 需要文件的绝对路径 /home/ubuntu/myapp.jar :

    ExecStart=/usr/bin/java -jar /home/ubuntu/myapp.jar

    配置了 WorkingDirectory 可以将 /home/ubuntu 目录省略,直接使用相对路径,更简洁明了:

    WorkingDirectory=/home/ubuntu
    ExecStart=/usr/bin/java -jar myapp.jar

    Environment 参数介绍:

    就是给程序设置环境变量。

    比如,在终端执行:

    java -jar myapp.jar –server.port=8888

    写入服务,设置环境变量:

    Environment="SERVER_PORT=8888"
    ExecStart=/usr/bin/java -jar myapp.jar –server.port=${SERVER_PORT}

    ExecStart 参数介绍:

    服务启动的指令, 必须配置 ,当你执行 sudo systemctl start ufw 时,systemd 就会跑这一行 ExecStart=/usr/lib/ufw/ufw-init start quiet 。表示的是:启动 ufw 防火墙的脚本,并且安静启动(不输出多余日志),这个更偏向底层,比较复杂,我们换一个简单点的指令进行介绍:

    ExecStart=/usr/bin/java -jar /home/ubuntu/myapp.jar

    这个指令表示:在服务启动时,使用 java 运行一个叫 myapp.jar 的 jar 包。

    注意:

    • ExecStart 后面跟的程序的指令( java )必须是绝对路径,不能是相对路径。 文件的指令可以是相对路径(前提是必须存在 WorkingDirectory )。
    • java 程序的路径: /usr/bin/java (绝对路径), 参数: -jar ,启动的 jar 包: /home/ubuntu/myapp.jar (绝对路径)。
    • Exec* 后面不能跟注释,否则会报错。在运行指令时,systemd 会把 ExecStart 后面的所有内容当作指令传给可执行程序,注释可能会被当成参数传递,可执行程序检测到不是正确的参数就会报错。

    ExecStop 参数介绍:

    服务关闭时,要执行的命令。与 ExecStart 类似。ExecStop 通常是给 Type=oneshot 脚本服务使用,常驻服务 Type=simple 不需要写。

    ExecReload 参数介绍:

    服务重载配置时执行的命令。适用于支持热重载配置的服务(指:不重启、只重新加载配置的服务),不支持就不写 ExecReload 参数,自定义的服务一般不写。比如:nginx 支持热重载配置(nginx -s reload)在 /usr/lib/systemd/system/nginx.service 中就有 ExecReload , 我们平时写的 Java 程序不支持也不需要写 ExecReload。

    Restart 参数介绍:

    配置重启策略(推荐生产环境配置)。systemd 会根据 Restart= 的值,决定要不要重启。

    参数值作用说明适用场景
    Restart=no 默认值,服务退出 / 崩溃后,不自动重启 一次性脚本、临时任务
    Restart=on-failure 服务非正常退出(崩溃、报错、被强制终止、非 0 退出码)时重启 Java 应用、FRP、Nginx、数据库服务
    Restart=always 无论服务是正常退出、崩溃还是被终止,永远自动重启 核心业务服务、必须常驻的进程
    以下两个不常用:
    Restart=on-success 仅服务正常退出(退出码 0)时重启,失败则不重启 极少使用,适配特殊成功退出场景
    Restart=on-abnormal 仅非正常退出时重启,与on-failure功能基本一致(部分系统下无区别) 通用服务,替代on-failure

    RestartSec 参数介绍:

    与 Restart 搭配使用,服务异常退出后,延迟重启的时间(单位:秒),避免疯狂重启占用资源。RestartSec=3 表示:服务退出后,3秒后重启。

    StandardOutput/StandardError 参数介绍:

    这两个参数是 systemd 服务配置 中,用于控制服务 标准输出(stdout) 和 标准错误输出(stderr) 重定向方式的核心配置,决定了服务的日志如何存储、如何查看。

    参数作用取值说明
    StandardOutput 控制标准输出(程序正常打印的日志)的输出方式 journal(默认) 日志写入 systemd 日志,可通过 journalctl 查看
    journal+console 同时写入日志 + 输出到控制台(仅调试场景)
    null 丢弃所有标准输出,不记录日志
    绝对路径(如 /var/log/app.log) 输出日志到指定文件
    StandardError 控制标准错误输出(程序报错、异常信息)的输出方式 取值与 StandardOutput 完全一致 单独配置错误日志的输出路径 / 方式

    如果不写,默认是 journal ,使用以下指令查看日志:

    journalctl -u myapp.service -f

    • -u myapp.service :unit,筛选服务,只看这个服务。
    • -f : follow 实时追踪,实时刷新(跟着输出)。

    写绝对路径,输出 / 错误分别写入不同文件:

    [Service]
    ExecStart=/home/ubuntu/myapp.jar
    StandardOutput=/var/log/myapp/output.log
    StandardError=/var/log/myapp/error.log

    2.3 [Install] 节(开机自启配置)

    用于配置服务的安装和启用规则,执行 systemctl enable 时生效。如果你想配置开机自启,就加这个 [Install] 。

    配置项作用示例
    WantedBy 定义服务在哪个目标(target)下启用,最常用 WantedBy=multi-user.target(多用户命令行环境,服务器通用)
    RequiredBy 强依赖的目标 RequiredBy=graphical.target

    # /usr/lib/systemd/system/ufw.service
    [Install]
    # 多用户命令行环境,大部分情况下都选这个
    WantedBy=multi-user.target

    • WantedBy = 弱依赖安装(推荐 99% 场景)。当系统进入多用户模式(Linux 默认就是多用户模式)时,顺便启动我的服务,我挂了不影响系统。

    • RequiredBy = 强依赖安装(几乎不用)。系统必须等我服务启动成功,才能进入多用户模式,我挂了系统起不来!!

    • 它们只在你执行 systemctl enable 时生效。

    三、如何编写一个 .service 文件?

    以 java 程序为例,如何以服务的方式运行 myapp.jar 程序?

    创建一个 service 文件 myapp.service:

    sudo vim /etc/systemd/system/myapp.service

    写入配置文件:

    [Unit]
    # 服务描述
    Description=我的 java 程序服务 myapp.service
    # 依赖网络启动后再启动本服务(本地测试,无需连接外网)
    After=network.target
    # 弱依赖网络就绪
    Wants=network-online.target

    [Service]
    # 服务类型(有默认值,可以不写)
    Type=simple
    # 运行该服务的用户(修改为你自己的用户名)
    User=ubuntu
    # 工作目录
    WorkingDirectory=/home/ubuntu
    # 设置环境变量(例如:JVM参数、应用程序端口(8081端口)等)
    Environment="JAVA_OPTS=-Xms512m -Xmx1024m"
    Environment="SERVER_PORT=8081"
    # 启动命令——绝对路径(修改为你自己的 jar 包名字)
    ExecStart=/usr/bin/java ${JAVA_OPTS} -jar myapp.jar –server.port=${SERVER_PORT}
    # 停止命令:优雅地终止进程
    ExecStop=/usr/bin/kill -TERM $MAINPID
    # 异常退出时自动重启
    Restart=on-failure
    # 重启间隔3秒
    RestartSec=3
    # 日志输出到系统日志(有默认值,可不写)
    StandardOutput=journal
    StandardError=journal

    [Install]
    # 多用户环境下启用(不需要开机自启,则移除此项)
    WantedBy=multi-user.target

    网络补充:

    • network.target :网络初始化完成,网卡亮了,但 IP 还没拿到,不能上网!相当于自己windows 电脑没有网络,但是可以使用mysql, http:localhost:8080 等。
    • network-online.target :网络真正准备好了(IP 拿到、DNS 正常、能上网)。相当于自己windows电脑连接了网络,可以使用远程服务器上的 OSS 对象存储,MySQL 数控库等。 适用于生产环境 。
    • 使用那一个? 如果仅仅使用本地的网络服务,就使用 network.target , 如果需要连外部服务(OSS, Redis, MQ, MySQL等)使用 network-online.target 。

    省略非必要参数,最基础的启动 java 程序服务:

    [Service]
    ExecStart=/usr/bin/java -jar /home/ubuntu/myapp.jar

    四、如何使用 .service 文件?

    修改 / 新增 .service 文件后,必须重载 systemd 配置,让系统识别新服务:

    sudo systemctl daemon-reload

    启动服务:

    # sudo systemctl start myapp.service
    # 可以简写为myapp(省略 .service)
    sudo systemctl start myapp

    查看服务状态:

    sudo systemctl status myapp

    设置开机自启(service 文件中必须有[Install]):

    sudo systemctl enable myapp

    禁止开机自启:

    sudo systemctl disable myapp

    停止服务:

    sudo systemctl stop myapp

    重启服务:

    sudo systemctl restart myapp

    查看服务日志:

    # 查看当前服务日志
    sudo journalctl -u myapp
    # 实时跟踪日志(类似 tail -f)
    sudo journalctl -u myapp -f
    # 查看最近10分钟的日志
    sudo journalctl -u myapp –since "10 minutes ago"


    End

    你好,少年,未来可期~

    赞(0)
    未经允许不得转载:171主机测评 » 【Linux】Linux 中 .service 文件核心介绍
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址