Готовим deb из наших бинарников

16 minute read

Go прекрасный язык. Одна из его супер-сил - это возможность собирать все в один бинарник. А это очень удобно, вы можете везде таскать этот файл и использовать на любой машине. Но хочется иметь возможность устанавливать нашу программу простым способом.

С помощью deb пакетов довольно просто можно организовать деплой на ваши сервера. При этом у вас будет версионирование и все такое. Я чаще всего использую ubuntu, поэтому речь будет именно о deb пакетах, которые можно установить/удалить с помощью утилит apt.

Что же нужно сделать, для создания своего репозитория с пакетами? Можно воспользоваться тем же launchpad.net, например. Но, последнее время, он не очень развивается и выглядит ненадежно. К тому же, его удобно использовать для своих не коммерческих разработок, но использовать его для дистрибуции корпоративного ПО будет проблематично.

Подойдем к проблеме с другой стороны. Во первых, нам нужно собирать deb пакеты, а это очень просто сделать самим с помощью утилиты dpkg-deb. Во-вторых, нам нужно где-то эти пакеты размещать, и для этого мы воспользуемся супер простым сервером apt репозиториев deb-simple

Сборка пакетов

Для всех своих проектов я использую gb. Структура проекта выглядит примерно так:

project/
 |- bin/
 |      |- project
 |- src/
 |      |- github.com/
 |          |- 4gophers/
 |              |- project/
 |                 |- main.go
 |- vendor/

Когда я запускаю gb build, то все бинарники собираются в папке bin. Таким образом, все что нам нужно - это просто добавить спецификацию нашего будущего deb пакета прям в папку с проектом:

mkdir project/DEBIAN
touch project/DEBIAN/control

В результате будет такая структура:

project/
 |- DEBIAN/
 |      |- control
 |- bin/
 |      |- project 
 |- src/
 |- vendor/

В файле control нужно указать информацию о нашем пакете. Не забывайте про пустую последнюю строку:

Package: project
Priority: optional
Section: devel
Installed-Size: 100
Maintainer: Ivan Ivanov <test@test.ru>
Architecture: i386
Version: 1.0
Depends: libc6 (>= 2.1)
Description: Short description here
 Long description here

  • Package — имя вашего пакета
  • Priority — приоритет пакета (optional, extra, standard, important, required) для обычных программ лучше ставить optional
  • Section — раздел к которому относится данный пакет (admin, base, comm, contrib, devel, doc, editors, electronics, embedded, games, gnome, graphics, hamradio, interpreters, kde, libs, libdevel, mail, math, misc, net, news, non-free, oldlibs, otherosfs, perl, python, science, shells, sound, tex, text, utils, web, x11)
  • Installed-Size — размер файлов пакета в килобайтах
  • Maintainer — имя и email создателя пакета
  • Architecture — архитектура процессора, для которой предназначен пакет (i386, amd64, all, source, all)
  • Version — версия пакета
  • Depends — в данном поле необходимо указать имена пакетов, от которых зависит ваш пакет (например, библиотеки)
  • Description — в первой строке пишем короткое описание пакета, в остальных более подробно

Все что находится в папке project попадет в пакет. И папка bin тоже. В этой папке лежит наш бинарный файл, который нужно установить. Чтобы ваши файлы оказались в нужной директории на компьютере пользователя, нужно создать соответствующую структуру каталогов внутри вашей папки с проектом.

Стоит отметить, что такой подход к созданию deb пакетов не самый правильный. Конечно, в нашем случае мы осознанно идем на этот шаг, но вам нужно понимать, что в deb пакет попадет все содержимое папки project, в том числе папки src, vendor и так далее. Конечно, можно скопировать файлы в другую папку, и даже написать скрипт для этого, но все уже придумано до нас. Более правильный способ - это использовать утилиты dh_make и dpkg-buildpackage.

Теперь можно собирать пакет. Для этого на уровень выше выполним команду:

dpkg-deb -z8 -Zgzip --build project

На уровень выше будет создан файл project.deb, который можно устанавливать с помощью команды:

sudo dpkg -i project.deb

Больше информации о правильной сборке deb пакетов можно узнать в официальной документации.

Свой репозиторий пакетов

Теперь переходим к самому интересному. Как же нам распространять наши пакеты? Запустим свой сервер репозиториев, конечно же. А для этого воспользуемся сервером apt репозиториев deb-simple.

Это действительно простой сервер, который устанавливается всего одной командой:

go get github.com/esell/deb-simple

Если go не установлен на той машине, где вы собираетесь запустить сервер с репозиториями, то вы можете собрать бинарник локально и просто скопировать его. Кроме этого, можно использовать docker.

Затем нужно запустить сервер. Это можно сделать с помощью docker, но мне больше нравится использовать supervisord. Вот пример моей конфигурации сервиса:

[program:deb-simple]
command=/home/user/go1.5/bin/deb-simple
directory=/home/user/deb-simple/
autorestart=true
stdout_logfile=none

Тут важно указать путь к бинарнику(command) и рабочую папку(directory), в которой мы разместим наш конфиг.

Сервер deb-simple поддерживает https, но пока нам это не нужно. Для репозиториев нужно создать папку repo. Наш конфиг conf.json будет выглядит так:

{
    "listenPort" : "9090",
    "rootRepoPath" : "/home/user/deb-simple/repo",
    "supportedArch" : ["all","i386","amd64"],
    "enableSSL" : false,
    "SSLcert" : "server.crt",
    "SSLkey" : "server.key"
}

Чтобы загрузить пакет в свой репозиторий, нужно воспользоваться HTTP API самого сервиса:

curl -XPOST 'http://localhost:9090/upload?arch=amd64' -F "file=@project.deb"

Точно так же для удаления:

curl -XDELETE 'http://localhost:9090/delete' -d '{"filename":"project.deb","arch":"amd64"}'

Нам осталось добавить наш сервер репозиториев к списку в /etc/apt/source.list.d/. Можно создать отдельный файл с содержимым:

deb http://my-hostname:9090/ stable main

Теперь запускайте sudo apt-get update и устанавливайте свои программы сколько душе угодно.