LINUX.ORG.RU

Как я управляю конфигурацией системы в Alpine Linux

 , ,


0

1

В этой статье я хотел бы рассказать о том, как управляю конфигурацией системных папок (/etc, /usr, etc) на своих машинах.

Для таких целей часто советуют применять инструменты вроде stow, ansible или разнообразных Docker Swarm с Kubernetes (для этих не хочу даже ссылки давать), но я их не использую.

Я создаю свои пакеты (для пакетного менеджера дистрибутива) и публикую их в своих репозиториях. Можно конечно заливать все нужные файлы руками по ssh (раньше я так и делал), но у пакетов есть важное преимущество: с их помощью легко не только добавлять или обновлять файлы, но и удалять их, и в целом контролировать, что есть в системе. Это предотвращает её захламление. В статье описано, как это делается для Alpine Linux (которым я пользуюсь на домашнем ПК) и, кратко, для Debian/Ubuntu.

Репозиторий в Alpine Linux

Этот раздел посвящен тому, как собрать свой пакет для Alpine Linux, опубликовать в локальном репозитории и установить его оттуда. В качестве подопытного использую dbin – менеджер пользовательских пакетов с ориентацией на статическую линковку и AppImage.

Сборка бинарника

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

$ tree -L 1 ./dbin 
./dbin
├── cache
├── dbin
├── install
├── nfpm.yaml
├── nfpm_template.yaml
└── package.sh

dbin/cache – кэш сборки; dbin/dbin – склонированный репозиторий; dbin/package.sh – скрипт, который собирает пакет и добавляет его в локальный репозиторий пакетов. Основная магия происходит в этом скрипте. Рассмотрим его.

Для начала надо установить переменные:

export REPO="${HOME}/packages/$( uname -m )"
export PROJ="$( basename ${PWD} )" # dbin

export PREFIX="${PWD}/install"
export GOPATH="${PWD}/cache"
export GOBIN="${PREFIX}/bin"

mkdir -p "${GOPATH}" "${GOBIN}"

REPO – расположение локального репозитория пакетов; PREFIX – папка, в которой будет сформировано дерево устанавливаемых файлов; GOPATH – путь к локальному кэшу (dbin написан на Go); GOBIN – папка, в которую команда go install устанавливает скомпилированные бинарники.

Далее переходим на актуальный тег в репозитории и, собственно, собираем dbin:

cd ${PROJ}
git fetch --tags
export TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
git switch --detach ${TAG}

go mod download -x
go install -ldflags "-s -w" -trimpath
cd ..

git switch – современная альтернатива git checkout для случаев, когда нужно перейти на ветку или коммит.

После этого в папке ./install появятся нужные файлы:

$ tree ./install 
./install
└── bin
    └── dbin

и можно приступать к сборке собственно пакета.

Side note. Слежение за тегами.

Как узнать, когда надо обновляться? GitHub формирует для проектов ленту с тегами в формате Atom. Для её получения надо просто прибавить tags.atom к адресу репозитория, например

https://github.com/xplshn/dbin/tags.atom

Далее эту ленту можно загрузить в читалку RSS, я пользуюсь Feeder для Android.

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

Для сборки пакета я пользуюсь nfpm. Во-первых им можно делать единообразные конфиги для нескольких дистрибутивов, во-вторых тулинг Debian и Ubuntu просто отвратителен. Конфиг nfpm для dbin выглядит примерно так:

name: "dbin"
arch: "amd64"
platform: "linux"
version: "${TAG}"
section: "default"
priority: "extra"
maintainer: "me"
description: |
  The easy to use, easy to get, suckless software distribution system.
vendor: "me"
homepage: "https://github.com/xplshn/dbin"
license: "ISC"
contents:
  - src: ${PREFIX}
    dst: /
    type: tree
    file_info:
      mode: 0755
apk:
  signature:
    key_file: ${PACKAGER_PRIVKEY}
    key_name: ${PACKAGER_PRIVKEY_NAME}

Наиболее важные метаданные здесь – это contents (содержимое пакета) и signature. Хоть это и не обязательно, но я подписываю пакет своим ключом, который сгенерирован с помощью утилиты abuild-keygen из состава Alpine Linux SDK. Это обычный RSA-ключ в формате PKCS#8. Его открытую часть нужно положить в /etc/apk/keys. Переменные PACKAGER_PRIVKEY* можно установить так:

source "${HOME}/.abuild/abuild.conf" # устанавливает ${PACKAGER_PRIVKEY}

export PACKAGER_PRIVKEY_NAME="$( basename ${PACKAGER_PRIVKEY} .rsa )"

Файл abuild.conf автоматически обновляется abuild-keygen при генерации ключа, редактировать его руками не нужно.

Открытая версия nfpm не поддерживает шаблоны. Поэтому я пользуюсь сторонним шаблонизатором, в данном случае envsubst из состава gettext. Эта утилита подставляет вместо имён переменных среды их значения, что мне и нужно. См. как устанавливается ${TAG} выше.

envsubst < nfpm_template.yaml > nfpm.yaml

Получив nfpm.yaml, генерируем apk-пакет:

nfpm pkg --packager apk --target $REPO/${PROJ}-${TAG}.0.apk

.0 в конце из-за того что Alpine ожидает, что у всех пакетов версии будут в формате x.y.z.

После того как пакет попал в репозиторий, остаётся только обновить индекс пакетов и подписать этот индекс своим ключом:

apk index -vU -o APKINDEX.tar.gz *.apk
abuild-sign -k ${PACKAGER_PRIVKEY} APKINDEX.tar.gz

Установка пакета

Для установки пакета нужно, во-первых, добавить в систему использованный для подписи ключ. Это делается опять же с помощью abuild-keygen, но никто не запрещает скопировать файл .rsa.pub в /etc/apk/keys руками.

Во-вторых, нужно добавить локальный репозиторий в список репозиториев:

echo @my ${HOME}/packages/ >> /etc/apk/repositories

маска @my тут применяется, чтобы не было конфликтов имен с пакетами из уже имеющихся репозиториев. Обновляем кэш пакетов и смотрим информацию:

$ doas apk update
$ apk info dbin
dbin-1.5.0 description:
The easy to use, easy to get, suckless software distribution system.

dbin-1.5.0 webpage:
https://github.com/xplshn/dbin

dbin-1.5.0 installed size:
10 MiB
$ doas apk add dbin@my
$ cat /etc/apk/world | grep dbin # проверяем в списке пакетов
dbin@my
$ dbin list | wc -l
4053

С помощью этой штуки можно поставить 4053 пакета, на данный момент. Среди которых, впрочем, куча всяких AppImage из Nix и в целом нет ничего нужного мне. Так что…

$ doas apk del dbin
$ rm -rf ${PROJ}

Репозиторий в Debian/Ubuntu

В целом процедура его поднятия аналогична репозиториям Alpine: мы создаем с помощью nfpm набор deb-пакетов, генерируем индекс с помощью утилиты dpkg-scanpackages, записываем хэш этого индекса в файл с метаданными репозитория (файл Release), и подписываем, храня подпись либо в отдельном файле (Release.gpg), либо прямо по месту (файл InRelease) – последний способ рекомендуется.

Но дальше начинаются детали, расписывать которые у меня нет никакого желания. Например, оно использует GnuPG вместо PKCS#8 и допускает дублирование имён пакетов в разных репозиториях. Для разрешения конфликтов введён механизм приоритетов, при этом APT плевать хотел на этот механизм, когда дело касается репозиториев из /etc/apt/sources.list.d/ubuntu.sources, пакеты оттуда всегда выбираются первыми.

Уже жду, как они гордо заменят GnuPG (разработчики которого кстати выпилили возможность запускаться как пользовательский сервис под супервизором) на безопасно переписанный на Rust Sequoia. Не ну а что, sudo-rs у них уже есть.

В результате получается набор статических файлов, на который я натравливаю nginx (не вижу, почему бы благородным донам не использовать nginx), после чего пробрасываю получившийся порт при подключении к серверу по ssh:

# ~/.ssh/config
  RemoteForward 7777 localhost:7777

и прописываю на сервере в качестве адреса репозитория http://localhost:7777. Дальше – всё по классике, apt install/update/remove.

Заключение

Всё это может показаться сложным, но на самом деле эти скрипты нужно написать только один раз, и потом просто копировать с минимальными изменениями. Которые заключаются по сути только в сборке и преобразовании тегов репозитория в правильный номер версии для каждого нового пакета.

Также, надеюсь, стало понятно, почему я пользуюсь Alpine Linux. При работе с ним постоянно натыкаешься на простые и понятные решения, сделанные для людей, а не для корпораций, которым важно чтобы пользователи скачивали пакеты из каких надо репозиториев.

★★★★★

Проверено: dataman ()
Последнее исправление: dataman (всего исправлений: 3)

Твоя проблема решается установкой арчика, где уде есть минималистичный (не как в дебиан) пакетный менеджер. Собственные баш-костыли не нужны.

ox55ff ★★★★★
()

А какая главная цель?

rtxtxtrx ★★★
()

системных папок

Системных мамок!

//шучу

Спасибо, интересно было почитать.

Zhbert ★★★★★
()
Ответ на: комментарий от rtxtxtrx

но по тексту он какой-то бинарь собирает на голанге!!! и про назначение бинаря непонятно в контексте управления конфигами

irton ★★★★★
()
Ответ на: комментарий от irton

Я создаю свои пакеты (для пакетного менеджера дистрибутива) и публикую их в своих репозиториях.

Пакет, видимо, с софтиной на голанге, для которой есть еще и конфиги, о паковании которых и идёт речь дальше.

Zhbert ★★★★★
()

Конфиги… опакечивать…
Понятно что это тоже IaC, но…

А что если твой пакет будет установлен перед другим пакетом, дефолт которого твой пакет переопределяет?

mord0d ★★★★★
()
Ответ на: комментарий от sanyo1234

есть команда apk verify, проверяющая целостность пакета. Для уже установленных файлов - только руками

Lrrr ★★★★★
() автор топика
Ответ на: комментарий от irton

А где управление конфигами?

под конфигурацией я понимаю в том числе и установленные программы. Файлы конфигов закидываю в пакеты ровно по той же схеме.

к вопросу

А что если твой пакет будет установлен перед другим пакетом, дефолт которого твой пакет переопределяет?

у нормального софта (99% того чем я пользуюсь) предусмотрены папки .d и прочее подобное.

Lrrr ★★★★★
() автор топика
Последнее исправление: Lrrr (всего исправлений: 1)
Ответ на: комментарий от Zhbert

В этой статье я хотел бы рассказать о том, как управляю конфигурацией системных папок (/etc, /usr, etc) на своих машинах.

где вот про это вот все?

irton ★★★★★
()

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

somemong
()

А где управление конфигурацией? Главная задача cm это убедиться, что в любой момент времени у тебя система приведена к определенному состоянию с минимумом дрифта, как это проявляется тут? Написанием пачки одноразовых баш скриптов которые как проверяют идемпотентность? Короче автор перепутал пупу с лупой. Это было сразу понятно, когда я увидел про K8s и swarm которые вообще отношения к конфигурации не имеют.

Zlogene ★★
()
Последнее исправление: Zlogene (всего исправлений: 1)
Ответ на: комментарий от Zlogene

гарантий команд вроде sudo apt-get install мне вполне достаточно.

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

Lrrr ★★★★★
() автор топика
Ответ на: комментарий от Nurmukh

Не ври, ты вообще не читал, потому что ansible упоминается в самом начале 🫠

Lrrr ★★★★★
() автор топика
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.