Trong các hệ thống dựa trên RHEL hoặc CentOS, việc tạo các gói RPM tùy chỉnh là một kỹ năng quan trọng để phân phối và quản lý phần mềm. Quá trình này chủ yếu xoay quanh việc viết một tệp SPEC, định nghĩa cách biên dịch, đóng gói và cài đặt ứng dụng của bạn. Bài viết này sẽ đi sâu vào cấu trúc của tệp SPEC và hướng dẫn cách xây dựng một gói RPM cơ bản.
Thiết lập môi trường đóng gói RPM
Trước khi bắt đầu tạo gói, bạn cần thiết lập môi trường cần thiết trên hệ thống của mình.
Cài đặt các công cụ cần thiết
Bạn cần cài đặt các gói rpm-build và rpmdevtools để có các tiện ích xây dựng RPM.
sudo yum -y install rpm-build rpmdevtools
Tạo cấu trúc thư mục làm việc
Công cụ rpmdev-setuptree sẽ tạo cấu trúc thư mục chuẩn mà rpmbuild mong đợi. Theo mặc định, các thư mục này sẽ được tạo trong thư mục chính của người dùng (ví dụ: /root/rpmbuild nếu bạn đang dùng root).
[user@host ~]$ rpmdev-setuptree
[user@host ~]$ ls ~/rpmbuild/
BUILD BUILDROOT RPMS SOURCES SPECS SRPMS
Các thư mục này có vai trò cụ thể:
- BUILD: Nơi mã nguồn được giải nén và xây dựng.
- BUILDROOT: Một môi trường cài đặt ảo tạm thời. Tất cả các tệp sẽ được cài đặt vào đây trong giai đoạn
%installtrước khi được đóng gói thành RPM. Nội dung của thư mục này sẽ bị xóa sau khi hoàn thành gói RPM. - RPMS: Thư mục chứa các gói RPM đã hoàn thành, được phân loại theo kiến trúc (ví dụ:
x86_64). - SOURCES: Nơi đặt các tệp mã nguồn nén (tarball), tệp cấu hình, tệp vá lỗi (patch files) và các tệp tài nguyên khác.
- SPECS: Nơi chứa các tệp SPEC của bạn.
- SRPMS: Thư mục chứa các gói RPM nguồn (Source RPM) có thể được sử dụng để tái tạo gói nhị phân (binary RPM).
Thay đổi thư mục làm việc mặc định
Nếu bạn muốn lưu trữ môi trường xây dựng RPM ở một vị trí khác (ví dụ: /home/user/my_rpms), bạn có thể định cấu hình nó trong tệp ~/.rpmmacros.
Di chuyển thư mục rpmbuild hiện có đến vị trí mới:
[user@host ~]$ mv ~/rpmbuild /home/user/my_rpms
Chỉnh sửa tệp ~/.rpmmacros để cập nhật biến %_topdir:
[user@host ~]$ vi ~/.rpmmacros
Thêm hoặc sửa đổi dòng sau:
# Định nghĩa thư mục làm việc gốc cho rpmbuild
%_topdir /home/user/my_rpms
# Các cấu hình khác (ví dụ: %_smp_mflags, %__arch_install_post)
# ... giữ nguyên các dòng cấu hình mặc định khác ...
Để xác minh thay đổi, bạn có thể kiểm tra cấu hình rpmbuild:
[user@host ~]$ rpmbuild --showrc | grep topdir
-14: _builddir %{_topdir}/BUILD
-14: _buildrootdir %{_topdir}/BUILDROOT
-14: _rpmdir %{_topdir}/RPMS
-14: _sourcedir %{_topdir}/SOURCES
-14: _specdir %{_topdir}/SPECS
-14: _srcrpmdir %{_topdir}/SRPMS
-14: _topdir /home/user/my_rpms
Giải thích chi tiết về tệp SPEC
Tệp SPEC là trung tâm của quá trình xây dựng gói RPM. Nó chứa tất cả thông tin và hướng dẫn cần thiết để rpmbuild tạo gói. Một tệp SPEC bao gồm nhiều phần khác nhau, mỗi phần phục vụ một mục đích cụ thể.
Các trường Metadata (Thông tin gói)
Phần này định nghĩa các thuộc tính cơ bản của gói:
- Name: Tên của gói (ví dụ:
my-application). Có thể được tham chiếu trong SPEC bằng%{name}. - Version: Phiên bản phần mềm (ví dụ:
1.0.0). Tham chiếu bằng%{version}. - Release: Số phát hành của gói RPM này (ví dụ:
1%{?dist}). Tăng số này mỗi khi bạn xây dựng lại gói cho cùng một phiên bản phần mềm. Tham chiếu bằng%{release}. - Summary: Một mô tả ngắn gọn, một dòng về gói.
- Group: Phân loại gói (ví dụ:
Applications/System). - License: Giấy phép của phần mềm (ví dụ:
GPLv3,MIT). - Source: Đường dẫn đến tệp mã nguồn gốc (thường là tarball nén). Có thể có nhiều nguồn (
Source0,Source1, v.v.). Tham chiếu bằng%{source0},%{source1}. - Patch: Đường dẫn đến các tệp vá lỗi (patch files) nếu cần sửa đổi mã nguồn. Có thể có nhiều patch (
Patch0,Patch1, v.v.). Tham chiếu bằng%{patch0}. - URL: Địa chỉ trang web của dự án phần mềm.
- Vendor: Tên của tổ chức hoặc người đã đóng gói RPM.
- BuildRoot: Định nghĩa thư mục root ảo tạm thời được sử dụng trong giai đoạn
%install. Nó thường là%{_buildrootdir}hoặc có thể được tham chiếu bằng biến môi trường$RPM_BUILD_ROOT. - Requires: Liệt kê các gói mà gói này phụ thuộc để hoạt động. Có thể chỉ định phiên bản (ví dụ:
httpd >= 2.4). Các yêu cầu được phân tách bằng dấu cách. - BuildRequires: Liệt kê các gói chỉ cần thiết để biên dịch hoặc xây dựng gói, không phải để chạy.
- Prefix:
%{_prefix}hoặc%{_sysconfdir}. Được sử dụng để cho phép người dùng thay đổi thư mục cài đặt mặc định khi cài đặt RPM. - %description: Một mô tả dài hơn, chi tiết hơn về gói.
- %define: Cho phép định nghĩa các biến tùy chỉnh trong tệp SPEC (ví dụ:
%define app_dir /opt/%{name}).
Các phần Scriptlet (Giai đoạn xây dựng và cài đặt)
Các phần này chứa các lệnh shell được thực thi ở các giai đoạn khác nhau của quá trình xây dựng và cài đặt.
- %prep: Giai đoạn chuẩn bị. Thường chứa lệnh
%setup -qđể giải nén mã nguồn vào thư mụcBUILDvà áp dụng các tệp vá lỗi (%patch0 -p1). - %build: Giai đoạn biên dịch. Chứa các lệnh để biên dịch mã nguồn (ví dụ:
./configure --prefix=%{_prefix} && make %{?_smp_mflags}). - %install: Giai đoạn cài đặt. Các tệp đã biên dịch được cài đặt vào thư mục
BUILDROOTảo. Sử dụng lệnhinstallchuẩn hoặcmake install DESTDIR=%{buildroot}. - %check: Giai đoạn kiểm tra. Chứa các lệnh để chạy bộ kiểm thử của phần mềm (ví dụ:
make check). - %clean: Giai đoạn dọn dẹp. Xóa thư mục
BUILDROOTtạm thời sau khi gói được tạo. - %pre: Script được thực thi TRƯỚC khi cài đặt gói. Thường được dùng để tạo người dùng, nhóm hoặc kiểm tra điều kiện.
- %post: Script được thực thi SAU khi cài đặt gói. Có thể được dùng để khởi động dịch vụ, cập nhật bộ nhớ đệm (cache) hoặc cấu hình cuối cùng.
- %preun: Script được thực thi TRƯỚC khi gỡ cài đặt gói. Dùng để dừng dịch vụ hoặc sao lưu dữ liệu.
- %postun: Script được thực thi SAU khi gỡ cài đặt gói. Dùng để xóa người dùng, nhóm hoặc dọn dẹp các tệp còn sót lại.
%files (Kê khai tệp)
Phần này liệt kê tất cả các tệp và thư mục sẽ được đưa vào gói RPM, cùng với các thuộc tính của chúng (quyền, chủ sở hữu, nhóm).
- Cú pháp:
%attr(mode, user, group) /đường/dẫn/đến/tệp %doc: Đánh dấu các tệp là tài liệu.%config: Đánh dấu các tệp là tệp cấu hình (sẽ không bị ghi đè khi nâng cấp gói).- Sử dụng dấu đại diện (wildcard) để bao gồm nhiều tệp.
%changelog (Lịch sử thay đổi)
Ghi lại lịch sử thay đổi của gói RPM, bao gồm ngày, tác giả và mô tả các thay đổi.
* Mon Jan 01 2024 Your Name <your.email@example.com> - 1.0.0-1
- Initial release of the package.
Ví dụ thực tế: Xây dựng gói RPM cho cấu hình SSH
Hãy tạo một gói RPM đơn giản để phân phối các tệp cấu hình SSH cho truy cập không cần mật khẩu.
Chuẩn bị tệp nguồn
Tạo một thư mục chứa các tệp nguồn trong ~/my_rpms/SOURCES/.
[user@host ~]$ mkdir -p ~/my_rpms/SOURCES/ssh-key-setup-1.0.0
[user@host ~]$ cp ~/.ssh/authorized_keys ~/.ssh/id_rsa.pub ~/.ssh/id_rsa ~/my_rpms/SOURCES/ssh-key-setup-1.0.0/
Lưu ý: Trong thực tế, bạn nên cẩn thận với việc phân phối khóa riêng tư (id_rsa) qua RPM. Đây chỉ là một ví dụ minh họa.
Tạo tệp SPEC
Tạo tệp SPEC trong thư mục ~/my_rpms/SPECS/. Chúng ta sẽ đặt tên là ssh-key-setup.spec.
[user@host ~]$ touch ~/my_rpms/SPECS/ssh-key-setup.spec
[user@host ~]$ vi ~/my_rpms/SPECS/ssh-key-setup.spec
Nội dung của ssh-key-setup.spec:
Name: ssh-key-setup
Version: 1.0.0
Release: 1
Summary: Cấu hình khóa SSH cho truy cập không mật khẩu
License: MIT
Source0: %{name}-%{version}
# Định nghĩa thư mục đích cho các khóa SSH
%define target_ssh_dir /root/.ssh
%description
Gói này cung cấp các tệp khóa SSH cần thiết để thiết lập truy cập không cần mật khẩu
trên các hệ thống RHEL/CentOS.
%prep
# Không cần giải nén vì chúng ta đang sao chép trực tiếp các tệp từ thư mục SOURCE
# Chỉ cần đảm bảo thư mục nguồn tồn tại.
# %setup -q -n %{name}-%{version}
%install
# Tạo thư mục đích trong BUILDROOT nếu nó chưa tồn tại
install -d -m 0700 %{buildroot}%{target_ssh_dir}
# Cài đặt các tệp khóa SSH vào thư mục đích với quyền phù hợp
install -p -m 0600 %{SOURCE0}/authorized_keys %{buildroot}%{target_ssh_dir}/authorized_keys
install -p -m 0600 %{SOURCE0}/id_rsa.pub %{buildroot}%{target_ssh_dir}/id_rsa.pub
install -p -m 0600 %{SOURCE0}/id_rsa %{buildroot}%{target_ssh_dir}/id_rsa
%pre
# Xóa các tệp khóa SSH cũ trước khi cài đặt để đảm bảo sạch sẽ
rm -f %{target_ssh_dir}/authorized_keys \
%{target_ssh_dir}/id_rsa.pub \
%{target_ssh_dir}/id_rsa
%postun
# Sau khi gỡ cài đặt, kiểm tra xem thư mục có rỗng không và xóa nó nếu có thể
# Lưu ý: Thư mục này có thể chứa các tệp khác không thuộc về gói này,
# nên cẩn thận khi xóa toàn bộ thư mục.
# Để an toàn, chỉ xóa các tệp do gói này cài đặt.
# rm -rf %{target_ssh_dir} # Có thể quá hung hãn
rm -f %{target_ssh_dir}/authorized_keys \
%{target_ssh_dir}/id_rsa.pub \
%{target_ssh_dir}/id_rsa
%clean
# Xóa thư mục BUILDROOT tạm thời
[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT"
%files
# Liệt kê các tệp sẽ được đóng gói và đặt quyền sở hữu
%attr(0600,root,root) %{target_ssh_dir}/authorized_keys
%attr(0600,root,root) %{target_ssh_dir}/id_rsa.pub
%attr(0600,root,root) %{target_ssh_dir}/id_rsa
%changelog
* Mon Jan 01 2024 TechUser <tech.user@example.com> - 1.0.0-1
- Phát hành ban đầu gói cấu hình khóa SSH.
Xây dựng gói RPM
Sử dụng lệnh rpmbuild -bb để xây dựng gói RPM nhị phân từ tệp SPEC của bạn.
[user@host ~]$ rpmbuild -bb ~/my_rpms/SPECS/ssh-key-setup.spec
Nếu quá trình xây dựng thành công, bạn sẽ tìm thấy gói RPM trong thư mục RPMS/x86_64/:
[user@host ~]$ ls ~/my_rpms/RPMS/x86_64/ssh-key-setup-1.0.0-1.x86_64.rpm
/home/user/my_rpms/RPMS/x86_64/ssh-key-setup-1.0.0-1.x86_64.rpm
Bạn có thể kiểm tra nội dung của gói RPM bằng lệnh rpm -qpl:
[user@host ~]$ rpm -qpl ~/my_rpms/RPMS/x86_64/ssh-key-setup-1.0.0-1.x86_64.rpm
/root/.ssh/authorized_keys
/root/.ssh/id_rsa
/root/.ssh/id_rsa.pub
Xác minh cài đặt
Để kiểm tra gói RPM đã tạo, hãy cài đặt nó trên một hệ thống (hoặc cùng một hệ thống).
[user@host ~]$ sudo rpm -ivh ~/my_rpms/RPMS/x86_64/ssh-key-setup-1.0.0-1.x86_64.rpm
Preparing... ################################# [100%]
Updating / installing...
1:ssh-key-setup-1.0.0-1 ################################# [100%]
Sau khi cài đặt, bạn có thể kiểm tra xem các tệp đã được đặt đúng vị trí chưa:
[user@host ~]$ ls -l /root/.ssh/
total 12
-rw-------. 1 root root 398 Apr 20 2020 authorized_keys
-rw-------. 1 root root 1679 Apr 20 2020 id_rsa
-rw-r--r--. 1 root root 398 Apr 20 2020 id_rsa.pub
Quá trình xây dựng và cài đặt gói RPM của bạn đã thành công.