Linux服务器应用服务部署指南

因为不能被理解,所以想说的话越来越少

Posted by yishuifengxiao on 2025-03-22

systemd 是现代 Linux 发行版的标准初始化系统和服务管理器。我们通过创建一个 服务单元文件(Service Unit File) 来实现所需的功能。

整体步骤概览

  1. 准备你的应用程序:确保你的应用已经安装或编译好,知道其启动命令和所需的工作目录。
  2. 创建 Service 文件:在 /etc/systemd/system/ 目录下创建一个以 .service 结尾的文件。
  3. 设置文件和目录权限:确保 systemd 有权限执行你的应用和相关文件。
  4. 重载 systemd 配置:让 systemd 识别新的服务文件。
  5. 启动并测试服务:启动服务,检查状态,测试功能。
  6. 启用开机自启:配置服务在系统启动时自动运行。
  7. (可选)查看日志:学习如何排查问题。

第1步:准备应用程序

假设你的应用是一个名为 myapp 的二进制文件,放在 /opt/myapp/ 目录下。
启动命令为:/opt/myapp/myapp --config /opt/myapp/config.conf

  • 最佳实践
    • 将你的应用程序放在 /opt, /srv/usr/local/bin 等标准位置。
    • 如果应用会产生日志,建议让它输出到 stdout/stderr,由 systemd 统一捕获和管理,而不是自己写日志文件。
    • 确保应用不会自行“守护进程化”(daemonize/fork into the background),systemd 更适合管理前台进程。

第2步:创建 Service 文件

使用 sudo 权限在 /etc/systemd/system/ 目录下创建服务文件,例如 myapp.service

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

将以下内容粘贴到文件中,并根据你的实际情况进行修改。

[Unit]
Description=My Custom Application # 服务的描述,方便识别
Documentation=https://myapp.com/docs # (可选)应用文档的URL
After=network.target # 定义启动顺序,表明本服务在网络就绪后启动

[Service]
Type=simple # 常见类型:simple(默认,主进程)、forking(子进程托管)、exec
User=appuser # (强烈建议)指定运行此服务的非root用户
Group=appgroup # (可选)指定用户组
WorkingDirectory=/opt/myapp # 设置工作目录,便于应用访问相对路径的文件
ExecStart=/opt/myapp/myapp --config /opt/myapp/config.conf # 最重要的指令:启动命令
Restart=always # 自动重启策略:always, on-failure, on-abort等
RestartSec=5 # 重启前等待的时间(秒)
Environment=PORT=8080 # (可选)设置环境变量
EnvironmentFile=-/etc/default/myapp # (可选)从文件加载环境变量(前面的-表示文件不存在也不报错)
StandardOutput=journal # 输出重定向到systemd journal(默认)
StandardError=journal # 错误重定向到systemd journal(默认)
# 资源限制(可选)
#LimitNOFILE=65535
#LimitNPROC=65535

[Install]
WantedBy=multi-user.target # 表示当系统以“多用户”模式启动时,启用此服务

第3步:设置权限

  1. 为应用文件设置权限

    # 假设你创建了一个名为 ‘appuser’ 的用户来运行此服务
    sudo useradd -r -s /bin/false appuser # 创建系统用户,无需登录shell
    sudo chown -R appuser:appgroup /opt/myapp # 将应用目录的所有权给该用户
    sudo chmod -R 750 /opt/myapp # 设置合适的权限
  2. Service 文件权限:通常 root ownership 和 644 权限即可,systemctl 会自动处理。

第4步:重载 systemd 配置

创建或修改服务文件后,必须让 systemd 重新加载其配置。

sudo systemctl daemon-reload

第5步:启动并测试服务

  1. 启动服务

    sudo systemctl start myapp
  2. 检查服务状态:这是最重要的调试命令。

    sudo systemctl status myapp
    • 如果状态是 active (running),表示启动成功。
    • 如果失败, status 命令通常会显示最近的错误信息。
  3. 测试自动重启

    • 手动杀掉你的应用进程:sudo pkill myapp
    • 等待几秒(我们设置了 RestartSec=5),再次运行 sudo systemctl status myapp。你应该会看到服务的 Active 时间更新了,并且日志里可能有重启的记录。

第6步:启用开机自启

sudo systemctl enable myapp

这个命令会在 /etc/systemd/system/multi-user.target.wants/ 目录下创建一个符号链接,指向你的服务文件。这样系统启动时就会自动启动该服务。

验证是否启用

sudo systemctl is-enabled myapp
# 应返回 ‘enabled’

第7步:查看应用日志

systemd 使用 journalctl 统一管理所有服务的日志。

  1. 查看该服务的全部日志

    sudo journalctl -u myapp
  2. 实时追踪最新日志(类似 tail -f):

    sudo journalctl -u myapp -f
  3. 查看本次启动以来的日志

    sudo journalctl -u myapp -b
  4. 查看日志并显示更详细的时间戳

    sudo journalctl -u myapp --since "2024-01-01 12:00:00"

Service 脚本各部分含义详解

  • [Unit] 部分

    • Description: 对人类友好的服务描述文本。
    • Documentation: 提供项目文档的 URL,方便维护者查阅。
    • After: 定义启动顺序的依赖关系。After=network.target 表示“在 network.target 单元之后启动”,确保网络可用后再启动你的网络应用。
  • [Service] 部分(核心)

    • Type
      • simple(默认): 假设 ExecStart 命令是主进程,并且会一直在前台运行。
      • forking: 假设 ExecStart 命令会调用 fork() 创建子进程,然后父进程退出。systemd 需要跟踪子进程。常用于传统的守护进程。
      • exec: 类似 simple,但在执行完 ExecStart 命令后,systemd 才会认为服务启动完成。
    • User/Group安全最佳实践。以最小权限的非 root 用户运行服务,减少被攻击后的影响面。
    • WorkingDirectory: 在运行程序前,切换到此目录。这样你的应用就可以使用相对路径(如 ./config.conf)来访问文件。
    • ExecStart最关键的指令。指定启动服务的完整命令和参数。
    • Restart自动重启策略
      • no: 从不重启。
      • on-failure: 仅在进程以非零退出码终止时重启(推荐用于大多数情况)。
      • always: 无论什么原因退出,总是重启(适合必须持续运行的服务)。
      • on-abort: 仅在收到未处理的信号而终止时重启。
    • RestartSec: 在尝试重启服务前,systemd 等待的时间。防止频繁崩溃时不断快速重启加重系统负担。
    • Environment: 设置环境变量,格式为 KEY=VAL
    • EnvironmentFile: 指定一个文件(如 /etc/default/myapp),该文件包含 KEY=VAL 格式的环境变量。在文件中管理配置比直接在 service 文件中写更清晰。
  • [Install] 部分

    • WantedBy: 指定服务安装在哪个“目标(target)”下multi-user.target 是标准的无图形界面的多用户命令行模式。当您执行 systemctl enable myapp 时,就是在为这个 WantedBy 关系创建符号链接。