Сборка собственного пакета для Debian или Ubuntu решает несколько задач: установка программы без make install, обновления через apt, контроль зависимостей и возможность поделиться сборкой. Разберём процесс через dpkg-buildpackage, автоматическую сборку в изолированной среде и публикацию локального репозитория.
Структура пакета
Исходники пакета описывает каталог debian/: в нём лежат правила сборки, описание, контроль зависимостей и чangelog. Это есть у любого исходного пакета Debian.
# минимальная структура
mytool-1.0/
├── debian/
│ ├── control # описание и зависимости
│ ├── rules # Makefile сборки
│ ├── changelog # история версий
│ └── install # куда класть файлы
└── src/
# посмотреть пакет существующей программы
apt source hello 2>/dev/null || apt-get source hello
ls hello-*/debian/
Начинайте с копирования debian/ у простого пакета-аналога: так меньше шансов ошибиться.
Файл control
# debian/control
Source: mytool
Section: utils
Priority: optional
Maintainer: admin <admin@example.com>
Build-Depends: debhelper-compat (= 13), golang-any
Standards-Version: 4.6.0
Package: mytool
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: краткое описание утилиты
Полное описание: что делает и зачем нужно.
Строка Depends: ${shlibs:Depends} подставит автоматически вычисленные библиотечные зависимости. Без неё пакет установится, а программа не запустится на чистой системе.
Сборка
# установить инструменты
sudo apt install build-essential debhelper devscripts dh-make
# запустить сборку из каталога с исходниками
cd mytool-1.0
dpkg-buildpackage -us -uc -b
# результат — на уровень выше
ls -lh ../*.deb ../*.buildinfo 2>/dev/null
Флаги -us -uc отключают подпись (нужна GPG-пара для публикации), -b означает бинарную сборку без пакета исходников.
# проверить содержимое
dpkg -c ../mytool_1.0_amd64.deb | head -20
# метаданные
dpkg -I ../mytool_1.0_amd64.deb
Изолированная сборка через pbuilder
На рабочей машине сборка может подхватить случайно установленные библиотеки. pbuilder собирает пакет в чистом окружении — так получается воспроизводимый результат.
sudo apt install pbuilder debootstrap
# создать базовый образ (один раз)
sudo pbuilder create
# сборка в чистой среде
sudo pbuilder --build ../mytool_1.0.dsc
# результат в /var/cache/pbuilder/result/
ls -lh /var/cache/pbuilder/result/
Если сборка падает с «не найдена зависимость», проблема видна сразу — в рабочем окружении она бы замолчала.
Установка и проверка
# локальная установка
sudo dpkg -i ../mytool_1.0_amd64.deb
sudo apt -f install # подтянуть недостающие зависимости
# проверить
mytool --version
dpkg -L mytool # какие файлы установлены
dpkg -s mytool | head # статус и версия
# удаление
sudo apt purge mytool
Локальное репозиторий
Чтобы apt видел пакет и подтягивал обновления, разместите его в каталоге и опишите как раздел репозитория.
# структура репозитория
mkdir -p /srv/repo/deb
cp ../mytool_*.deb /srv/repo/deb/
cd /srv/repo/deb && dpkg-scanpackages . /dev/null | gzip -9 > Packages.gz
# на клиентах: sources.list
# deb [trusted=yes] http://repo.local/deb ./
sudo apt update
apt policy mytool
Для публичного распространения подпишите репозиторий ключом GPG: dpkg-scanpackages и gpg --detach-sign в паре дают проверяемость пакетов.
Типичные ошибки
- Отсутствует
${misc:Depends}— ломаются служебные скрипты. - Неправильные права на файлы:
debian/installуказывает на/usr/localвместо/usr. - Сборка «на живой» машине даёт невоспроизводимый результат.
- Нет
changelog— сборка завершается ошибкой. - Пакет не удаляется чисто: не прописан
postrm.
# проверить качество пакета
lintian ../mytool_1.0_amd64.deb 2>&1 | head -30
# просмотреть ошибки сборки в журнале
grep -iE "error|fail" ../mytool_1.0_amd64.build | head -20
Обновление версии пакета
При выходе новой версии программы обновляются debian/changelog, номер в debian/control и, если нужно, патчи. Debian требует соблюдения формата changelog — без него сборка не запустится.
# создать новую запись
dch -v 1.1-1 --package mytool "исправлена ошибка с конфигурацией"
# или вручную отредактировать debian/changelog
head -12 debian/changelog
# проверить формат
linda --linda debian/changelog 2>/dev/null || echo "проверьте синтаксис"
# сборка новой версии
dpkg-buildpackage -us -uc -b
Соблюдайте смысл версии: если изменился только пакет, увеличивайте третью часть ревизии (1.0-2); если сама программа — вторую (1.1-1).
Автоматическая сборка
Когда пакетов становится несколько, ручная сборка превращается в рутину. Простейший вариант — скрипт, который запускает pbuilder и складывает результаты в репозиторий.
#!/bin/bash
# /usr/local/bin/build-all.sh
set -euo pipefail
REPO=/srv/repo/deb
mkdir -p "$REPO"
for dsc in ../src/*.dsc; do
sudo pbuilder --build "$dsc" --results "$REPO"
done
cd "$REPO" && dpkg-scanpackages . /dev/null | gzip -9 > Packages.gz
echo "репозиторий обновлён: $(ls -1 *.deb | wc -l) пакетов"
Добавьте запуск по расписанию или по событию в системе непрерывной сборки, а результаты подписывайте ключом GPG.
Требования к структуре файлов
- Исполняемые файлы попадают в
/usr/bin, а не в/usr/local/bin— управляется apt. - Конфигурации помечаются как
conffiles, чтобы пользовательские правки сохранялись. - Служебные скрипты systemd укладываются в
debian/mytool.service. - Документация — в
debian/docs, man-страницы — черезdh-installman.
# что реально попало в пакет
dpkg -c ../mytool_1.1_amd64.deb | head -30
# конфигурационные файлы
dpkg -s mytool | grep -A5 "Conffiles"
Публикация и обновления для пользователей
Чтобы другие машины получали ваши обновления через apt upgrade, нужен подписанный репозиторий и строка в источниках пакетов.
# подпись метаданных
cd /srv/repo/deb
dpkg-scanpackages . /dev/null > Packages
gzip -9 -c Packages > Packages.gz
gpg --detach-sign --armor Packages.gz
# на клиенте
# deb [signed-by=/usr/share/keyrings/my.gpg] http://repo.local/deb ./
sudo apt update
apt policy mytool
Проверьте обновление на одной тестовой машине прежде чем открывать репозиторий для всего парка.
Итог
Сборка пакета — это debian/control с зависимостями, dpkg-buildpackage для сборки, pbuilder для чистого окружения и lintian для проверки качества. Готовый .deb устанавливается через apt вместе с зависимостями, а локальный репозиторий превращает ваши сборки в обычный канал обновлений.