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

Обновлено Обновлено: Опубликовано Опубликовано:

Если нам нужно часто устанавливать свои пакеты, у нас может уходить много времени на их конфигурирование и сборку. Мы рассмотрим процесс того, как сделать RPM-пакет для установки на дистрибутив Linux одноименного семейства (например, CentOS или Red Hat). В качестве примера мы соберем NGINX с модулем SPNEGO. Это будет сделано поэтапно — сначала мы соберем простой пакет, потом добавим в него модуль и внесем изменения в конфигурационный файл.

Подготовка системы

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 — а в ней:

  1. BUILD — содержит все файлы, которые появляются при создании пакета.
  2. RPMS — сюда будут складываться готовые пакеты.
  3. SOURCES — для исходников, из которых и будут собираться RPM-пакеты.
  4. SPECS — для файлов с описанием процесса сборки.
  5. SRPMS — для исходников RPM-файлов.

Мы готовы к загрузке исходника и его подготовке.

Загрузка исходника и сборка RPM

На странице загрузки пакетов NGINX мы можем найти пакеты для нужной нам операционной системы. Так как в нашем примере собирается пакет для CentOS (я выбрал 7), то можно перейти сразу в соответствующий каталог.

Находим исходник вида nginx-<версия>.<отметка версии linux>.ngx.src.rpm и копируем на него ссылку:

Копируем ссылку для загрузки исходника NGINX

* в моем примере мне нужен 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 файла:

  1. nginx-1.19.3-1.el7.ngx.x86_64.rpm: пакет для установки.
  2. 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-пакета:

  1. nginx-1.19.3-1.el7.ngx.x86_64.rpm
  2. 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 изменения:

  1. worker_processes, который отвечает за распределение нагрузки по ядрам уже давно рекомендуется выставлять в значение auto.
  2. Также мы дописали строку 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

# CentOS # DevOps # NGINX # Операционные системы
Дмитрий Моск — частный мастер
Была ли полезна вам эта инструкция?

Да            Нет