在Linux系统中,如何将开发者编写的应用程序转化为可靠的生产环境服务?本文将深入解析如何将Go程序封装为Systemd服务单元,并通过RPM包实现标准化部署。这套方案被广泛应用于企业级软件部署,如Nginx、MySQL等服务的分发安装。

Systemd

Systemd是内核之上的第一个用户进程(PID=1),是现代 Linux 发行版(如 Ubuntu、CentOS、Debian、Fedora 等)的初始化系统和服务管理器。

内核启动后,Systemd 是第一个运行的用户空间程序,由内核直接启动。其他服务/应用由 Systemd 直接或间接启动,Systemd 能并行启动多个服务,显著加快开机速度。并自动处理服务之间的依赖关系。

用于管理所有用户空间进程: • 管理服务生命周期。`systemctl start nginx`类似的启动/停止/重启服务,查看服务状态,开机自启,检查是否运行中。

• 依赖解析。哪些服务必须先启动(前置依赖);哪些服务可以并行启动(无依赖关系时);哪些服务需要一起启动(关联服务)

• 资源隔离。Systemd 原生集成 Linux Cgroup(控制组),比如实时查看 Cgroup 资源使用systemctl show nginx --property=MemoryCurrent,MemoryMax systemd-cgtop

创建一个 systemd 服务

Systemd服务单元(testrpm.service)是一个配置文件,它定义了如何管理系统服务、服务依赖关系、环境变量、用户权限、资源限制等,Systemd服务单元示例解析:

[Unit]
Description=testrpm Daemon
After=network.service sys-fs-resctrl.mount  # 确保在网络和resctrl文件系统就绪后启动

[Service]
ExecStart=/usr/local/bin/testrpm --log_level debug # 启动test程序并传入相应参数以启动该服务
ExecStopPost=-/usr/local/bin/reset_test.sh # 服务停止后执行清理脚本
MemoryLimit=1G # 限制服务最多使用1GB内存,通过内核 cgroups 实现,支持动态调整:systemctl set-property testrpm MemoryLimit=5G
Restart=on-failure # 服务异常退出时自动重启
User=daemon_user

[Install]
WantedBy=multi-user.target  # 定义服务在系统多用户模式下启用

服务部署与管理:

# 部署服务文件
sudo cp testrpm.service /usr/lib/systemd/system/
# 重新加载配置
sudo systemctl daemon-reload
# 启动服务
sudo systemctl start testrpm
# 设置开机自启
sudo systemctl enable testrpm
# 查看服务状态
sudo systemctl status testrpm
# 查看服务日志,日志统一管理,集成 Journald 组件,二进制日志存储(/var/log/journal/),结构化查询
journalctl -u testrpm -f

RPM包是干什么的

RPM包是部署工具和服务配置的载体,是Linux下主流的软件分发格式(将软件及其依赖打包成单个.rpm 文件),MySQL、Nginx 等软件都提供 RPM 包。自动解决软件依赖关系;支持升级、降级和回滚;统一安装、查询、卸载接口。

RPM文件是Red Hat系, 包管理工具是yum(旧)、dnf(新),默认系统CentOS/RHEL/Fedora/Alibaba Linux.

管理RPM/DEB包的平台:

开发者 ────┬───> 官方仓库(如Ubuntu Archive、RHEL BaseOS)
           │
           ├──> 第三方仓库(如EPEL、PPA)
           │
           └──> 私有仓库(如Nexus、Artifactory)
                  │
                  ▼
              客户端(yum/apt)───> 解析依赖并安装

创建一个RPM包

准备源码结构

testrpm-1.0.0/
├── cmd/
│   └── testrpm/          # Go主程序代码
├── config/
│   └── testrpm/
│       ├── testrpm.service  # Systemd服务文件
│       └── reset_testrpm.sh # 清理脚本
├── vendor/           # Go依赖
└── go.mod            # Go模块文件

编写SPEC文件,指导rpm包的安装

Name: testrpm
Version: 1.0.0
Release: 1.myself
Summary: testrpm Daemon

%description
System service for test rpm.

%prep
%setup -q  # 解压源码

%build
# 静态编译Go程序
CGO_ENABLED=0 GOOS=linux go build -o bin/testrpm ./cmd/testrpm

%install
# 安装二进制文件
install -m 0755 bin/testrpm %{buildroot}/usr/local/bin/testrpm
# 安装Systemd服务文件
install -m 0644 config/testrpm.service %{buildroot}/usr/lib/systemd/system/testrpm.service

%files
# 声明包含的文件
/usr/local/bin/testrpm
/usr/lib/systemd/system/testrpm.service

构建RPM包

# 生成源码压缩包
tar -czvf testrpm-1.0.0.tar.gz testrpm-1.0.0/
# 构建RPM
rpmbuild -bb testrpm.spec

RPM包安装行为:

  1. 二进制文件直接解压到目标路径(如/usr/local/bin/testrpm)
  2. Systemd服务文件部署到/usr/lib/systemd/system/
  3. 不会重新编译(二进制已在构建阶段生成)

技术方案对比

内核模块 vs RPM包 vs Systemd服务,某个需求我要选哪种方式实现?

  • Systemd服务:进程管理,长期稳定的服务,比如:apt install nginx + systemctl enable nginx
  • 内核模块: 内核级功能扩展,比如设备驱动、文件系统等内核级功能。
  • rpm包: 用户态应用程序分发。

比如:内核模块 nvidia.ko 提供 GPU 驱动能力。Systemd 服务 nvidia-persistenced 管理用户态守护进程。通过 udev 规则在设备插入时自动加载模块并启动服务。


文章作者: 易百分
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 易百分 !
  目录