В прошлой части мы рассмотрели возможности Packer и Vagrant для создания образов виртуальных машин, их запуска и конфигурирования, а также установили их на хостовой машине. Теперь мы перейдем к практике использования этих инструментов, создадим с помощью них образ виртуальной машины и проверим её запуск. При этом разработаем механизмы, позволяющие заменять версии платформы 1С и PostgreSQL в наших сборках, а также переключаться между двумя версиями операционной системы (в нашем случае это Ubuntu 19.04 и 19.10).
Данную публикацию можно использовать не только как руководство по сборке образов виртуальных машин для последующего их включения в состав CI-контура, но и как инструкцию по автоматической установке необходимого программного обеспечения для работы с 1С на последних релизах Linux Ubuntu. Более того, если Вы по какой-то причине не захотите применять Packer и Vagrant для автоматизации сборок, то развернуть CI по прежнему можно через ручную настройку набора физических или виртуальных машин, а приведённые здесь и в следующей теме скрипты позволят упростить и унифицировать этот процесс.
Распределение задач между Packer и Vagrant
Packer и Vagrant являются во многом взаимозаменяемыми инструментами. Почти всё, что мы можем сделать на этапе сборки образа виртуальной машины, мы также можем сделать и во время её первого запуска. Таким образом вместо сборки образа можно было бы взять образ с чистой операционной системой из облака HashiCorp и настраивать всё необходимое в момент первого запуска виртуальной машины через Vagrant:
Точно также и наоборот, можно все необходимые настройки делать при сборке образа через Packer, а вместо Vagrant использовать несколько простых команд, предоставляемых интерфейсом командной строки гипервизора.
Вопрос лишь в оптимальности распределения процесса конфигурирования между этими двумя инструментами. Ведь если абсолютно все настройки делать с помощью Packer, то потребность в малейшем изменении конфигурации потребует длительной пересборки образа. Также при этом потребуется вносить изменения в конфигурационные файлы, отвечающие за сборку образа. А ведь они по хорошему должны отвечать за более фундаментальные вещи, чем установка имени хоста или запуск агента Jenkins, который мы вообще можем в один прекрасный момент захотеть заменить на Bamboo или Gitlab CI. С другой стороны если вынести все настройки на сторону Vagrant, то каждый запуск новой виртуальной машины, каждое пересоздание CI-узла будет занимать огромное количество времени.
Таким образом, конфигурирование и установку программ стоит вынести в Packer если установка или конфигурация удовлетворяет следующим условиям:
- выполняется долго и необходима во всех виртуальных машинах
- необходима в большинстве машин и при этом программу легко отключить (или конфигурацию легко изменить) на тех машинах, на которых она не нужна, либо такое отключение программы (или изменение конфигурации) вообще не обязательно.
Конфигурирование стоит вынести в Vagrant при выполнении одного из следующих условий:
- конфигурация специфична для конкретной машины
- конфигурация может часто меняться и поэтому правила конфигурирования хранятся на хостовой машине, а затем импортируются в виртуальную машину и исполняются при ее запуске.
Рассмотрим необходимые нам этапы конфигурирования узлов CI-сервера и будем сразу же распределять их по зонам ответственности между Packer и Vagrant исходя из критериев, приведенных выше.
Через Packer будем выполнять установку и конфигурирование:
1) Операционной системы и ее графического окружения.
2) Инструментов, упрощающих разработку, отладку и редактирование файлов. В нашем случае это будет эмулятор консоли Terminator, редактор Visual Studio Code и OneScript (эти инструменты Вы можете заменить по своему вкусу).
3) JVM или JDK, которые необходимы для работы узлов Jenkins.
4) Системных утилит, позволяющих нашим узлам нормально работать в сети совместно с Windows и при необходимости найти проблему, если что-то пойдет не так. Это будут сервисы Avahi , Samba и утилита traceroute.
5) Гостевые дополнения гипервизора - Virtual Box Guest Additions. Их обновления требуются очень редко, поэтому можно сразу упаковать их в образ машины.
6) Запретить гашение экрана и отключить энергосбережение. Это необходимо, чтобы машина не "засыпала" в периоды простоя, становясь недоступной для управления с мастер-узла на хостовой машине.
7) Настроить автологон. Мы будем использовать систему для CI, а не для пользовательских нужд и после запуска машин логиниться в них будет некому. При нужно, чтобы машина становилась доступной для эмуляции пользовательских действий сразу после запуска. Также через автологон впоследствии будет решаться задача автозапуска агентов CI-сервера.
8) Установить PostgreSQL сконфигурировать его для работы с 1С. В описании этого процесса обратите внимание на особенности неинтерактивной установки и настройки логов.
9) Установить саму платформу 1С. В автоматической установке 1С для целей CI тоже будет ряд тонкостей, обратите на них внимание.
10) Установить Apache и при необхо димости выполнить минимальную конфигурацию (в нашем случае для работы с SSL).
Любые изменение, связанные с этими этапами, потребуют пересборки виртуальной машины. Сборка хоть и будет выполняться автоматически, но процесс может занять длительное время - от 40 до 60 минут.
Остальные действия будут выполняться через Vagrant.
Только при первом запуске машины потребуется выполнять:
1) Настройку сети и имени хоста. Наши машины в момент развертывания будут "клонами" исходного образа. Но для обеспечения возможности работать с ними индивидуально и возможности их взаимодействия друг с другом необходимо добавить им индивидуальности. Делать это будем за счет назначения им разных IP адресов и имен хостов.
2) Адаптацию настроек сервера 1С под новое имя хоста и копирование файла nethasp.ini с хостовой машины.
3) Настройку автозапуска агента Jenkins, чтобы наша машина фу нкционировала как узел CI-сервера.
При каждом запуске машины через Vagrant нужно выполнить:
1) Выделение системных ресурсов виртуальной машине.
2) Настройку общих каталогов
3) Установку приемлемого разрешения экрана для работы с GUI и снятия скриншотов.
4) Запуск агента Jenkins
Таким образом первый запуск через Vagrant будет происходить несколько дольше (5-10 минут) чем последующие (1 - 2 минуты).
На рисунке ниже этот же процесс отображен схематично. При этом сделано небольшое допущение. Выделение системных ресурсов для виртуальной машины отнесено к этапу её создания, хотя на самом деле ресурсами при необходимости можно управлять при каждом её запуске.

Здесь мы разделяем установку операционной системы и графического интерфейса , так как за основу мы будем брать легковесный Ubuntu Server, который не имеет GUI и множества программ, ориентированных на десктопы. Уже затем мы будем устанавливать пакеты для работы с графикой. Это позволит значительно сократить занимаемое операционной системой место на дисках и не устанавливать лишние пакеты программ. А значит можно будет создавать больше виртуальных машин на одном сервере или оставить дисковое пространство для выполнения других задач.
Порядок исполнения этапов сборки виртуальной машины, отображенных на схеме, можно менять. Но рекомендую устанавливать программы, упрощающие администрирование и работу с кодом, как можно раньше. В нашем случае это эмулятор консоли Terminator и Visual Studio Code (вы можете выбрать для себя другие инструменты). Дело в том, что сразу после старта виртуальной машины мы можем с ней взаимодействовать - эту возможность даёт нам гипервизор через свой графический интерфейс. В то же время на любом из следующих шагов конфигурирования могут возникнуть ошибки. Если в системе будет установлен редактор кода и эмулятор терминала, к которому Вы привыкли, то поиск и исправление причин ошибок будет происходить быстрее.
По той же причине сразу после этого имеет смысл установить дополнения гипервизора (в нашем случае это VirtualBox Guest Additions). Поставить их всё равно потребуется, но будет проще работать с системой, если она будет более отзывчивой и способной к удобному взаимодействию с хостовой машиной.
Включите виртуализацию на хостовой машине
На хостовой машине, в которой работает гипервизор, должен быть доступен функционал виртуализации. На физических машинах это делается в BIOS или UEFI. В большинстве случаев в этом нет необходимости, так как обычно это уже сделано производителем.
Если же в качестве хоста у вас выступает виртуальная машина работающая под управлением гипервизора первого типа, то в этом гипервизоре должна быть включена вложенная виртуализация. Если этого не сделать, то любой гипервизор второго типа, будь то VMWare, Hyper-V или VirtualBox при попытке запустить виртуальную машину будет выдавать ошибку следующего вида:

Как работать с Packer?
Packer работает на основе конфигурационного файла, декларативно описывающего что он должен сделать в процессе развертывания образа виртуальной машины. При этом есть раздел, где внутри декларативно описываемых шагов можно производить вызов команд гостевой операционной системы, явно прописывая какие строки кода нужно выполнить и какие скрипты вызвать.
Конфигурация Packer задается в виде JSON-файла и содержит следующие базовые блоки:
- Установка значений переменных, определенных пользователем. Их значения можно задать либо константами, либо загрузить из переменных окружения (environment variables).
- Указание параметров сборщиков : определение выделяемых хостовой машиной системных ресурсов, других основных настроек виртуальной машины, указание потока символов, ввод которых с клавиатуры необходимо сэмулировать при запуске машины.
- Блок provisioners (поставщиков). Провизионеры - это общее понятие, объединяющее в себе множество инструментов, с которыми может взаимодействовать Packer и Vagrant. В данном блоке определяется последовательность действий, которая будет выполняться в гостевой машине, и за счет какого программного обеспечения будут выполняться эти действия. Можно подключать к процессу настройки Ansible, Chef, PowerShell и т.д. В простейшем случае здесь могут быть обычные shell-команды. Именно такой простейший случай мы и будем рассматривать.
- Пост-обработчики. Здесь указывается с помощью какого приложения будет производиться постобработка виртуальной машины и дается инструкция этому приложению, что именно нужно сделать. В нашем случае на этом этапе может происходить упаковка настроенной виртуальной машины в так называемые "боксы" (boxes). Результатом будет образ виртуальной машины, из которого затем можно будет разворачивать любое количество машин-клонов.

В сети можно встретить множество примеров конфигурационных файлов для Packer. Можно найти даже очень универсальные, рассчитанные на переключение между разными гипервизорами (Hyper-V, VirtualBox, VMWare), и расчитанные на применение Chef или Ansible. Хотел бы поделиться с Вами ссылкой на богатый репозиторий, с которого я начинал изучение этой темы. Он позволяет разворачивать системы, аналогичные тем, которые мы рассматриваем, но на базе Windows-машин: https://github.com/joefitzgerald/packer-windows. Для новых версий ОС - Windows Server 2016 и Windows Server 2019 код этого репозитория нуждается в небольшой адаптации.
Конфигурационный файл, который мы создадим, будет очень простым. Он "заточен" под VirtualBox и выполнение shell-команд. Обратной стороной этой простоты будет необходимость немного его адаптировать при желании использовать другой гипервизор или заменить обычные shell-команды на Ansible или его аналог.
И последнее замечание, перед тем как перейти непосредственно к созданию файла для Packer. При сборке обязательно должен быть доступен интернет и связь должна быть стабильной. Далеко не везде в используемых скриптах учитывается возможность возникновения сбоя установки из-за разрыва интернет-соединения. Как правило в случае ошибок в загрузке пакетов вся сборка остановится, но в ряде случаев этого может не произойти. Поэтому убедитесь в стабильности канала.
Прежде чем переходить к следующим частям этой публикации предлагаю бегло ознакомиться с содержимым файла, который мы будем использовать для сборки образа виртуальной машины. Если держать файл перед глазами, то будет проще понимать написанное далее. Ссылки на файл:
- https://gitlab.com/vladimirlitvinenko84/ci-infrastructure-for-1c/blob/master/packer_build.json
- https://github.com/VladimirLitvinenko84/ci-infrastructure-for-1c/blob/master/packer_build.json
Раздел переменных
Переменные в JSON-файле Packer служат для удобства и гибкости конфигурирования. Находятся они в блоке variables.
"variables": {
"имя_переменной_1": "{{env `имя_переменной_окружения_1`}}",
"имя_переменной_2": "константное_значение_переменной_2",
},
Переменные расположенные в этом блоке называются пользовательскими и являются единственной точкой входа, где происходит задание вообще каких бы то ни было переменных. Далее в файле задаются только предопределенные конфигурационные параметры.
В конфигурационном файле Packer также можно использовать переменные окружения (переменные среды). Но делать это можно только в разделе пользовательских переменных. Это ограничение введено специально. Оно позволяет точно знать, где задаются используемые в файле переменные и из чего они формируются. Таким образом, чтобы использовать в файле переменную окружения её предварительно необходимо записать в пользовательскую переменную.
По началу кажется, что это только лишний раз раздувает файл. Но правильность такого подхода чувствуется, когда приходится отлаживать процесс сборки или когда спустя месяц-два приходится вносить правки в конфигурационный файл. Благодаря такому подходу при отладке можно сосредоточиться только на самом конфигурационном файле, а не вносить изменения в разные внешние файлы и искать "где же установлена та самая переменная окружения".
Обращаться к значениям пользовательских переменных в дальнейшем производится через такое выражение:
{{user `имя_переменной`}}
Везде, где Packer встретит подобное выражение, он заменит его на значение переменной с соответствующим именем.
Все пользовательские переменные мы будем устанавливать из переменных окружения. Использование переменных окружения, передаваемых в пользовательские переменные Packer, позволит нам сохраняя неизменным сам конфигурационный файл создавать с его помощью образы машин содержащие разные версии операционной системы, платформы 1С и СУБД. Хотя, как уже было упомянуто выше, во время отладки имеет смысл задавать значения переменных прямо в JSON-файле. Обратиться к переменной окружения можно используя выражение :
{{env `имя_переменной`}}
Общий список переменных можно увидеть в файле, ссылка на который дана выше. Но рассматривать их вне контекста пожалуй не имеет смысла. Поэтому сразу перейдем к следующему разделу, где будет множество выражений вида {{user `имя_переменной`}}.
Раздел "сборщиков". Выделение ресурсов виртуальной машине.
В блоке "builders" зададим настройки только для одного типа сборщиков. Это тип virtualbox-iso который обеспечивает установку гостевой машины через VirtualBox из iso-файла с дистрибутивом операционной системы.
"builders": [
{
"type": "virtualbox-iso",
"iso_url": "./iso/ubuntu-{{user `version_of_vm_os_with_dot`}}-live-server-amd64.iso",
"iso_checksum_type": "{{user `iso_checksum_type`}}",
"iso_checksum": "{{user `iso_checksum`}}",
"headless": false,
"communicator": "ssh",
"ssh_username": "{{user `ssh_username`}}",
"ssh_password": "{{user `ssh_password`}}",
"ssh_pty" : "true",
"ssh_timeout": "15m",
"shutdown_command": "{{user `shutdown_command`}}",
"shutdown_timeout": "360m",
"guest_os_type": "Ubuntu_64",
"vm_name": "{{user `vm_name`}}",
"disk_size": "{{user `disk_size_mb`}}",
"http_directory": "http_distr",
"floppy_files": [],
"boot_wait": "1m",
"boot_command": ["{{user `boot_command`}}"],
"guest_additions_mode": "upload",
"guest_additions_path": "~/VBoxGuestAdditions.iso",
"vboxmanage": [
[ "modifyvm", "{{.Name}}", "--memory", "2048" ],
[ "modifyvm", "{{.Name}}", "--vram", "128" ],
[ "modifyvm", "{{.Name}}", "--cpus", "2" ],
[ "modifyvm", "{{.Name}}", "--nic1", "nat" ],
[ "modifyvm", "{{.Name}}", "--clipboard", "bidirectional" ],
[ "modifyvm", "{{.Name}}", "--draganddrop", "bidirectional" ],
[ "modifyvm", "{{.Name}}", "--accelerate3d", "on" ],
[ "modifyvm", "{{.Name}}", "--graphicscontroller", "vboxsvga" ]
Вступайте в нашу телеграмм-группу Инфостарт
