在 CentOS 7 中使用 systemd 创建自定义服务

发布于:2025-08-15 ⋅ 阅读:(15) ⋅ 点赞:(0)

简述创建自定义服务步骤

  • 创建服务文件:在 /etc/systemd/system/ 目录下创建一个新的服务文件,例如 myapp.service。使用 sudo 权限进行创建。
  • 编辑服务文件:使用文本编辑器(如 vi 或 nano)编写服务单元文件。
  • 重新加载 systemd 配置:每次修改服务文件后,需要运行 sudo systemctl daemon-reload 来重新加载配置。
  • 启用服务:使用 sudo systemctl enable myapp.service 设置开机启动。
  • 启动服务:使用 sudo systemctl start myapp.service 启动服务。
  • 检查服务状态:使用 sudo systemctl status myapp.service 查看服务状态。

文件覆盖优先级

在 CentOS 7 的 systemd 系统中,/usr/lib/systemd/system/ 和 /etc/systemd/system/ 两个目录有明确的区别:

  • systemd 加载配置的顺序(从高到低):
/etc/systemd/system/service.d/*.conf
/etc/systemd/system/service
/run/systemd/system/service.d/*.conf(临时配置)
/usr/lib/systemd/system/service.d/*.conf
/usr/lib/systemd/system/service
需求 操作位置
安装新服务 /etc/systemd/system/
修改现有服务参数 /etc/systemd/system/service.d/
完全替换服务文件 /etc/systemd/system/
查看软件原始配置 /usr/lib/systemd/system/
添加开机启动依赖 /etc/systemd/system/service.d/

/lib/systemd/system/(实际上是 /usr/lib/systemd/system/ 的符号链接)

特性 /usr/lib/systemd/system/ /etc/systemd/system/
来源 软件包安装的原始服务文件 管理员自定义的服务文件或覆盖配置
优先级 高(覆盖 /lib/ 中的配置)
是否会被覆盖 软件升级时可能被覆盖 不会被软件升级覆盖
推荐修改方式 不应直接修改 应在此目录添加自定义配置
目录类型 系统默认目录(只读) 管理员配置目录(可写)
  • 作用:存放软件包(通过 yum/rpm 安装)提供的原始服务文件
  • 特点:
    • 系统级别的默认配置
    • 软件升级时会覆盖此目录的文件
    • 不要直接修改这里的文件(修改会被覆盖)

创建服务流程

在 /etc/systemd/system/ 目录下创建 .service 文件(需 root 权限):

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

编写服务配置模板

[Unit]
Description=服务描述
After=network.target    # 依赖关系

[Service]
Type=forking     # 服务类型
ExecStart=/path/to/command
User=username           # 运行用户
Restart=on-failure      # 重启策略

[Install]
WantedBy=multi-user.target

Systemd 服务文件三大区块详解

[Unit]
• 服务标识 (Description)
• 启动顺序 (After/Before)
• 依赖关系 (Requires/Wants)
[Service] [Install]
• 进程控制 (Type/ExecStart) • 开机启动目标 (WantedBy)
• 运行环境 (User/Env) • 别名管理 (Alias)
• 资源限制 (MemoryLimit)
• 安全策略 (PrivateTmp)
[Unit] 区块 - 服务元数据与依赖

定义服务的描述、依赖关系和启动顺序

指令 说明 示例值
Description 必填 服务描述信息(显示在 systemctl status 中) Description=Nginx Web Server
After 定义启动顺序依赖(在此服务之后启动) After=network.target
Before 定义反向依赖(在此服务之前启动) Before=shutdown.target
Requires 强依赖 - 依赖服务失败则本服务失败 Requires=mysql.service
Wants 弱依赖 - 依赖服务失败不影响本服务 Wants=postfix.service
Conflicts 冲突服务 - 不能同时运行的服务 Conflicts=httpd.service
Documentation 服务文档链接 Documentation=man:nginx(8)
Condition… 启动条件检查(如 ConditionPathExists=/etc/nginx.conf)

[Unit] 区块示例

[Unit]
Description=High Performance Web Server
After=network.target remote-fs.target nss-lookup.target
Wants=postgresql.service
Documentation=https://nginx.org/en/docs/
[Service] 区块 - 进程运行配置

定义服务进程的执行方式和运行时行为

类别 指令 说明 常用值
启动类型 Type 必填 进程启动类型 simple、forking、oneshot、notify
ExecStart 必填 启动命令(绝对路径) /usr/sbin/nginx -g “daemon off;”
ExecStartPre 主命令前执行的预备命令 /bin/mkdir -p /run/nginx
ExecStartPost 主命令后执行的后续命令 /bin/echo “Service started”
ExecReload 重载服务时执行的命令 /bin/kill -HUP $MAINPID
运行环境 User 运行服务的用户 nginx、nobody
Group 运行服务的用户组 www-data
WorkingDirectory 工作目录 /var/www/html
Environment 设置环境变量 PORT=8080
EnvironmentFile 从文件加载环境变量 /etc/sysconfig/nginx
重启策略 Restart 服务退出时重启策略 no、always、onfailure、on-abort
RestartSec 重启前等待时间 5s、1min
资源限制 MemoryLimit 内存限制 512M
CPUQuota CPU配额 80%
安全控制 PrivateTmp 使用私有/tmp目录(增强安全) true
ProtectSystem 文件系统保护级别 full、strict

[Service]示例

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
User=nginx
Group=nginx
Environment="NGINX_LOGLEVEL=info"
Restart=on-failure
RestartSec=5s
MemoryLimit=500M
PrivateTmp=true

常见 Type 类型:

特性 Type=simple Type=forking
工作方式 主进程直接在前台运行 主进程 fork 子进程后退出
systemd 监控对象 ExecStart 启动的进程 fork 出来的子进程
适用场景 现代应用 (Python/Node.js/Go 等) 传统守护进程 (Nginx/MySQL 等)
PID 文件 不需要 必须 通过 PIDFile= 指定
启动完成判定 立即标记为 active 需等待主进程退出
日志处理 自动捕获 stdout/stderr 需程序自行处理日志
启动速度 快 (直接启动) 稍慢 (需完成 fork 过程)
典型应用 Flask, Redis, systemd 自身服务 Apache, PostgreSQL, Zabbix Server

在这里插入图片描述

判断应该使用哪种类型:

# 手动测试启动程序
/usr/sbin/nginx -c /etc/nginx/nginx.conf

# 观察行为:
# 1. 如果命令立即返回且后台有进程 → forking
# 2. 如果命令阻塞在前台 → simple
[Install] 区块 - 开机启动配置

定义服务安装到哪个运行级别(target)

指令 说明 示例值
WantedBy 必填 指定服务关联的 target(实现开机启动) multi-user.target
RequiredBy 指定强依赖本服务的 target graphical.target
Alias 服务别名 Alias=webserver.service
Also 安装时同时启用的其他服务 Also=nginx-sockets.service

[Install] 示例

[Install]
WantedBy=multi-user.target
Alias=web.service

完整示例

[Unit]
Description=My Custom Application   # 服务描述
After=network.target                # 在网络启动后运行

[Service]
Type=simple                         # 服务类型(常用 simple 或 forking)
User=appuser                        # 运行服务的用户
Group=appgroup                      # 运行服务的组
WorkingDirectory=/opt/myapp         # 工作目录
ExecStart=/usr/bin/java -jar /opt/myapp/app.jar  # 启动命令(必须绝对路径)
Restart=on-failure                  # 失败时自动重启  
RestartSec=5s                       # 重启间隔
Environment="PORT=8080"             # 设置环境变量
PrivateTmp=true                     # 启用私有临时目录(安全增强)

# 日志配置(可选)
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=myapp

[Install]
WantedBy=multi-user.target          # 多用户模式下启用

设置权限和路径

# 确保可执行文件有权限
sudo chmod +x /opt/myapp/start.sh
# 环境变量文件(可选)
sudo vi /etc/sysconfig/myapp  # 定义变量 APP_ENV=production

服务文件中引用:

EnvironmentFile=/etc/sysconfig/myapp
ExecStart=/opt/myapp/start.sh ${APP_ENV}

管理服务命令

# 重载 systemd 配置(修改服务文件后必须执行)
sudo systemctl daemon-reload

# 启动/停止服务
sudo systemctl start myapp.service
sudo systemctl stop myapp.service

# 设置开机自启
sudo systemctl enable myapp.service

# 查看状态和日志
systemctl status myapp         # 服务状态
journalctl -u myapp -f         # 实时日志(-f 跟踪日志)
journalctl -u myapp --since "2020-01-01" --until "1 hour ago"  # 时间筛选

启动失败排查

systemctl status myapp      # 查看错误摘要
journalctl -xe              # 检查详细日志
  • 测试启动命令: 手动执行 ExecStart 中的命令,验证路径和权限。
  • 环境变量问题: 使用 systemctl show myapp 检查最终环境变量

注意事项

  • 路径必须为绝对路径(包括脚本和命令)
  • 修改服务文件后必须执行 daemon-reload
  • 生产环境建议用非 root 用户运行(User=)

网站公告

今日签到

点亮在社区的每一天
去签到