2020-10 upd: we reached the first fundraising goal and rented a server in Hetzner for development! Thank you for donating !
Создание CBSD образов с настроенными сервисами с помощью Puppet
Данный HowTo рассчитан на тех, кто уже знаком с системой управления виртуальными окружениями CBSD и менеджером конфигурации Puppet
В какой-то момент времени вы можете захотеть создать свои собственные 'jail registry' (по аналогии с Docker registry) для возможности создавать и закачивать свои собственные образы в репозиторий образов
С помощью этих скриптов вы можете создавать CBSD образы из Puppet кода. Это может быть полезно, например, в таких случаях:
- - Вы имеете существующую кодовую базу Puppet и желаете перенести часть ваших сервисов в контейнера. Совместное использование кода между контейнерами и не контейниризированным окружением позволит вам минимизировать дубляж кода и сэкономит время по обслуживанию инфраструктуры;
- - Вы создаете большое количество образов с настроенными внутри сервисами и определенными параметрами. В этом случае, Puppet позволяет вам использовать декларативный язык по описанию ваших образов и с помощью скрипта вы можете создавать и обновлять ваши образы достаточно просто и быстро.
Настройка
Наша реализация будет состоять из двух частей. Первое - это файловая структура, содержащая обычные Puppet ресурсы - стандартный Puppet-манифест, описывающий ваше окружение и Puppetfile. В Puppetfile вы должны описать модули, которые вам требуются для созданного манифеста.
Вторая часть - скрипт, который создает контейнер, запускает r10k на Puppetfile и выполняет puppet apply.
В данном HowTo рассматривается server-less архитектура. Тем не менее, вы можете легко использовать ваш Puppet сервер вместо локальных манифестов.
Итак, создадим рабочий каталог /root/buid-jail. В нем мы будем хранить per-instance каталоги со всеми необходимыми файлами. Например, для сервиса 'redis' будем использовать каталог /root/build-jail/redis:
% mkdir -p /root/build-jail/redis
Внутри этого каталога создадим директорию 'manifest' в котором создадим Puppet манифест. В нем вы должны описать все то, что пишете в обычных манифестах Puppet сервера:
% mkdir /root/build-jail/redis/manifest
Поскольку наш пример ориентирован на демонстрацию запуска redis, подключим класс 'redis':
% echo "class { 'redis': }" > /root/build-jail/redis/manifest/init.pp
Чтобы расширить пример, и продемонстрируем возможность использования Hiera, напишем часть параметров в yaml бакенде. Для этого, создадим соответствующий каталог:
% mkdir /root/build-jail/redis/hieradata
И напишем в yaml формате часть параметров так, как вы это делаете в обычных yaml файлах Puppet сервера:
cat > /root/build-jail/redis/hieradata/common.yaml << EOF redis::manage_repo: false redis::bind: 0.0.0.0 redis::port: 6379 redis::log_level: warning EOF
Далее, нам осталось написать Puppetfile. Нам потребуется сам модуль redis, а также его зависимости:
cat > /root/build-jail/redis/Cbsdfile <<EOF forge 'https://forgeapi.puppetlabs.com' mod 'arioch-redis', '1.2.4' mod 'puppetlabs/apt' mod 'puppetlabs/stdlib' mod 'stahnma/epel' EOF
Теперь, нам осталось написать скрипт, который будет создавать jail из темплейта и применять Puppet внутри.
Сам template, где мы заменили наш рабочий каталог на конструкцию #workdir# и jname - на #jname#, будет выглядеть следующим образом:
relative_path="1"; jname="#jname#"; path="#workdir#/jails/#jname#"; host_hostname="#jname#.my.domain"; ip4_addr="DHCP"; mount_devfs="1"; allow_mount="1"; allow_devfs="1"; allow_nullfs="1"; mount_fstab="#workdir#/jails-fstab/fstab.#jname#"; arch="native"; mkhostsfile="1"; devfs_ruleset="4"; ver="native"; basename=""; baserw="0"; mount_src="0"; mount_obj="0"; mount_kernel="0"; mount_ports="1"; astart="1"; data="#workdir#/jails-data/#jname#-data"; vnet="0"; nic_hwaddr="0"; applytpl="1"; mdsize="0"; rcconf="#workdir#/jails-rcconf/rc.conf_#jname#"; floatresolv="1"; zfs_snapsrc=""; exec_poststart="0"; exec_poststop=""; exec_prestart="0"; exec_prestop="0"; exec_master_poststart="0"; exec_master_poststop="0"; exec_master_prestart="0"; exec_master_prestop="0"; pkg_bootstrap="1"; with_img_helpers=""; runasap="0"; interface="auto"; jailskeldir="#workdir#/share/FreeBSD-jail-skel"; jail_profile="default"; # root password user_pw_root='cbsd'; exec_start="/bin/sh /etc/rc" exec_stop="/bin/sh /etc/rc.shutdown" emulator="jail"
Сохраним этот темплейт как /root/build-jail/tpl.jconf
Вы можете получить этот темплейт самостоятельно, запустив 'cbsd jconstruct-tui', введя необходимые параметры и ответив 'no' на вопрос 'Do you want to create jail immediately?'.
На выходе вы получите тот самый темплейт, в котором необходимо заменить ваш рабочий каталог на #workdir# и имя клетки на #jname#.
Сам скрипт может иметь примерно следующий вид (назовем его Cbsdfile):
#!/bin/sh JAILNAME="jredis" ## MYDIR="$( /usr/bin/dirname $0 )" MYPATH="$( /bin/realpath ${MYDIR} )" . /etc/rc.conf cbsd jstatus jname=${JAILNAME} > /dev/null 2>&1 ret=$? if [ ${ret} -ne 0 ]; then echo "Warning, jail exist. Please remove them first" # cbsd jremove ${JAILNAME} exit 0 fi tmpjconf=$( mktemp ) trap "/bin/rm -f ${tmpjconf}" HUP INT QUIT ABRT KILL ALRM TERM BUS EXIT sed -e "s:#jname#:${JAILNAME}:g" \ -e "s:#workdir#:${cbsd_workdir}:g" ${MYPATH}/tpl.jconf > ${tmpjconf} cbsd jcreate jconf=${tmpjconf} cbsd jstart inter=0 ${JAILNAME} cbsd jexec jname=${JAILNAME} pkg update cbsd jexec jname=${JAILNAME} pkg install -y sysutils/puppet4 ca_root_nss rubygem-r10k cbsd jailscp ${MYPATH}/Puppetfile ${JAILNAME}:/tmp/Puppetfile cbsd jexec jname=${JAILNAME} "cd /tmp && r10k puppetfile install --moduledir /tmp/module" [ -f ${MYPATH}/hiera.yaml ] && cbsd jailscp ${MYPATH}/hiera.yaml ${JAILNAME}:/tmp/hiera.yaml [ -d ${MYPATH}/hieradata ] && cbsd jailscp ${MYPATH}/hieradata/ ${JAILNAME}:/tmp/hieradata cbsd jailscp ${MYPATH}/manifests/ ${JAILNAME}:/tmp/manifests cbsd jexec jname=${JAILNAME} env FACTER_hostname=${JAILNAME} puppet apply /tmp/manifests/init.pp --detailed-exitcodes --verbose --show_diff --summarize --hiera_config=/tmp/hiera.yaml --app_management --modulepath=/tmp/module cbsd jexec jname=${JAILNAME} pkg clean -y # And push to registry: # cbsd jstop jname=${JAILNAME} # cbsd jexport jname=${JAILNAME} # scp ~cbsd/exports/${JAILNAME} builder@repo.my.domain:/path/.../ # .. exit 0
Обратите внимание, что имя создаваемого контейнера указано в этом скрипте в параметре JAILNAME.
Вы можете вынести этот параметр за пределы скрипта в конфигурационный файл, или принимать его в качестве аргумента.
Также, возможно, вы захотите не делать проверку на существование контейнера и удалять его автоматически при запуске каждый раз. Для этого, раскомментируйте строку 'cbsd jremove ${JAILNAME}'
На выходе работы данного скрипта мы получим рабочий jail с именем jredis с конфигурированным и запущенным сервисом redis внутри.
Далее с этим можно делать все что угодно, например клонировать или экспортировать и загрузить свой репозиторий образов.
Вы можете превратить подобный скрипт в сервис по созданию контейнеров внутри компании, где ваши сотрудники (например, разработчики) самостоятельно конфигурируют параметры контейнера и 'заказывают' сборку необходимого образа
Например, вы можете создать Jenkins Job для вышеописанного случая, создав параметизированный Job, в котором пользователь может менять определенные вами параметры (таким образом поступил автор статьи для сборки Docker образов)
Посмотрите на пример, как это может выглядеть: https://youtu.be/AQ7FbCHhIBk