В жизни любого развивающегося проекта рано или поздно (и лучше рано) наступает момент, когда эксплуатация многозначительно смотрит на разработку и предлагает оформить отношения. Дальнейшее развитие событий, как водится, зависит от обеих сторон. О плохом сегодня не будем, рассмотрим сразу случай, когда разработка готова использовать нехитрый инструментарий сборки пакетов, подготовленный для нее эксплуатацией (шаблоны debian/rules и debian/control, команды fakeroot, debuild, и так далее). Осталась самая малость: поднять для собранных пакетов собственный репозиторий.


Поскольку изучения интернетов внезапно показали, что тема, хоть и освещалась, и даже на Хабре, вряд ли может считаться внятно раскрытой, попробуем восполнить этот пробел.


Для начала нам потребуется ключ, которым будет подписан репозиторий. В данном примере мы создаем RSA-ключ длиной 4096 бита, который не имеет срока давности:


$ sudo apt install gpg
$ gpg --gen-key
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)
Your selection? 4

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits

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) 0

Key does not expire at all
Is this correct? (y/N) y

You need a user ID to identify your key; the software constructs the user ID from the Real Name, Comment and Email Address in this form:
      "Zaphod Beeblebrox (Galactic President) <zbeeblebrox@pres.galaxy.com>"

Real name: SnakeOil Admin
Email address: admin@snakeoil.org
Comment:

You selected this USER-ID:
      "SnakeOil Admin <admin@snakeoil.org>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

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


$ export PUBKEY_ID=`gpg --list-keys | awk '( $1 == "pub" ) { print $2 ; exit }' | cut -f 2 -d /`
$ gpg --output keyFile --armor --export $PUBKEY_ID

Пора подготовить дерево репозитория. У нас есть только один дистрибутив Ubuntu, только Intel x86_64 и нет пакетов с исходным кодом, поэтому о создании других элементов дерева мы не беспокоимся. Если пакеты собираются под разные дистрибутивы и имеют разные зависимости, дерево получится более развесистым, да и помянутые ниже правила сборки усложнятся.


$ sudo mkdir -p /var/www/repo
$ sudo mv keyFile !$
$ cd !$
$ sudo mkdir -p conf contrib/binary-amd64 dists/xenial

Создадим файл конфигурации репозитория:


$ sudo cat > /var/www/repo/conf/distributions <<EOF
Origin: SnakeOil
Label: SnakeOil private Ubuntu repo
Codename: xenial
Architectures: amd64
Components: contrib
Description: Our own and 3rd party software packaged internally
EOF
$ sudo echo SignWith: $PUBKEY_ID >> /var/www/repo/conf/distributions

Пора настроить автоматическое обновление репозитория при появлении в нем новых пакетов. Файл InRelease со встроенной подписью запрашивается новыми пакетными менеджерами, а связка из двух файлов Release и Release.gpg нужна старым. Зависимости нужно продублировать для всех дистрибутивов, которые вы планируете поддерживать.


$ sudo cat > /var/www/repo/Makefile <<EOF
#!/usr/bin/make
#
# Update the repository every time when a new package arrives

all: repo

repo: dists/xenial/InRelease dists/xenial/Release.gpg

dists/xenial/InRelease: dists/xenial/Release
        gpg --clearsign --digest-algo SHA512 -o dists/xenial/InRelease.new dists/xenial/Release
        mv dists/xenial/InRelease.new dists/xenial/InRelease

dists/xenial/Release.gpg: dists/xenial/Release
        gpg -abs -o dists/xenial/Release.gpg-new dists/xenial/Release
        mv dists/xenial/Release.gpg-new dists/xenial/Release.gpg

dists/xenial/Release: conf/distributions contrib/binary-amd64/Packages.gz
        cat conf/distributions > dists/xenial/Release
        apt-ftparchive release . >> dists/xenial/Release

contrib/binary-amd64/Packages.gz: contrib/binary-amd64/Packages
        gzip --keep --force -9 ../../contrib/binary-amd64/Packages

contrib/binary-amd64/Packages: contrib/binary-amd64/*.deb
        dpkg-scanpackages contrib/binary-amd64 > contrib/binary-amd64/Packages.new
        mv contrib/binary-amd64/Packages.new contrib/binary-amd64/Packages
EOF

Репозиторий готов, осталось настроить попадание всех вновь создаваемых пакетов в /var/www/repo/dists/xenial/contrib/binary-amd64 (за рамками данной статьи). Однако много ли проку от репозитория, если он сугубо локальный? Надо обеспечить его доступность по HTTP:


$ sudo apt install nginx
$ sudo cat > /etc/nginx/sites-available/repo.conf <<EOF

 server {
   listen 80;
   server_name repo repo.snakeoil.org;

   location ~ /(.*)/conf {
      deny all;
   }

   root /var/www/repo;
 }
EOF
$ sudo ln -s /etc/nginx/sites-available/repo.conf /etc/nginx/sites-enabled/
$ sudo service nginx restart

И, наконец, прописываем свой репозиторий на клиентах:


$ wget -O - http://repo/keyFile | sudo apt-key add -
$ sudo echo 'deb [arch=amd64] http://repo/ xenial contrib' > /etc/apt/sources.list.d/mylovelyrepo.list
$ sudo apt update

Сеанс черной магии с разоблачением окончен, всем спасибо за внимание.

Поделиться с друзьями
-->

Комментарии (35)


  1. grossws
    25.11.2016 19:30
    +2

    wget -O — http://repo/keyFile | sudo apt-key add -

    За такое хочется бить по рукам. Добавлять в доверенные ключ полученный по http вредно. Возьмите letsencrypt и настройте https для отдачи ключа или расположите его на доверенном сервере, доступном по https.


    1. sleeply4cat
      25.11.2016 21:46

      В локальной сети можно и http, наверное.


      1. grossws
        26.11.2016 02:30
        +3

        Тогда не нужны и подписи, можно подключать репозиторий так deb [trusted=yes] http://repo/ xenial contrib и не париться.


  1. kt97679
    25.11.2016 21:44
    +1

    Некоторое время назад мне понадобилось поднять репозиторий пакетов для убунту и центоса. Готовых решений под мои требования не нашлось, как следствие появилось вот это: https://github.com/hulu/urepo


    1. grossws
      26.11.2016 02:32

      С rhel/centos обычно проблемы-то и нет, дёрнуть createrepo да и выставить директорию по http.


      1. kt97679
        26.11.2016 06:29

        urepo именно это и делает


  1. bogolt
    25.11.2016 22:06

    А что насчет сборки под разные дистрибутивы и архитектуры? Есть ли для этого какие-то удобные решения ( помимо того что поднимаем по виртукалке под каждую убунту, собираем, и выкладываем )?


    1. Emily_Rose
      25.11.2016 22:34

      1. nightvich
        25.11.2016 22:49

        http://openbuildservice.org/


      1. akamensky
        28.11.2016 18:20

        Была бы возможность поставил бы здоровый плюс. Сейчас активно fpm использую в нашей компании, собираем 30+ пакетов с его помощью на одной машине сразу для yum и apt и никакой мороки с specfile и прочим.

        Одно только проблема это написание хуков которые бы работали сразу с всеми менеджерами (yum ,dnf, apt-get).


    1. nightvich
      25.11.2016 22:37
      +1

      Идеального варианта сейчас нет. Оптимальным вариантом является использование контейнеров. Позволяет решить вопрос декларативности окружения для сборки. Да и ресурсов требуется меньше, чем для виртуалок. Вообще тема крайне интересная, хотя специалистов по данной тематике не так много.


    1. kt97679
      25.11.2016 22:57
      +1

      Я использую chroot. Хост система убунту, chroot среду собираю для разных версий убунту и центоса. Работает даже экзотический вариант, когда на 64-битной хост убунте собираются 32-битные пакеты для центоса.


  1. iborzenkov
    25.11.2016 22:58

    а чем reprepro не устроил?


    1. kt97679
      25.11.2016 23:19

      Когда я на него смотрел некоторое время назад у него не было возможности хостить несколько версий одного пакета.


      1. eisaev
        28.11.2016 18:20

        Я из-за этой особенности перешёл на mini-dinstall.


    1. Erelecano
      26.11.2016 01:10

      Зашел задать тот же вопрос. Много лет его использовал, был всем доволен.


    1. dburmistrov
      28.11.2016 18:20

      У reprepro, на мой взгляд, есть два существенных недостатка:
      — не умеет хранить несколько версий одного пакета в рамках одного Suite/Component
      — при попытке добавить пакет версии ниже существующей, молча скипает с exitcode 0


  1. istui
    26.11.2016 00:06

    А есть такой же мануал для CentOS?


    1. grossws
      26.11.2016 02:48

      rpm --addsign some-package-x.y.z-1.el6.rpm или rpmbuild -ba --sign path/to/package.spec + createrepo /path/to/repo требуют отдельного howto?


      Есть, например, Fedora RPM Guide, где подробно описано как сгенерировать ключи и подписывать пакеты.


      1. istui
        26.11.2016 19:25
        +1

        Да, иногда требуют:) это не моя специализация, поэтому было бы намного проще, если бы был пошаговый мануал вида: собираем программу из исходников — делаем из нее пакет — создаем репозиторий — настраиваем его на других машинах — автоматизируем скачивание исходников и сборку их с нужными опциями

        За ссылки спасибо, но полный мануал все же был бы лучше.


        1. grossws
          26.11.2016 21:31
          +1

          Fedora RPM Guide и представляет собой полный мануал, который рассказывает об rpm, как оно устроено, как пишутся spec-файлы, какие есть триггеры и т. п.


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


    1. nightvich
      26.11.2016 22:44

      Есть, спросите у Google.


  1. YourChief
    26.11.2016 00:39
    +1

    dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz
    


  1. MeGaPk
    26.11.2016 00:59
    +2

    есть еще клевая утилита aptly, сам её юзал и буду юзать :).


    1. olegbukatchuk
      28.11.2016 18:20

      Присоединяюсь! К тому же Aptly позволяет создавать сколько угодно репозиторием в рамках одной установки. Очень удобно.


  1. beTrue
    26.11.2016 18:36
    -2

    статья про шелл скрипт на треть экрана, но спасибо.


  1. rudenkovk
    26.11.2016 21:40
    +1

    контейнеры-шмонтейнеры. Описанный в статье вариант. Не решает частного варианта dependency hell в виде персборки при изменении зависимостей.


    1. nightvich
      26.11.2016 22:52

      Описанный вариант даже не затрагивает этого момента. Если у вас есть опыт решения данной задачи, расскажите, как вы это делаете?


      1. rudenkovk
        27.11.2016 09:02
        +2

        Для пакетов у меня стоит OBS (open build service), они решили вопрос сборки пакетов в docker, и стало возможным убрать в приватное облако.
        С контейнерами сложнее, я сократил количество базовых контейнеров до минимума и сам прописал между ними связи.


        1. nightvich
          28.11.2016 15:05

          У нас сейчас используется самописная сборочная система, я тоже смотрю OBS, но пока не решился на попытку перебраться на него. Я собираю порядка 30+ пакетов из 60+ компонентов со сложным деревом зависимостей в рамках одного продукта.


          1. rudenkovk
            28.11.2016 15:08

            Попытка что-то написать у меня была, но света в конце туннеля я не увидел. Как раз в тот же момент OBS нормально научился собирать в докере.


            Я даже не стал себе ломать голову, поддерживаю 1 машину с opensuse. Есть мысли обернуть запуск OBS демонов в какой-нибудь runit/supervisord и сделать докер образ.


  1. Icewild
    28.11.2016 18:20

    https://www.aptly.info/


  1. Hissing_Bridge
    28.11.2016 18:21

    ```sudo cat > /var/www/repo/Makefile <<EOF``` работать не будет. `sudo` запустить `cat` с повышенными привелегиями, а перенаправление ведется в шел, где привилегий нет. используйте ```sudo sh -c '...'```


    1. eisaev
      28.11.2016 19:09

      Ну или как вариант:

      cat << EOF | sudo tee -a /var/www/repo/Makefile
      


  1. Faunris
    28.11.2016 18:21

    Мы храним локальное зеркало репы debian (благодаря этому получаем профит по скорости локальной сборки пакетов). Само зеркало делаем утилитой ftpsync.
    А для хранения своих пакетов используем aptly. Он предоставляет очень удобное API для загрузки и публикации пакетов в репе. И не надо делать кучу магических скриптов :)