Сборка своего RPM-пакета на примере NGINX


Если нам нужно часто устанавливать свои пакеты, у нас может уходить много времени на их конфигурирование и сборку. Мы рассмотрим процесс того, как сделать RPM-пакет для установки на дистрибутив Linux одноименного семейства (например, CentOS или Red Hat). В качестве примера мы соберем NGINX с модулем SPNEGO. Это будет сделано поэтапно — сначала мы соберем простой пакет, потом добавим в него модуль и внесем изменения в конфигурационный файл.
Предварительная настройка операционной системы
Настройка рабочего окружения пользователя
Получение исходника и сборка пакета
Работа с установочным пакетом
Добавление модуля при сборке RPM
Изменение конфигурационного файла
Подготовка системы
1. Устанавливаем необходимые пакеты:
yum install wget rpm-build rpmdevtools gcc make
* где:
- wget — утилита для загрузки файлов по сети.
- rpm-build — включает в себя утилиту rpmbuild, с помощью которой будет выполняться сама сборка установочного пакета.
- rpmdevtools — позволит нам использовать утилиту rpmdev-setuptree, с помощью которой мы сможем создать рабочую среду в виде каталогов для сборки.
- gcc — компилятор СИ. Необходим для сборки.
- make — утилита для сборки исходников.
2. Устанавливаем зависимости:
yum install openssl-devel zlib-devel pcre-devel
* данные пакеты необходимы именно для нашего варианта сборки. Имейте ввиду, что в вашем случае может понадобиться больше зависимостей. Так или иначе, если в системе не будет хватать необходимых пакетов, мы получим ошибку при попытке выполнить сборку RPM.
3. Создаем пользователя.
Делать готовые установочные сборки пакетов очень опасно от пользователя root. Если мы допустим ошибку с путями, файлы могут перетереть или удалить важные для работы директории. Стоит создать отдельного пользователя и работать под ним.
Выполняем команду:
useradd builder -m
* в данном примере мы создадим пользователя builder. Опция -m сразу создаст домашний каталог для пользователя.
Теперь заходим под данным пользователем — последующие команды мы будем выполнять от него:
su - builder
Подготовка среды
Необходимо убедиться, что мы находимся в нужном каталоге для сборки — это может быть произвольная папка, которую мы создадим. В моем примере я буду использовать домашнюю директорию пользователя. Проверить текущее положение можно командой:
$ pwd
Мы должны увидеть что-то на подобие:
/home/builder
Перейти в домашний каталог пользователя можно командой:
$ cd ~
Создадим структуру каталогов для сборки:
$ rpmdev-setuptree
В нашей текущем каталоге должна появиться папка rpmbuild — а в ней:
- BUILD — содержит все файлы, которые появляются при создании пакета.
- RPMS — сюда будут складываться готовые пакеты.
- SOURCES — для исходников, из которых и будут собираться RPM-пакеты.
- SPECS — для файлов с описанием процесса сборки.
- SRPMS — для исходников RPM-файлов.
Мы готовы к загрузке исходника и его подготовке.
Загрузка исходника и сборка RPM
На странице загрузки пакетов NGINX мы можем найти пакеты для нужной нам операционной системы. Так как в нашем примере собирается пакет для CentOS (я выбрал 7), то можно перейти сразу в соответствующий каталог.
Находим исходник вида nginx-<версия>.<отметка версии linux>.ngx.src.rpm и копируем на него ссылку:
* в моем примере мне нужен nginx версии 1.19.3.
С помощью скопированной ссылки загружаем исходник:
$ wget https://nginx.org/packages/mainline/centos/7/SRPMS/nginx-1.19.3-1.el7.ngx.src.rpm
Установим скачанный исходник командой:
$ rpm -Uvh nginx-1.19.3-1.el7.ngx.src.rpm
В каталоге rpmbuild/SOURCES появятся исходники для сборки нужной нам версии NGINX.
Собираем установочный RPM-пакет:
$ rpmbuild -bb rpmbuild/SPECS/nginx.spec
В каталоге rpmbuild/RPMS, в зависимости от архитектуры пакета создастся каталог. В моем примере полный путь до созданного пакета — rpmbuild/RPMS/x86_64. В нем мы должны найти 2 файла:
- nginx-1.19.3-1.el7.ngx.x86_64.rpm: пакет для установки.
- nginx-debuginfo-1.19.3-1.el7.ngx.x86_64.rpm: пакет для установки с отладочной информацией.
Пакет создан и готов к установке.
Установка, запуск и удаление
1. Для установки собранного пакета вводим команду:
rpm -Uvh <путь до собранного пакета>
* где rpm вводится с ключами:
- U — обновить, если пакет уже установлен в системе.
- v — вывод информации о ходе процесса.
- h — показывать статус установки.
Список всех ключей можно посмотреть командой rpm --help или man rpm.
Для выполнения данной команды мы должны скопировать на необходимый компьютер наш собранный пакет и зайти в систему под пользователем с правами на установку (как правило, при повышении привилегий до root).
В нашем случае команда будет такой:
rpm -Uvh nginx-1.19.3-1.el7.ngx.x86_64.rpm
* при этом мы должны находиться в каталоге, в котором разместили пакет RPM.
2. Для запуска nginx вводим команды:
systemctl enable nginx
systemctl start nginx
* Первая команда позволит нашему веб-серверу запускаться автоматически. Вторая запустит сервис.
Для проверки состояния сервиса вводим команду:
systemctl status nginx
Я столкнулся с 2-я разными проблема при запуске сервиса.
1) служба не стартовала, выдавая ошибку. В логе говорилось, что нет доступа к файлу /var/run/nginx.pid. Повторный запуск службы решил проблемы.
2) система выдавала ошибку «Unit nginx.service could not be found», которая говорит, что сервиса nginx не существует. Проблема решается вводом команды systemctl daemon-reload, которая перечитываем конфигурационные файлы для systemd.
3. Чтобы удалить пакет сначала запретив автозапуск сервиса и остановим его:
systemctl disable nginx
systemctl stop nginx
Смотрим полное название установленного в системе пакета:
rpm -qa | grep nginx
В моем случае это было:
nginx-1.19.3-1.el7.ngx.x86_64
Для удаления пакета вводим:
rpm -e nginx-1.19.3-1.el7.ngx.x86_64
Добавление модуля
Как говорилось выше, мы добавим модуль SPNEGO в нашу сборку. Для примера, мы будем использовать динамическое подключение данного модуля.
В моем примере необходимо клонировать проект из GIT-репозитория. Для этого необходимо установить одноименную утилиту:
yum install git
Теперь заходим под ранее созданным пользователем builder:
su - builder
Переходим в каталог для сборки. В нашем случае, это домашняя директория:
$ cd ~
Клонируем исходник модуля в директорию /tmp:
$ git clone https://github.com/stnoonan/spnego-http-auth-nginx-module.git /tmp/spnego-http-auth-nginx-module
Ранее мы уже скачивали исходники nginx, поэтому сразу открываем файл nginx.spec:
$ vi rpmbuild/SPECS/nginx.spec
Находим:
%define BASE_CONFIGURE_ARGS ...
После последнего --with-... добавим:
--add-dynamic-module=/tmp/spnego-http-auth-nginx-module
Находим
%description
После него добавляем:
%package module-spnego
Group: %{_group}
Requires: nginx = %{?epoch:%{epoch}:}%{main_version}-%{main_release}
Summary: nginx spnego module
%description module-spnego
Dynamic Spnego module for nginx.
После:
%build
... добавляем:
echo 'load_module "%{_libdir}/nginx/modules/ngx_http_auth_spnego_module.so";' \
> %{buildroot}%{_sysconfdir}/nginx/modules/spnego-http-auth-nginx-module.conf
Находим разделы %files и после них добавим:
%files module-spnego
%{_libdir}/nginx/modules/spnego-http-auth-nginx-module.conf
%{_libdir}/nginx/modules/ngx_http_auth_spnego_module.so
Запускаем сборку:
$ rpmbuild -bb rpmbuild/SPECS/nginx.spec
Для установки нам понадобится 2 RPM-пакета:
- nginx-1.19.3-1.el7.ngx.x86_64.rpm
- nginx-module-spnego-1.19.3-1.el7.ngx.x86_64.rpm
Оба эти пакета будут находиться в каталоге RPMS.
После установки пакета выполняем команду:
nginx -V
Среди полученных опций сборки мы должны увидеть нашу:
... --add-dynamic-module=/tmp/spnego-http-auth-nginx-module ...
Также мы должны будем отредактировать конфигурационный файл NGINX, чтобы наши модули подгружались:
vi /etc/nginx/nginx.conf
В корневой секции добавим:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
include /etc/nginx/modules/*.conf;
events {
...
* новая строчка отмечена красным.
Ниже по инструкции будет рассказано, как собрать пакет со своим конфигурационным файлом.
Изменение конфигурационного файла NGINX
Перед сборкой мы можем изменить конфигурационный файл веб-сервера, который уже попадет в наш установочный пакет. Так как мы рассматриваем пример работы с модулем spnego, внесем настройки для него.
Открываем файл:
$ vi rpmbuild/SOURCES/nginx.conf
Внесем следующие изменения:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
include /etc/nginx/modules/*.conf;
events {
...
* в нашем примере внесено всего 2 изменения:
- worker_processes, который отвечает за распределение нагрузки по ядрам уже давно рекомендуется выставлять в значение auto.
- Также мы дописали строку include /etc/nginx/modules/*.conf, которая укажет нашему веб-серверу подгружать все конфигурационные файлы из каталога modules.
Также активируем для сайта по умолчанию опцию для модуля spnego. Открываем файл:
$ vi rpmbuild/SOURCES/nginx.vh.default.conf
Это файл, который будет находиться по пути /etc/nginx/conf.d/default.conf. Внесем в него изменения:
location / {
root /usr/share/nginx/html;
index index.html index.htm;
auth_gss on;
auth_gss_realm DMOSK.RU;
auth_gss_keytab /etc/http.keytab;
auth_gss_service_name HTTP/test.dmosk.ru;
}
Пересобираем RPM:
$ rpmbuild -bb rpmbuild/SPECS/nginx.spec
Выполняем установку новых пакетов на целевом сервере. В нашем примере мы можем переустановить пакеты командами:
rpm -Uvh --force nginx-1.19.3-1.el7.ngx.x86_64.rpm
rpm -Uvh --force nginx-module-spnego-1.19.3-1.el7.ngx.x86_64.rpm
* напоминаю, что у нас используется версия 1.19.3. Чтобы данные команды отработали, необходимо находиться в каталоге, где лежат наши установочные файлы.
Мы должны увидеть изменения в конфигах, которые сделали до сборки.
Подписываем пакет
Установим на созданный файл цифровую подпись, чтобы можно было гарантировать на целевом для установки компьютере, что пакет собрали именно мы. Не все нижеописанные действия можно выполнять от пользователя builder (под которым собирался пакет nginx), поэтому мы будем что-то делать от root (в начале команды #), а что-то от builder ($).
Подпись пакета
Устанавливаем пакеты (от пользователя root):
# yum install rpm-sign pinentry
Генерируем ключ (уже от пользователя builder).
а) В CentOS 7:
$ gpg2 --gen-key
б) В CentOS 8:
$ gpg2 --full-gen-key
Система выкинет запрос, на который мы отвечаем 4 (RSA ключ только для подписи):
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(14) Existing key from card
Your selection? 4
Размер ключа можно оставить по умолчанию:
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
Мы можем указать период, в течение которого будет работать ключ или оставить значение 0 (бессрочно):
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Подтвердим корректность данных:
Is this correct? (y/N) y
Вводим данные для ключа, например:
Real name: DMOSK
Email address: rpm@dmosk.ru
Comment:
Подтверждаем корректность введенных данных:
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
Система запросит пароль — вводим дважды. Если мы увидим окно:
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
Необходимо выполнять различные действия, чтобы сгенерировалась последовательность. Просто открываем вторую сессию SSH и вводим команду:
dd if=/dev/sda of=/dev/zero
Ждем завершения генерации ключа. После его можно посмотреть командой:
$ gpg -K
Теперь открываем файл:
$ vi ~/.rpmmacros
И добавим:
%_signature gpg
%_gpg_name DMOSK
%_gpgbin /usr/bin/gpg2
%__gpg_sign_cmd %{__gpg} gpg --force-v3-sigs --batch --verbose --no-armor --no-secmem-warning -u "%{_gpg_name}" -sbo %{__signature_filename} --digest-algo sha256 %{__plaintext_filename}'
* где:
- _signature — указывает с помощью чего будет создаваться подпись.
- _gpg_name — имя ключа, которое мы указывали при его создании.
- _gpgbin — путь до исполняемого файла gpg.
- __gpg_sign_cmd — определяет команду, с помощью которой будет выполняться подпись пакета.
Можно подписывать пакет:
$ rpm --addsign rpmbuild/RPMS/x86_64/nginx-1.19.3-1.el7.ngx.x86_64.rpm
Система должна запросить пароль и подписать пакет.
Проверка подписи
На компьютере, где мы сгенерировали ключ, выполняем экспорт public key:
gpg2 -a --export DMOSK > RPM-GPG-KEY-dmosk
* где DMOSK — имя ключа; RPM-GPG-KEY-dmosk — файл, в который мы поместим открытый ключ.
В результате мы получим ключ RPM-GPG-KEY-dmosk. Переносим его на целевой компьютер, где выполняем проверку (например, с помощью WinSCP).
Импортируем ключ (нужны права root):
rpm --import RPM-GPG-KEY-dmosk
Проверяем подпись пакета:
rpm --checksig nginx-1.19.3-1.el7.ngx.x86_64.rpm
Мы должны получить что-то на подобие:
nginx-1.19.3-1.el7.ngx.x86_64.rpm: digests signatures OK