evgen@spb: ~/2026/05/kuklovodim-cherez-openvox-chast-1-ustanovka-servera/

Кукловодим через OpenVox. Часть 1. Установка сервера

Первая часть цикла про то, как я приручил парк серверов через OpenVox — форк Puppet, который живёт и развивается, пока сам Puppet потихоньку закрывается. В этой части поднимаем сервер управления на Debian 13, кладём весь код под git и настраиваем автоматическую раскатку через r10k.

Идея простая: ни одной настройки руками на боевых серверах. Всё, что делает инфраструктуру такой, какая она есть, лежит в git, проходит через ревью в виде коммита и раскатывается одной командой. Хочешь понять, почему сервер настроен именно так — смотришь историю. Хочешь откатить — git revert. Вот к этому и идём.

Все команды выполняются от root на сервере.

Ставим OpenVox Server

Подключаем репозиторий OpenVox и ставим сервер:

wget https://apt.voxpupuli.org/openvox8-release-debian13.deb
dpkg -i openvox8-release-debian13.deb
apt update
apt install -y openvox-server

Запускаем и включаем автозапуск. Обратите внимание: исторически сервис называется puppetserver, а не openvoxserver — форк сохранил совместимость:

systemctl enable --now puppetserver
/opt/puppetlabs/bin/puppetserver --version

Добавляем бинарники OpenVox в PATH, чтобы не писать полный путь каждый раз:

echo 'export PATH=$PATH:/opt/puppetlabs/bin' > /etc/profile.d/openvox.sh

Три грабли, на которые я наступил на Debian 13

Свежий trixie преподнёс пару сюрпризов — сохраняю, чтобы вы их обошли.

Ошибка про openjdk при установке. В середине 2025-го пакет openvox-server на trixie тянул несуществующие openjdk-17 и openjdk-11. Если словили такую ошибку — поставьте openjdk-21-jre-headless руками и повторите установку сервера.

puppetserver не сразу слушает порт 8140. Это JVM, холодный старт занимает 30–90 секунд. Если systemctl status puppetserver показывает active, а порта всё ещё нет — не паникуйте, просто подождите. Проверка:

ss -tlnp | grep 8140

Память. По умолчанию heap 2 ГБ (-Xms2g -Xmx2g). Для 10–50 нод хватает с запасом. Если RAM в обрез, правьте JAVA_ARGS в /etc/default/puppetserver и перезапускайте сервис.

Финальная проверка, что сервер жив и слушает порт:

systemctl status puppetserver          # active (running)
ss -tlnp | grep 8140                    # java слушает 8140

Кладём код в control-repo

Теперь самое важное архитектурное решение. Весь код — манифесты, Hiera, профили — живёт в git-репозитории /root/control-repo. А r10k раскатывает его в рабочее окружение /etc/puppetlabs/code/environments/production/.

Здесь есть одна вещь, которую надо усвоить сразу, иначе потом будет больно.

Ветка git = окружение Puppet. Ветка production соответствует окружению production. И r10k затирает содержимое окружения тем, что лежит в git. Поэтому весь код обязан быть закоммичен, а рабочая ветка обязана называться production, а не main. Забудете — r10k молча снесёт незакоммиченное.

Структура кода

control-repo/
├── environment.conf          # modulepath (обязательно с site-modules)
├── hiera.yaml                # иерархия данных
├── Puppetfile                # внешние модули с Forge (stdlib и т.п.)
├── .gitignore                # /modules/ (наполняется r10k)
├── data/                     # данные Hiera
│   ├── common.yaml           # дефолты для всех нод
│   └── nodes/                # переопределения по конкретной ноде
├── manifests/
│   └── site.pp               # классификация нод
└── site-modules/             # локальный код (не трогается r10k)
    ├── role/manifests/       # роли (чем является сервер)
    └── profile/              # профили (технологические кусочки)
        ├── manifests/
        └── templates/

Разделение site-modules/ и modules/ — принципиальное. r10k управляет каталогом modules/ целиком и сносит оттуда всё, чего нет в Puppetfile. А ваш локальный код — роли и профили — живёт в site-modules/ и r10k не трогается. Перепутаете каталоги — потеряете свои модули при первом же деплое.

Собираем репозиторий из текущего кода

Если на сервере уже есть код в окружении production, берём его как основу:

cp -a /etc/puppetlabs/code/environments/production /root/control-repo
cd /root/control-repo

Если начинаем с чистого листа — создаём каталоги вручную:

mkdir -p /root/control-repo/{manifests,data/nodes,site-modules/role/manifests,site-modules/profile/manifests,site-modules/profile/templates}
cd /root/control-repo

Ключевые файлы

environment.confобязательно с site-modules в modulepath, иначе Puppet не найдёт ваши роли:

cat > environment.conf <<'EOF'
modulepath = site-modules:modules:$basemodulepath
EOF

hiera.yaml — иерархия данных, от частного к общему: сначала ищем настройки конкретной ноды, потом общие:

cat > hiera.yaml <<'EOF'
---
version: 5
defaults:
  datadir: data
  data_hash: yaml_data
hierarchy:
  - name: 'Per-node'
    path: 'nodes/%{trusted.certname}.yaml'
  - name: 'Common'
    path: 'common.yaml'
EOF

Puppetfile — внешние модули с Forge. stdlib нужен почти всем модулям, так что ставим сразу:

cat > Puppetfile <<'EOF'
forge 'https://forge.puppet.com'

# базовый модуль; держим на 9.x до осознанного перехода на 10.x
mod 'puppetlabs-stdlib', '9.7.0'
EOF

.gitignore — каталог modules/ наполняет r10k, в git его не держим:

cat > .gitignore <<'EOF'
# modules/ наполняет r10k из Puppetfile — в git не держим
/modules/
EOF

manifests/site.pp — базовая классификация. Пока все ноды получают role::base:

cat > manifests/site.pp <<'EOF'
node default {
  include role::base
}
EOF

Инициализируем git — и не забываем про ветку

git init -b production
git config user.name  'puppet admin'
git config user.email 'root@puppet.example.com'
git add -A
git commit -m 'Initial control repo import'
git branch                 # ПРОВЕРЬ: активна ветка production

Если по какой-то причине ветка называется иначе — переименуйте:

git branch -m production

Bare-репозиторий как origin

r10k тянет код из git-remote. Простейший рабочий вариант — локальный bare-репозиторий прямо на сервере:

git init --bare /srv/puppet/control-repo.git
git remote add origin /srv/puppet/control-repo.git
git push origin production

Про бэкап честно. Bare-репозиторий на том же сервере спасает от ошибок в коде — есть история, есть откат. Но он не переживёт смерть диска. Для настоящего бэкапа заведите приватный репозиторий на GitHub или GitLab и добавьте его вторым remote:

git remote set-url --add origin git@github.com:youruser/control-repo.git

Ставим и настраиваем r10k

r10k ставим как ruby-gem внутрь AIO-Ruby от OpenVox — чтобы не мешать системному Ruby:

/opt/puppetlabs/puppet/bin/gem install r10k
/opt/puppetlabs/puppet/bin/r10k version

Конфиг r10k — указываем, откуда брать код и куда его раскатывать:

mkdir -p /etc/puppetlabs/r10k
cat > /etc/puppetlabs/r10k/r10k.yaml <<'EOF'
---
sources:
  main:
    remote: '/srv/puppet/control-repo.git'
    basedir: '/etc/puppetlabs/code/environments'
EOF

Первый деплой. Флаг -p — ставить модули из Puppetfile, -v — подробный вывод. Перед этим на всякий случай бэкапим текущее окружение, потому что r10k его перезапишет:

cp -a /etc/puppetlabs/code/environments/production /root/production-backup-$(date +%F)

/opt/puppetlabs/puppet/bin/r10k deploy environment -pv

Проверяем, что код на месте и внешние модули подтянулись:

ls /etc/puppetlabs/code/environments/production          # код на месте
ls /etc/puppetlabs/code/environments/production/modules  # появился stdlib

Рабочий цикл — то, ради чего всё затевалось

С этого момента /etc/puppetlabs/codeтолько для чтения. Его наполняет r10k, и лезть туда руками нельзя. Любая правка манифеста, Hiera или шаблона идёт через git:

cd /root/control-repo
# ... правите манифесты / Hiera / шаблоны ...
git add -A
git commit -m 'что изменил'
git push origin production
/opt/puppetlabs/puppet/bin/r10k deploy environment production -pv

Отредактировал → закоммитил → запушил → задеплоил. Четыре шага, которые быстро уходят в мышечную память. Взамен вы получаете историю всех изменений, откат через git revert и бэкап кода как побочный эффект.

И последнее правило, нарушать которое дорого: внешние модули с Forge теперь добавляются только через Puppetfile. Никаких puppet module install — r10k снесёт всё установленное вручную при следующем же деплое.

Что в итоге

После этих шагов у вас есть:

  • OpenVox Server на Debian 13, слушает порт 8140;
  • весь код инфраструктуры под git — с историей и откатом;
  • r10k как механизм раскатки, где ветка production соответствует окружению;
  • доступ ко всему Puppet Forge через Puppetfile;
  • отлаженный рабочий цикл правок без ручных вмешательств в прод.

В следующей части подключим к серверу первых клиентов и разберёмся с подписью сертификатов. А дальше — начнём собственно кукловодить: писать роли и профили, которые превращают голый сервер в то, чем он должен быть.

evgen@spb: ~/contacts
evgen@spbping -c1 evgen.info
64 bytes from evgen.info: отвечу в течение рабочего дня
evgen@spbcat contacts.txt
mail      ya@evgen.info
telegram  @EvgenOne
github    github.com/onegin
blog      evgen.info/blog
evgen@spbecho $ЗАЧЕМ_ПИСАТЬ
интересная инфраструктурная задача · вопрос по Proxmox или Icinga ·
желание обсудить, почему memtest молчал, а память была битая
evgen@spb
© 2026 Евгений Подолинский · Санкт-Петербург
синий здесь – не тот, о котором вы подумали.