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

【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我的自定义服务# 服务描述必写便于管理Afternetwork.target# 依赖网络启动后再启动本服务Wantsnetwork-online.target# 弱依赖有网络更好没有也没关系但是我更希望你存在。Requiresnetwork.target# 强依赖网络服务失败则本服务也失败一般不使用[Service]定义服务的核心运行逻辑包括启动/停止/重启命令、执行用户、工作目录、重启策略、标准输出 / 错误日志等是服务能正常运行的核心。必须存在如果没有这个段systemd 无法知道如何启动服务会直接启动失败。[Service]Typesimple# 服务类型simple 为默认前台进程# 启动命令唯一必填配置, 并且可执行程序必须指定绝对路径不能使用相对路径且 Exec* 后面不能跟注释ExecStart/usr/bin/myappUserubuntu# 运行用户Restarton-failure# 重启策略进程异常退出时重启WorkingDirectory/opt/myapp# 工作目录[Install]定义服务的安装配置核心用于配置开机自启、服务所属的 target运行级别是systemctl enable/disable命令的核心依赖。可选取决于你的需求。如果你不需要开机自启可以完全省略[Install]段如果你需要开机自启必须添加该段且至少包含WantedBy或RequiredBy配置。[Install]WantedBymulti-user.target# 多用户图形/命令行环境下开机自启可选节如[Install]之外还有[Timer]配合定时器使用、[Socket]套接字激活服务等。如何使用sudosystemctl daemon-reload# 重载配置sudosystemctl start my-service.service# 手动启动sudosystemctl stop my-service.service# 手动停止# 设置开机启用并立即启动如果没有 [Install] 段则无法使用 enable/disablesudosystemctlenable--nowmy-service.service# 禁止开机自启sudosystemctl disable my-service.service1.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服务的简短描述DescriptionMy Custom ServiceDocumentation服务文档地址Documentationhttps://example.com/docsAfter控制我在谁之后启动仅控制启动顺序不强制服务启动成功Afternetwork.target网络启动后再启动本服务Before控制我在谁之前启动仅控制启动顺序不强制服务启动成功Beforenginx.serviceRequires强依赖依赖的服务启动失败本服务也会启动失败Requiresnetwork.targetWants弱依赖依赖的服务启动失败不影响本服务启动Wantsnetwork-online.targetDescription对服务进行简洁描述可以使用中文可以有空格。推荐写上。Documentation服务的文档地址类似于使用说明。可以是man手册适用于系统自带的服务, 可以是网页URL(适用于自己写的服务)也可以是本地文件路径。文档地址可以写多个使用空格分开。自定义的服务一般不用写这个参数。After/Before仅控制启动顺序不控制依赖关系。我必须要在谁之前/之后启动但是你是否成功启动与我无关我只管启动的先后顺序。Requires/Wants仅控制依赖关系不控制启动顺序。我的启动需要有你这个服务作为依赖分为强依赖和弱依赖。systemd 默认并行启动服务除非你使用Before/After显示指定启动顺序。两者可以组合使用形成 “先启动谁、再启动谁、谁失败会影响谁”。Requires 强依赖依赖的服务必须存在且成功启动否则本服务会被停止。如果你添加了强依赖那么强依赖必须成功运行。这个参数一般不使用。Wants 弱依赖依赖的服务是否存在/是否启动成功不影响本服务弱依赖只是作为一个辅助参数锦上添花有更好没有也无妨一点不影响本服务的启动。存在的意义表达弱依赖关系让 systemd 知道这个服务对我很重要但是你启动失败了也没关系不影响我的启动。以Ubuntu的防火墙ufw为例# /usr/lib/systemd/system/ufw.service[Unit]# 对 ufw 服务的简洁描述DescriptionUncomplicated firewall# 文档信息Documentationman:ufw(8)# 我的服务ufw在该服务local-fs启动之后启动仅控制启动顺序不强制服务启动成功Afterlocal-fs.target# 我的服务ufw在该服务network-pre启动之前启动仅控制启动顺序不强制服务启动成功Beforenetwork-pre.target# 这个Requires是我自己加的默认没有这里做演示# 表示ufw 服务需要 local-fs 服务成功启动本服务才能启动是强依赖本服务的启动强依赖于requires后面的服务。# 如果 local-fs 服务启动失败那么ufw 服务也不会启动成功。(启动时无先后顺序本服务和Requires后面跟的服务并行启动。强调requires后跟的服务是否成功。如果成功则本服务可能成功也可能失败如果失败则本服务也启动失败)# Requireslocal-fs.target# 与requires 差不多这是弱依赖。我需要这两个目标多个目标用空格分开达成但不强求必须成功。即使这两个都是失败了也不影响我启动。# 你有更好没有也无所谓也不影响我启动。Wantsnetwork-pre.target local-fs.target# 是否关掉 systemd 默认给你加的一堆依赖# 这个是系统更底层的基础服务。有的系统服务需要添加这个# 个人自己写的服务一定不要加这个否则可能会启动失败DefaultDependenciesno2.2 [Service] 节服务运行核心定义服务的执行方式包括启动/停止/重启命令、执行用户、工作目录、重启策略、标准输出 / 错误日志等是服务能正常运行的核心。必须一个服务要想启动必须要有[Service]。配置项作用示例Type服务类型决定 systemd 如何判断服务启动成功-simple默认主进程是前台进程启动后不退出-forking进程会 fork 子进程父进程退出适合守护进程-oneshot一次性执行执行完就退出User / Group服务运行的用户 / 组Userwww-data、Groupwww-dataWorkingDirectory服务的工作目录WorkingDirectory/opt/myappEnvironment环境变量EnvironmentPATH/usr/local/bin:/usr/binExecStart必须配置服务启动的命令绝对路径ExecStart/usr/bin/python3 /opt/myapp/app.pyExecStop服务停止时执行的命令ExecStop/usr/bin/kill -9 $MAINPIDExecReload服务重启 / 重载时执行的命令ExecReload/bin/kill -HUP $MAINPIDRestart重启策略推荐生产环境配置-no默认不重启-on-failure异常退出时重启-always任何退出都重启RestartSec重启间隔秒RestartSec5StandardOutput/StandardError日志输出配置StandardOutputjournalconsole输出到系统日志 控制台# /usr/lib/systemd/system/ufw.service[Service]# 服务只需要执行一次执行完 → 进程退出 → 服务状态变成 inactive (dead)Typeoneshot# 与Typeoneshot 组合使用RemainAfterExityes# 服务启动时执行的指令ExecStart/usr/lib/ufw/ufw-init start quiet# 服务关闭时执行的指令一般不用写ExecStop/usr/lib/ufw/ufw-init stopType 参数介绍Type类型特点进程状态适用于Typesimple启动后一直运行如果不写默认就是simple常驻内存自定义服务一般都是这个。或者你不写使用默认值。Typeoneshot跑一次就退出。执行完 → 进程退出 → 服务状态变成 inactive (dead)执行完就死初始化脚本、或者一次性脚本/任务Typeforking程序启动后会自己创建子进程然后父进程会自己退出子进程再后台运行。常驻内存Nginx、MySQL、Apache、传统老服务RemainAfterExit 参数介绍RemainAfterExityes表示就算进程退出了systemd 也认为服务是成功的不会把它标记为失败。一般是执行一次性任务与Typeoneshot组合使用只要你的服务是一次性任务执行完就退出就用它。User / Group 参数介绍用来给服务设置权限保证安全就是当服务启动时以哪个用户的身份运行这个服务启动后该服务是谁User在运行所属哪个组Group如果不写默认都是root用户权限过大不安全生产环境中禁止一般自己写的服务就写当前使用的用户名普通用户就行不推荐使用root。比如当前用户是zzq以用户 zzq 的身份运行这个服务你可以写UserzzqGroupzzq另外由于每个用户都默认属于一个同名的主组所以你可以只写一个Usersystemd 会自动把 Group 设成和 User 一样。WorkingDirectory 参数介绍服务的当前工作目录。服务启动前先 cd 进去的目录所有相对路径都是相对于它如果不写默认是根目录/。比如使用 Java 运行myapp.jar这个 jar 包这个jar 包会产生日志文件日志文件存放的根路径就是你定义的WorkingDirectory路径。所有文件都是相对于这个路径存放如果没设置那么日志文件就会由 root 用户在根路径创建。通常myapp.jar需要文件的绝对路径/home/ubuntu/myapp.jarExecStart/usr/bin/java-jar/home/ubuntu/myapp.jar配置了WorkingDirectory可以将/home/ubuntu目录省略直接使用相对路径更简洁明了WorkingDirectory/home/ubuntuExecStart/usr/bin/java-jarmyapp.jarEnvironment 参数介绍就是给程序设置环境变量。比如在终端执行java-jarmyapp.jar--server.port8888写入服务设置环境变量EnvironmentSERVER_PORT8888ExecStart/usr/bin/java-jarmyapp.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 通常是给Typeoneshot脚本服务使用常驻服务Typesimple不需要写。ExecReload 参数介绍服务重载配置时执行的命令。适用于支持热重载配置的服务指不重启、只重新加载配置的服务不支持就不写ExecReload参数自定义的服务一般不写。比如nginx 支持热重载配置nginx -s reload在/usr/lib/systemd/system/nginx.service中就有 ExecReload , 我们平时写的 Java 程序不支持也不需要写 ExecReload。Restart 参数介绍配置重启策略推荐生产环境配置。systemd 会根据Restart的值决定要不要重启。参数值作用说明适用场景Restartno默认值服务退出 / 崩溃后不自动重启一次性脚本、临时任务Restarton-failure服务非正常退出崩溃、报错、被强制终止、非 0 退出码时重启Java 应用、FRP、Nginx、数据库服务Restartalways无论服务是正常退出、崩溃还是被终止永远自动重启核心业务服务、必须常驻的进程以下两个不常用Restarton-success仅服务正常退出退出码 0时重启失败则不重启极少使用适配特殊成功退出场景Restarton-abnormal仅非正常退出时重启与on-failure功能基本一致部分系统下无区别通用服务替代on-failureRestartSec 参数介绍与Restart搭配使用服务异常退出后延迟重启的时间单位秒避免疯狂重启占用资源。RestartSec3表示服务退出后3秒后重启。StandardOutput/StandardError 参数介绍这两个参数是systemd 服务配置中用于控制服务标准输出stdout和标准错误输出stderr重定向方式的核心配置决定了服务的日志如何存储、如何查看。参数作用取值说明StandardOutput控制标准输出程序正常打印的日志的输出方式journal默认日志写入 systemd 日志可通过journalctl查看journalconsole同时写入日志 输出到控制台仅调试场景null丢弃所有标准输出不记录日志绝对路径如/var/log/app.log输出日志到指定文件StandardError控制标准错误输出程序报错、异常信息的输出方式取值与StandardOutput完全一致单独配置错误日志的输出路径 / 方式如果不写默认是journal使用以下指令查看日志journalctl-umyapp.service-f-u myapp.serviceunit筛选服务只看这个服务。-f follow 实时追踪实时刷新跟着输出。写绝对路径输出 / 错误分别写入不同文件[Service]ExecStart/home/ubuntu/myapp.jarStandardOutput/var/log/myapp/output.logStandardError/var/log/myapp/error.log2.3 [Install] 节开机自启配置用于配置服务的安装和启用规则执行systemctl enable时生效。如果你想配置开机自启就加这个[Install]。配置项作用示例WantedBy定义服务在哪个目标target下启用最常用WantedBymulti-user.target多用户命令行环境服务器通用RequiredBy强依赖的目标RequiredBygraphical.target# /usr/lib/systemd/system/ufw.service[Install]# 多用户命令行环境大部分情况下都选这个WantedBymulti-user.targetWantedBy 弱依赖安装推荐 99% 场景。当系统进入多用户模式Linux 默认就是多用户模式时顺便启动我的服务我挂了不影响系统。RequiredBy 强依赖安装几乎不用。系统必须等我服务启动成功才能进入多用户模式我挂了系统起不来它们只在你执行systemctl enable时生效。三、如何编写一个 .service 文件以 java 程序为例如何以服务的方式运行myapp.jar程序创建一个 service 文件myapp.servicesudovim/etc/systemd/system/myapp.service写入配置文件[Unit]# 服务描述Description我的java程序服务 myapp.service# 依赖网络启动后再启动本服务(本地测试无需连接外网)Afternetwork.target# 弱依赖网络就绪Wantsnetwork-online.target[Service]# 服务类型有默认值可以不写Typesimple# 运行该服务的用户修改为你自己的用户名Userubuntu# 工作目录WorkingDirectory/home/ubuntu# 设置环境变量例如JVM参数、应用程序端口(8081端口)等EnvironmentJAVA_OPTS-Xms512m -Xmx1024mEnvironmentSERVER_PORT8081# 启动命令——绝对路径修改为你自己的 jar 包名字ExecStart/usr/bin/java${JAVA_OPTS}-jarmyapp.jar--server.port${SERVER_PORT}# 停止命令优雅地终止进程ExecStop/usr/bin/kill-TERM$MAINPID# 异常退出时自动重启Restarton-failure# 重启间隔3秒RestartSec3# 日志输出到系统日志有默认值可不写StandardOutputjournalStandardErrorjournal[Install]# 多用户环境下启用不需要开机自启则移除此项WantedBymulti-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 配置让系统识别新服务sudosystemctl daemon-reload启动服务# sudo systemctl start myapp.service# 可以简写为myapp省略 .servicesudosystemctl start myapp查看服务状态sudosystemctl status myapp设置开机自启service 文件中必须有[Install]sudosystemctlenablemyapp禁止开机自启sudosystemctl disable myapp停止服务sudosystemctl stop myapp重启服务sudosystemctl restart myapp查看服务日志# 查看当前服务日志sudojournalctl-umyapp# 实时跟踪日志类似 tail -fsudojournalctl-umyapp-f# 查看最近10分钟的日志sudojournalctl-umyapp--since10 minutes agoEnd你好少年未来可期~