Runit уже много лет пленяет пылкие сердца и умы любителей прекрасного и если вас тоже подташнивает от коричневых оттенков мэйнстримных облаков, то слушайте. Я расскажу о своём опыте использования runit в режиме native boot, который делает lightweight контейнеры по-настоящему lightweight.

Ведь как я делал раньше? Деплоил контейнер debian, отключал мерзкий бинарный лог в /etc/systemd/journald.conf, потом ставил вменяемый rsyslog, который тянул logrotate и cron, а потом выискивал свои крошечные поделки в списке процессов среди всех этих systemd, cron, rsyslogd, agetty - вот этот agetty я вообще победить не мог.

Вас бы не задолбало такое безобразие? Я-то терпеливый, но и меня тоже достало.

Devuan. Только Devuan.

А про native boot в runit вообще ни один из известных мне поисковиков ничего не может сказать, и никаких упоминаний нет на wiki всех этих gentoo, void, artix, где runit активно используется. И даже на этом сайте ни слова, хотя поиск по runit весьма познавателен, если отфильтровать весь спам про лошадиный спорт.

Увы, у всяких медалей есть обратная сторона. В данных мне ощущениях реальности, Devuan вообще забил на шаблоны LXC для себя любимого. Но не беда. Как говорится, даже если вас съели, то всё равно есть два выхода: 1) шаблон можно нарыть в интернетах, например:

и 2) у нас есть божественный debootstrap. Этот вариант мне больше нравится - всё в моих руках и под полным контролем. Если коротко, то бутстрапим систему в например /var/lib/lxc/devuan/rootfs, потом создаём config, потом запускаем контейнер - и вуаля - радуемся. Только перед вуаля надо чуточку поколдовать. С этого и начнём, а если кто про debootstrap слышит первый раз - тогда читайте эту заметку с конца.

Системы инициализации кроме мэйнстримной, с контейнерами не дружат совсем, поэтому приходится прибивать кучку ненужных сервисов. Вы это можете наблюдать в шаблонах, что я привёл выше (кстати, они удивительно похожи, где первоисточник?) Но даже то, как делают там, - недостаточно. Более того, sysvinit вообще для контейнеров не годится без серьёзных доработок. Runit - да, но она запускает скрипты из /etc/rcS.d и /etc/rc2.d на старте и из /etc/rc6.d при завершении работы. Гадят, в основном, вот эти:

  • hwclock.sh: на старте ничего не делает - там рулит udev, но при завершении работы пытается прописать время в hardware clock

  • bootlogs: пытается писать /var/log/dmesg, от которого в контейнерах только вред. Не забывайте прописывать на хосте kernel.dmesg_restrict = 1 в /etc/sysctl.conf.

  • umountfs: как вы видели, в шаблонах контейнеров этот сервис безуспешно пытаются прибить, я бы добавил umountroot, поскольку верю, что всем этим рулит LXC. Если, конечно, ничего не упускаю.

  • sendsigs: безуспешно пытается прибить процессы, чем вешает остановку контейнера на некоторое время.

Но, собственно, зачем нам весь этот хлам? Для контейнера он вообще не нужен. Да-да. Всё и так работает - LXC рулит. Но прибивать сервисы - занятие неблагодарное, и вот тут-то и выручает native boot. Если заглянуть в файлы /etc/runit/1 и /etc/runit/3, то становится ясно, что наличие файла /etc/runit/native.boot.run меняет всё:

  • /etc/runit/1 запускает скрипты *.sh из каталога /etc/runit/boot-run вместо /etc/rcS.d

  • /etc/runit/3 запускает скрипты из /etc/runit/shutdown-run вместо /etc/rc6.d, ну или до какого там runlevel-а ваша система дойдёт

Плюс, наличие файла /etc/runit/no.emulate.sysv отменяет запуск скриптов из /etc/rc2.d -- см. /etc/runit/2

Пробуем:

touch /etc/runit/native.boot.run
touch /etc/runit/no.emulate.sysv
mkdir /etc/runit/boot-run
mkdir /etc/runit/shutdown-run

Перезапускаем контейнер. У меня работает. А у вас?

Некоторые плюшки всё-же не помешают. Для себя я использую три:

  • вызов sysctl --system, как в /etc/init.d/procps

  • вызов hostname `cat /etc/hostname` -- в обычных применениях не нужен, но вдруг вам надо? Мне, например, - да.

  • вызов /etc/nftables.conf

Насчёт самого runit - там есть лишнее, но избавиться от него гораздо легче, чем в мэйнстриме:

for f in /etc/service/getty* ; do unlink $f ; done
for f in /etc/service/.getty* ; do unlink $f ; done
unlink /etc/service/default-syslog

Да, если используете sshd, но auditd не установлен, надо закомментировать строчку

sv start auditd  || sv check auditd || true

в файле /etc/service/ssh/run

Обещанный debootstrap, но это мои личные предпочтения. Внимательно проверьте include/exclude перед тем, как копипастить.

debootstrap --variant=minbase \
    --include=runit,runit-init,nano,apt-utils,dialog,procps,libc-l10n,locales,lsb-release,iproute2,netbase,nftables,tzdata,less,bsdextrautils,findutils,iputils-tracepath,iputils-ping,lsof,openssh-server,openssh-sftp-server,psutils,rsync,screen,bash-completion \
    --exclude=sysvinit-core,vim-common,vim-tiny,isc-dhcp-client,isc-dhcp-common,bootlogd,dmidecode \
    daedalus /var/lib/lxc/devuan/rootfs \
    http://us.deb.devuan.org/merged/

Да, ещё: если ваша базовая система не Devuan, то вам нужен правильный debootstrap (в комментариях подсказывают, что можно просто сделать ссылку в /usr/shared/debootstrap/scripts, но я предпочитаю туда не лазить):

git clone https://git.devuan.org/devuan/debootstrap.git
export DEBOOTSTRAP_DIR=`realpath debootstrap`

Плюс, ключи:

gpg --no-default-keyring --keyserver keyring.devuan.org \
    --keyring ./devuan-keyring.gpg \
    --recv-keys 0022D0AB5275F140 94532124541922FB

и добавьте тогда --keyring=./devuan-keyring.gpg к debootstrap

Пример файла конфигурации /var/lib/lxc/devuan/config:

lxc.net.0.type = veth
lxc.net.0.hwaddr = 00:12:34:56:78:9a
lxc.net.0.ipv4.address = 192.168.0.2/24
lxc.net.0.ipv4.gateway = 192.168.0.1
lxc.net.0.link = br0
lxc.net.0.flags = up
lxc.apparmor.profile = unconfined
lxc.apparmor.allow_nesting = 1
lxc.rootfs.path = dir:/var/lib/lxc/devuan/rootfs

# Common configuration
lxc.include = /usr/share/lxc/config/debian.common.conf

# lxcfs
lxc.mount.auto = cgroup:mixed
lxc.autodev = 1
lxc.include = /usr/share/lxc/config/common.conf.d/00-lxcfs.conf

# Container specific configuration
lxc.tty.max = 4
lxc.uts.name = devuan
lxc.arch = arm64
lxc.pty.max = 1024

# Map user and group ids
lxc.include = /usr/share/lxc/config/debian.userns.conf
lxc.idmap = u 0 900000 65536
lxc.idmap = g 0 900000 65536

lxc.start.auto = 1

И последнее: не знаю как у вас, а у меня fuidshift (поделка на go из lxd-tools) нифига не работает. Я пользуюсь более простой и понятной http://bazaar.launchpad.net/~serge-hallyn/+junk/nsexec/view/head:/uidmapshift.c

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


  1. 13werwolf13
    01.12.2023 06:25
    +1

    отключал мерзкий бинарный лог в /etc/systemd/journald.conf

    не холивара ради а из чистого интереса: а в чём собсна претензия к journald? оно шустрое, оно жмётся, оно удобно, оно умеет в сеть.. я что-то с ходу минусов то придумать не могу..


    1. amateur80lvl Автор
      01.12.2023 06:25

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


      1. 13werwolf13
        01.12.2023 06:25

        простите за назойливость, я просто не понял - зачем выпиливать то к чему нет претензий?


        1. amateur80lvl Автор
          01.12.2023 06:25

          А зачем оно мне если я этим не пользуюсь? Непорядок. Систему надо держать в чистоте, как руки :)

          Было бы оно по-настоящему модульным и юниксвейным - я пользовался бы только тем, что мне надо и по сторонам бы не смотрел.


          1. TIEugene
            01.12.2023 06:25

            Систему надо держать в чистоте

            +100500

            (но за упоминание deborphan/repreaper могут слить карму, аккуратнее)


            1. amateur80lvl Автор
              01.12.2023 06:25

              тапох, но я думаю что это случится за vim в exclude


      1. mayorovp
        01.12.2023 06:25

        Ну почему "никак"? Всегда же можно дать прописать в journald.conf опции Storage=none и ForwardToSyslog=true.

        Или вовсе подменить содержимое systemd-journald.service на что-нибудь другое.


        1. amateur80lvl Автор
          01.12.2023 06:25

          Вот именно так и делал в конфиге. Насчёт подменить - не пробовал. Жутко интересно, но уже неохота. А есть положительный опыт с подменой? Чтобы не наблюдать этот journald в списке процессов?


          1. mayorovp
            01.12.2023 06:25

            Нет, на практике я так не делал, ибо нахера?

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


    1. amateur80lvl Автор
      01.12.2023 06:25

      И, кстати, да: есть претензия - два или три года назад наблюдал какой-то ад с памятью. journald был в топе, кто жрал оперативку. С тех пор и начал отключать, тем более что в моём дистре rsyslog и так в довесок болтался.


  1. Johan_Palych
    01.12.2023 06:25
    +1

    Да, ещё: если ваша базовая система не Devuan, то вам нужен правильный debootstrap

    Любой debootstrap из любого дистриба правильный.
    https://pkgs.org/search/?q=debootstrap
    Нормально работает по старой схеме(daedalus - симлинк sid)
    LXC proxmox-devuan-containers devuan-5.0-minimal-64
    В devuan debootstrap 8 мес. назад изменили ceres. daedalus - симлинк на ceres

    Ставил на виртуалку с Ubuntu 22.04:

    apt install arch-install-scripts debootstrap systemd-container
    cd /usr/share/debootstrap/scripts/ && ln -sfn sid daedalus && mkdir /tmp/daedalus
    debootstrap --arch=amd64 --verbose --no-check-gpg --variant=minbase daedalus /tmp/daedalus http://deb.devuan.org/merged
    arch-chroot /tmp/daedalus /bin/bash
    systemd-nspawn -D /tmp/daedalus --machine="daedalus" --bind-ro="/etc/resolv.conf"
    /bin/sh -c "apt-get update && apt-get dist-upgrade"
    apt-get install --no-install-recommends devuan-keyring mc wget curl aptitude dialog
    И дальше по любому списку
    Бонус - все репы daedalus одной командой:
    sudo cat <<EOF | sudo tee /etc/apt/sources.list
    deb http://deb.devuan.org/merged daedalus main contrib non-free non-free-firmware
    # deb-src http://deb.devuan.org/merged daedalus main contrib non-free non-free-firmware
    
    deb http://deb.devuan.org/merged daedalus-security main contrib non-free non-free-firmware
    # deb-src http://deb.devuan.org/merged daedalus-security main contrib non-free non-free-firmware
    
    deb http://deb.devuan.org/merged daedalus-updates main contrib non-free non-free-firmware
    # deb-src http://deb.devuan.org/merged daedalus-updates main contrib non-free non-free-firmware
    
    deb http://deb.devuan.org/merged daedalus-backports main contrib non-free non-free-firmware
    # deb-src http://deb.devuan.org/merged daedalus-backports main contrib non-free non-free-firmware
    EOF