0

0

Linux如何创建自定义systemd服务

P粉602998670

P粉602998670

发布时间:2025-09-05 13:51:02

|

540人浏览过

|

来源于php中文网

原创

答案是编写.service文件并配置重启策略、日志管理、依赖关系和权限隔离。首先创建包含[Unit]、[Service]、[Install]三部分的service文件,设置Type、ExecStart、User、Restart等关键参数;接着将文件放入/etc/systemd/system/目录,执行daemon-reload加载配置;然后通过enable设置开机自启,start启动服务;最后用status和journalctl排查问题。相比传统脚本,systemd具备并行启动、依赖管理、集中日志、资源控制和自动重启等优势,通过合理配置可确保服务稳定可靠运行。

linux如何创建自定义systemd服务

在Linux系统上创建自定义systemd服务,本质上就是编写一个

.service
单元文件,来告诉systemd如何启动、停止和管理你的应用程序或脚本。这就像是给你的程序一个“身份卡”和一套“行为准则”,让操作系统能以统一且高效的方式来照看它。完成这个文件后,将其放置在systemd能找到的目录中,然后通过几个简单的命令就能让你的服务跑起来,并且在系统启动时自动运行。

解决方案

创建自定义systemd服务通常涉及以下几个核心步骤。我个人觉得,理解每一步背后的逻辑比单纯记住命令更重要,因为这能帮助你在遇到问题时快速定位。

第一步:编写你的服务单元文件

这是最关键的一步。你需要创建一个以

.service
为后缀的文件,比如
my-app.service
。这个文件通常放在
/etc/systemd/system/
目录下。选择这个目录是因为它用于存放系统管理员自定义的单元文件,优先级高于系统默认的单元文件,也方便管理。

一个典型的

.service
文件会包含三个主要部分:
[Unit]
[Service]
[Install]

# /etc/systemd/system/my-app.service

[Unit]
Description=我的自定义应用程序服务
# 这个服务在网络准备好之后才启动,对于需要网络的应用很重要。
# 如果你的应用不需要网络,可以省略或改为其他依赖。
After=network.target

[Service]
# Type=simple 表示ExecStart定义的命令就是主进程。
# 如果你的程序会fork出子进程然后主进程退出,可能需要Type=forking。
Type=simple
# 定义服务启动时执行的命令。这里我假设你有一个Python脚本。
# 最好使用绝对路径,避免环境问题。
ExecStart=/usr/bin/python3 /opt/my-app/app.py
# 定义服务停止时执行的命令,可选。
# 如果不指定,systemd会发送SIGTERM信号。
# ExecStop=/usr/bin/pkill -f "python3 /opt/my-app/app.py"
# 服务的运行用户和组,出于安全考虑,尽量不要用root。
User=myuser
Group=myuser
# 服务的工作目录。
WorkingDirectory=/opt/my-app/
# 当服务异常退出时,systemd会尝试重启它。
# on-failure表示只有在非正常退出(如错误码非0)时才重启。
# always表示无论如何都重启。
Restart=on-failure
# 重启前等待的秒数。
RestartSec=5
# 标准输出和标准错误重定向到journald,方便日志查看。
StandardOutput=journal
StandardError=journal

[Install]
# WantedBy=multi-user.target 表示当系统进入多用户模式(正常运行级别)时,
# 这个服务会被启动。这是最常见的设置,意味着系统启动时自动运行。
WantedBy=multi-user.target

这里我用了一个Python脚本作为例子,但

ExecStart
可以是任何可执行文件或脚本。关键是路径要正确,且脚本有执行权限。

第二步:重新加载systemd配置

在你创建或修改了

.service
文件后,systemd守护进程并不会立即知道这些变化。你需要告诉它去重新扫描配置目录:

sudo systemctl daemon-reload

这步非常重要,否则systemd不会找到你的新服务或应用你的修改。

第三步:启用你的服务

启用服务意味着systemd会在系统启动时自动启动它。

sudo systemctl enable my-app.service

这个命令会在

/etc/systemd/system/multi-user.target.wants/
目录下创建一个指向你服务文件的软链接。

第四步:启动你的服务

现在,你可以手动启动你的服务了:

sudo systemctl start my-app.service

第五步:检查服务状态

随时查看你的服务是否正常运行,以及最近的日志输出:

sudo systemctl status my-app.service

如果一切顺利,你会看到服务处于“active (running)”状态。

如何确保自定义systemd服务稳定可靠地运行?

让一个服务“跑起来”和让它“稳定可靠地跑起来”是两码事。我个人在部署生产环境服务时,会特别关注几个点,它们是确保服务健壮性的基石。

首先是重启策略(Restart Policy)。在

[Service]
部分,
Restart=
指令至关重要。我通常会设置为
on-failure
,这意味着如果我的应用程序因为内部错误(非正常退出码)而崩溃,systemd会自动尝试重启它。配合
RestartSec=5
(重启前等待5秒),可以避免服务在短时间内反复崩溃导致系统资源耗尽,给服务一个“喘息”的机会。对于某些极端情况,比如内存溢出,可能需要更长的
RestartSec
或者更复杂的外部监控。

其次是日志管理。我强烈建议将

StandardOutput
StandardError
都设置为
journal
。这样做的好处是,所有的日志都会被集中到systemd的日志系统
journald
中,你可以用
journalctl -u my-app.service
命令方便地查看、过滤和管理日志,而不是让日志散落在各个文件里。这在故障排查时简直是救命稻草。

再者是资源限制。对于一些资源密集型或可能失控的服务,使用

LimitNOFILE
(限制打开文件句柄数)、
LimitNPROC
(限制进程数)等指令可以有效防止单个服务耗尽系统资源。这就像给你的服务划定了一个“沙盒”,避免它影响到其他关键系统组件。

还有依赖关系

[Unit]
部分的
After=
Requires=
指令定义了服务的启动顺序和依赖。比如,一个数据库应用肯定需要
network.target
和数据库服务(如
postgresql.service
)都启动后才能正常工作。如果依赖没处理好,服务可能在依赖项还没准备好时就启动,然后失败。我通常会先手动测试服务的启动流程,确认所有依赖都已就绪。

最后是权限隔离。在

[Service]
部分指定
User=
Group=
非常重要。永远不要让你的服务以
root
用户运行,除非万不得已。创建一个专门的用户和组来运行服务,并只赋予它必要的权限,这是最基本的安全实践。systemd还提供了
ProtectSystem=full
ProtectHome=true
等更高级的安全选项,可以进一步限制服务对文件系统的访问,进一步增强安全性。

CreateWise AI
CreateWise AI

为播客创作者设计的AI创作工具,AI自动去口癖、提交亮点和生成Show notes、标题等

下载

systemd服务与传统启动脚本相比,有哪些显著优势?

回想我刚接触Linux那会儿,都是用

rc.local
或者在
/etc/init.d/
下写一堆shell脚本来管理服务,那真是段“狂野西部”的岁月。systemd出现后,我个人觉得它带来的变革是巨大的,尤其是以下几个显著优势:

首先,启动速度和并行化。传统的SysV init脚本是串行执行的,一个服务启动完才能轮到下一个。systemd通过其复杂的依赖关系管理,能够识别出哪些服务可以并行启动,从而大大缩短了系统的启动时间。这就像是把单车道变成了多车道高速公路。

其次,强大的依赖管理。在SysV init中,依赖关系通常通过脚本中的注释来暗示,或者需要手动调整启动顺序的数字。systemd则提供了

After=
,
Requires=
,
Wants=
等清晰明了的指令来定义服务间的依赖关系,这让服务的管理和维护变得异常直观和健壮。你不需要再去猜测哪个服务应该先启动,systemd会帮你处理好。

再者,统一的日志管理。前面提到了

journald
。以前,每个服务可能都有自己的日志文件,散落在
/var/log/
的各个角落,查看和分析日志非常不便。systemd将所有服务的日志都集中到
journald
中,通过
journalctl
命令就能进行统一的查询、过滤和分析,大大提高了故障排查的效率。这就像是拥有了一个中央监控室。

还有,资源控制(Cgroups)集成。systemd与Linux内核的Cgroups紧密集成,这意味着你可以非常精细地控制每个服务所能使用的CPU、内存、I/O等资源。这对于防止单个服务耗尽系统资源,或者在多租户环境中进行资源隔离非常有用。这是传统init脚本很难实现的功能。

最后,服务监控与自动重启。systemd能够持续监控服务的状态,并在服务异常退出时根据配置(如

Restart=on-failure
)自动重启服务。这为应用程序提供了一层基础的自我修复能力,减少了人工干预的需要。传统的init脚本需要额外的工具(如
supervisord
)才能实现类似的功能。

这些优势加起来,使得systemd在管理复杂系统服务时,无论是效率、可靠性还是易用性上,都远超传统的init系统。

自定义systemd服务遇到问题时,我应该如何进行故障排查?

哪怕是经验再丰富的开发者,在配置systemd服务时也难免会遇到一些“小插曲”。关键在于,当服务不按预期工作时,你得知道从哪里入手去“审问”它。我个人觉得,故障排查就像是侦探破案,需要一步步抽丝剥茧。

第一步,也是最直接的一步,就是检查服务状态

sudo systemctl status my-app.service

这个命令会告诉你服务当前是运行中、失败、还是停止。更重要的是,它会显示最近的几行日志,以及服务进程的退出代码。如果状态显示

failed
,那么退出代码(Exit Code)通常能给你提供第一个线索。

第二步,深入查看日志

如果

status
命令提供的日志信息不够,或者你想看更早的日志,
journalctl
就是你的好帮手。

sudo journalctl -u my-app.service

这个命令会显示该服务的所有日志。我通常会加上

-f
(follow)来实时查看日志,或者加上
--since "1 hour ago"
来查看特定时间段的日志。

sudo journalctl -u my-app.service -f # 实时跟踪日志
sudo journalctl -u my-app.service --since "2023-10-27 10:00:00" # 查看特定时间点后的日志

日志往往能揭示服务启动失败的具体原因,比如找不到文件、权限不足、端口被占用、程序内部错误等。

第三步,手动执行

ExecStart
命令

很多时候,服务在systemd下启动失败,但在终端手动执行

ExecStart
定义的命令却能成功。这通常意味着环境问题。我会在服务用户下,切换到
WorkingDirectory
,然后直接运行
ExecStart
中的命令。

sudo su - myuser # 切换到服务运行的用户
cd /opt/my-app/ # 进入工作目录
/usr/bin/python3 /opt/my-app/app.py # 尝试手动运行程序

如果手动运行失败,那么问题出在程序本身或其运行环境。如果手动运行成功,但在systemd下失败,那很可能是systemd服务文件中的配置问题,比如:

  • 权限问题:服务用户对程序文件、日志文件、数据目录是否有读写执行权限?
  • 环境变量:服务是否依赖某些环境变量?systemd默认提供的环境变量很少,你可能需要在服务文件中用
    Environment=
    EnvironmentFile=
    来设置。
  • 工作目录
    WorkingDirectory=
    是否设置正确?程序是否依赖当前工作目录来查找资源?
  • 依赖服务
    After=
    Requires=
    中的依赖服务是否真的已经启动并正常工作?

第四步,检查服务文件语法

虽然不常见,但服务文件本身可能存在语法错误。你可以使用

systemd-analyze verify
命令来检查你的服务文件。

systemd-analyze verify /etc/systemd/system/my-app.service

这个命令会指出服务文件中的任何语法错误或不规范之处。

通过这些步骤,你通常能够定位到问题的根源。记住,耐心和细致是故障排查的关键。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

447

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

606

2023.08.10

postgresql常用命令
postgresql常用命令

postgresql常用命令psql、createdb、dropdb、createuser、dropuser、l、c、dt、d table_name、du、i file_name、e和q等。本专题为大家提供postgresql相关的文章、下载、课程内容,供大家免费下载体验。

164

2023.10.10

常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1007

2023.11.02

postgresql常用命令有哪些
postgresql常用命令有哪些

postgresql常用命令psql、createdb、dropdb、createuser、dropuser、l、c、dt、d table_name、du、i file_name、e和q等。更详细的postgresql常用命令,大家可以访问下面的文章。

214

2023.11.16

postgresql常用命令介绍
postgresql常用命令介绍

postgresql常用命令有l、d、d5、di、ds、dv、df、dn、db、dg、dp、c、pset、show search_path、ALTER TABLE、INSERT INTO、UPDATE、DELETE FROM、SELECT等。想了解更多postgresql的相关内容,可以阅读本专题下面的文章。

281

2023.11.20

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

230

2026.02.12

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

389

2023.06.29

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 10.6万人学习

Git 教程
Git 教程

共21课时 | 4.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号