В прошлой части мы рассмотрели возможности 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" ]
]
}
]
Рассмотрим основные параметры, определяемые в этом блоке.
iso_url
Здесь мы указываем относительный или абсолютный путь к дистрибутиву операционной системы - iso-файлу.
Командный файл, осуществляющий сборку, мы будем запускать из того же каталога, в котором находится JSON-файл Packer.
Поэтому путь к iso-файлу также задается относительно него. Имена файлов с дистрибутивами Ubuntu Server отличаются незначительно - только версией, указываемой в середине их имени: ubuntu-19.04-live-server-amd64.iso , ubuntu- 9.10-live-server-amd64.iso.
Поэтому для обеспечения возможности выбора дистрибутива достаточно ввести переменную, содержащую номер версии. Назовем её version_of_vm_os_with_dot . В разделе пользовательских переменных таким образом появится строка, объявляющая эту переменную и устанавливающую ее значение из одноименной переменной окружения:
"version_of_vm_os_with_dot": "{{env `version_of_vm_os_with_dot`}}"
В каталоге iso на хостовой машине будут находиться скрипты с простейшими командами PowerShell , которые позволят скачать нужные iso-файлы с дистрибутивами. Эти файлы доступны в репозиториях на gitlab и github
- https://github.com/VladimirLitvinenko84/ci-infrastructure-for-1c/blob/master/iso/download_ubuntu_19_10.ps1
- https://github.com/VladimirLitvinenko84/ci-infrastructure-for-1c/blob/master/iso/download_ubuntu_19_04.ps1
headless
Параметр "headless" определяет будет ли гипервизор сразу показывать нам окно с операционной системой (такому поведению соответствует значение false этого параметра), или запуск будет выполнен в фоновом режиме (для этого значение параметра должно быть равно true). Лучше устанавливать этот параметр в false, чтобы иметь возможность следить за процессом.
Параметры ssh
Далее мы указываем, что будем взаимодействовать с гостевой ОС через ssh и задаем имя пользователя и пароль (ssh_username и ssh_password). Это же имя пользователя и пароль мы будем задавать для администратора в процессе установки ОС.
shutdown_command
Указание "shutdown_command" вместе с длительным периодом "shutdown_timeout" необходимо для выполнения отладки. В "shutdown_command" задается команда, выполняемая в гостевой машине после выполнения всех инструкций из блока provisioners, перед тем, как управление будет передано инструкциям из блока post_processors. Packer попытается выполнить эту команду, после чего будет ждать завершения работы операционной системы в течение периода, указанного в параметре shutdown_timeout. Если за это время работа машины не завершится, то Packer будет считать сборку ошибочной и не передаст управление в блок post_processors.
Эта особенность позволяет применить следующий приём при отладке механизмов. Можно указать в качестве shutdown_command любую несуществующую команду, а в качестве shutdown_timeout большое значение, например 360 минут. Тогда в конце сборки Packer попытается выполнить эту команду. Она не приведет к выключению виртуальной машины и Packer перейдет в режим ожидания на целых 360 минут. В течение всего этого времени нам будет доступна виртуальная машина для изучения результатов установки.
Если же мы убедимся, что установка выполнена корректно, можно вручную завершить ее работу, после чего Packer передаст управление в блок post_processors. Когда мы убедимся, что весь процесс установки и упаковки проходит корректно, в параметре shutdown_command можно снова указывать команду, завершающую работу машины (например " sudo systemctl poweroff").
disk_size
Очень важный параметр, если Вы работаете на хостовой машине с небольшим объемом свободного места на диске. Установить его нужно так, чтобы хватило на установку всего необходимого ПО и развертывание тестовых баз, но при этом не было занято всё свободное место на дисках хостовой машины.
По умолчанию Packer создает диски с типом "dynamically allocated", то есть место под диски на хосте выделяется по мере необходимости. Но если на одном из узлов CI-контура будет производиться выгрузка хранилища в cf-файлы, то соответствующая этому узлу виртуальная машина окажется очень прожорливой в отношении дисков и быстро будет съедать всё доступное место. Видимо это особенность работы платформы 1С с временными файлами в процессе выгрузки версий хранилища, так как дисковое пространство не расходуется так быстро даже на тех машинах, где разворачиваются образы тестовых баз, выполняется загрузка конфигураций из cf-файлов и выполняется тестирование.
Например работая с конфигурациями "Управление торговлей" и "Комплексной автоматизацией" и выделив под каждую машину по 60 ГБ (это значение по умолчанию для disk_size) можно обнаружить, что через короткое время узел, на котором выполнялась только выгрузка хранилища начинает занимать почти 60 ГБ. А узлы, на которых выполняются более тяжелые операции развёртывания баз, ограничились 20-30 гигабайтами:
При этом если ограничить аппетиты каждой виртуальной машины размером, например 32 ГБ, то они все корректно работают. Поэтому disk_size будем устанавливать явно равным 32 ГБ. При необходимости Вы можете увеличить этот размер.
http_directory
На время своей работы Packer создает HTTP-сервер на хостовой машине со случайным портом (из определенного диапазона). Корневым каталогом для указанного сервера является каталог, указанный в параметре http_directory.
Информация о том, какой порт был выбран для этого HTTP-сервера появляется в логах в самом начале сборки, еще до того как начала создаваться виртуальная машина:
Это позволяет скачивать все необходимые файлы с хостовой машины по "вездеходному" протоколу http. Например утилитой wget:
wget -r -np -nH --cut-dirs 2 -P /home/vagrant/distrs/pg http://$PACKER_HTTP_ADDR/postgresql_for_1c/11_5
Было бы удобно сделать то же самое задав параметр-массив floppy_files, указав в нем файлы, которые окажутся на виртуальном флоппи-диске. Но VirtualBox контролирует общий размер этих файлов и если он превышает размер трехдюймовой дискеты, то выдает ошибку. Поэтому параметр floppy_files в данном контексте для нас бесполезен.
Параметры Guest Additions
Здесь мы указываем , что дополнения гипервизора надо загрузить в файловую систему виртуальной машины и куда именно нужно их загрузить:
"guest_additions_mode": "upload",
"guest_additions_path": "~/VBoxGuestAdditions.iso",
vboxmanage
Здесь мы указываем какие ресурсы выделяем машине на этапе сборки. Например объем ОЗУ и видеопамяти в мегабайтах, параметры работы с буфером обмена.
Так как мы будем устанавливать дополнения гипервизора в виртуаьной машине, то можно настроить двунаправленный буфер обмена и драг-н-дроп. Это сильно упростит как отладку сборки образа, так и последующую работу с узлами CI-контура.
При сборке виртуальной машины должен быть определен виртуальный сетевой адаптер, чтобы было возможно взаимодействие по ssh и обращение к временному веб-серверу. На самом сетевых адаптеров можно определить несколько. Но первым всегда должен быть адаптер с типом NAT - это особенность как Packer, так и Vagrant.
"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" ]
]
boot_wait
Параметр boot_wait задает время ожидания начала загрузки, после которого Packer начнет эмулировать ввод с клавиатуры, передавая команды, заданные в boot_command. Как правило здесь достаточно задать 1 минуту. А параметр boot_command мы разберем подробнее далее.
Установка операционной системы
В процессе установки операционной системы нужно выполнить ее базовую конфигурацию:
- выбрать язык,
- разметить диск,
- задать имя администратора и его пароль,
- указать настройки обновления.
Для того чтобы сделать это в случае с Ubuntu (и рядом других дистрибутивов Linux) есть два варианта.
Первый вариант - использовать файл preceed.cfg
Этот файл имеет специальный формат. Пример такого файла можно увидеть здесь: https://help.ubuntu.com/lts/installation-guide/example-preseed.txt
Однако в этом случае мало будет разобраться с форматом этого файла и создать подходящий для нашей установки. В отличие от Windows, где аналогичный файл можно просто разместить на дискете, в случае с Linux нельзя просто так передать этот файл инсталлятору операционной системы. Нужно сначала ввести некоторые команды с клавиатуры. А поскольку мы выполняем автоматическую установку, то нужно обеспечить эмуляцию ввода.
Достигается эмуляция ввода с помощью упомянутого выше параметра " boot_command " . Прочитать про формат этого параметра можно в разделах документации Packer, посвященных сборщикам:
- https://www.packer.io/docs/builders/vmware-iso.html
- https://www.packer.io/docs/builders/virtualbox-iso.html
Суть в том, что для каждой специальной клавиши в этом параметре предусмотрено символьное представление. Например <bs> соответствует клавише Backspace, <enter> - клавише ввода, также есть специальная запись, означающая необходимость ожидания - <wait> с возможностью указания интервала ожидания. Если символы не обернуты в угловые скобки, то они представляют сами себя.
Чтобы передать управление файлу preceed.cfg нужно расположить этот файл в каталоге хостовой машины, который мы ранее указывали в параметре http_directory, и затем задать параметр boot_commad примерно такого содержания:
"boot_command": " <tab><wait><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>/linux initrd=/initrd.gz auto=true noapic=true fb=false hostname=localhost locale=en_US keyboard-configuration/modelcode=SKIP preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg<enter>",
Данный пример взят отсюда: https://raw.githubusercontent.com/uchida/packer-ubuntu/82fb63c4e8c7548e27f3750a82bff66f2c65a9aa/template.json
В данной записи {{ .HTTPIP }}:{{ .HTTPPort }} представляют собой IP-адрес и порт временно поднятого Packer-ом веб-сервера, корневым каталогом которого является каталог заданный в параметре http_directory. В других блоках конфигурационного JSON файла нельзя использовать такое выражение для обращения к веб-серверу Packer. Вместо него нужно использовать $PACKER_HTTP_ADDR, которое не позволяет получить отдельно IP-адрес и отдельно порт. Почему так сделано я не знаю. Может быть механизмы писались разными разработчиками, как это часто бывает ))
Второй способ - использовать только boot_command для эмуляции действий пользователя
Этот способ может понравиться тем, кто использует сценарное тестирование в 1С, так как эффект получается похожий )) Для себя я выбрал именно его.
В этом случае мы не передаем операционной системе файл preceed.cfg , а производим установку так, как если бы она выполнялась полностью вручную. При этом эмулируем абсолютно все действия пользователя с помощью boot_command.
Действуя таким образом можно добиться эффекта "автоматического ввода с клавиатуры". Понравился он мне также и тем, что расставив паузы в нужных местах легко отладить весь процесс и увидеть, где необходимо внести правки, а завершив отладку снять паузы и получить достаточно быстрый процесс установки:
По записи видно, что требуется сэмулировать совсем немного действий. Но проблема в том, что если мы запишем параметр boot_command так, как это предполагают разработчики Packer и как это делает большинство авторов на гитхабе, то даже для эмуляции такого небольшого числа действий у нас получится нечитаемая билиберда. Вот такая:
"boot_command": [ "<down><down><down><down><down><down><down><down><down><down><down><down><down><enter><wait>","<enter><wait>","<up><up><up><enter><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><down><enter><wait>","<down><down><down><enter><wait>","<up><enter><down><enter><down><enter><wait>","<enter><wait>","<enter><wait>","<enter><wait>","<enter><wait>","<enter><wait>","<enter><wait>","<enter><wait>","<down><enter><wait>","vagrant<enter>","vagrant-ci<enter>","vagrant<enter>","vagrant<enter>","vagrant<enter>","<enter><wait>","<enter><down><down><enter><wait>","<tab><enter><wait>","<wait4m>","<enter>","<wait10s><enter>"]
Это массив строк, каждая из которых отвечает за отдельный экран инсталлятора. Часть команд - это выбор языка, часть - разметка диска, часть - ввод имени пользователя. Но понять, что значит каждый символ в этой свалке совершенно невозможно! Разместить в JSON-файле комментарии, поясняющее происходящее, тоже невозможно - формат JSON не предусматривает комментариев.
В то же время есть хорошая альтернатива. Её дают нам пользовательские переменные, которые можно использовать в любом месте конфигурационного файла Packer. Можно задать boot_command следующим образом:
"boot_command": ["{{user `boot_command`}}"]
А дальше дело за малым - сформировать переменную окружения и передать ее в пользовательскую переменную, записав в разделе variables строку
"variables": {
"boot_command": "{{env `boot_command`}}"
}
При этом даже в Windows есть способы установить переменную окружения из текстового файла. Выберем в качестве расширения для такого файла .cfg. Это позволит очень удобно править его в Visual Studio Code. В этом случае строки, начинающиеся с символа # будут отображаться как комментарии:
Для того, чтобы в Windows установить значение переменной окружения из консольного вывода команды cat придется воспользоваться промежуточным файлом. В этот файл мы будем записывать вывод команд grep, sed и tr, которые задействуем чтобы удалить из файла комментарии и объединить оставшиеся строки в одну:
1) Выводим в файл преобразованный текст:
grep -v '#' boot_command_%version_of_vm_os_with_underscore%.cfg | sed 's/{{user `ssh_username`}}/%ssh_username%/' | sed 's/{{user `ssh_password`}}/%ssh_password%/' | sed 's/{{user `hostname`}}/%virtual_machine_hostname%/' | tr -d '\n' | tr -d '\r' > boot_command_temp.txt
2) Устанавливаем значение переменной окружения из файла
set /P boot_command=< boot_command_temp.txt
3) Удаляем более ненужный файл
rm -f boot_command_temp.txt
После выполнения этих команд у нас будет переменная окружения boot_command содержащая значение, пригодное для передачи в одноименный параметр в конфигурационный файл Packer.
В нашем репозитории сформированные таким образом файлы называются boot_command_19_10.cfg и boot_command_19_04.cfg.
Два разных файла нужны потому что последовательность команд для Ubuntu 19.04 и Ubuntu 19.10 будет немного отличаться. Поэтому на вход утилите grep будем передавать не фиксированное имя файла , а имя с использованием другой переменной окружения, определяющей, какую версию операционной системы мы хотим установить:
grep -v '#' boot_command_%version_of_vm_os_with_underscore%.cfg
В самих cfg-файлах использованы выражения вида {{user `ssh_username`}}, {{user `ssh_password`}}, {{user `hostname`}}. Такая запсиь позволяет сохранить исходный синтаксис Packer. Но при формировании переменной окружения их надо заменить на конкретные значения, которые передаются в переменные ssh_username , ssh_password и hostname .
Так как значения этих переменных в файле Packer мы формируем из одноименных переменных окружения, то здесь тоже имеет смысл сделать аналогичную замену. Поэтому сразу после grep применяется утилита sed :
sed 's/{{user `ssh_username`}}/%ssh_username%/'
и
sed 's/{{user `hostname`}}/%virtual_machine_hostname%/'
Хотелось бы обратить внимание на время ожидания, задаваемое в конце файла. Строка <wait14m> или <wait11m> определяет время ожидания равное 11-14 минут - это время ожидания основной установки и установки обновлений безопасности. В течение этого времени Packer не будет пытаться эмулировать никаких действий пользователя. Этот интервал вычисляется эмпирически и может расти с течением времени, так как количество загружаемых обновлений для операционных систем с течением времени растет, увеличивая полное время установки. Если у Вас при наличии быстрого компьютера и интернета установка завершается быстрее, чем за 14 минут, то этот интервал можно уменьшить. Но сделайте это сами, исходя из возможностей своего оборудования. А текущее значение в 14 минут оставим в репозитории, как более безопасное для большинства случаев, включающих работу на маломощных хостовых машинах.
Появление на экране надписи copying logs to installed system уже означает возможность корректной перезагрузки. Но не нужно делать это вручную - дождитесь пока отработает boot_command и сам нажмёт команду Reboot:
Собственно результат от такого задания boot_command Вы уже видели выше - это будет автоматический ввод нужных символов на всех экранах инсталлятора Ubuntu. На этом рассмотрение блока builders заканчивается. Переходим к блоку provisioners и скриптам установки необходимого программного обеспечения.
Принцип разделения команд в блоке provisioners
Итак, теперь мы находимся в блоке "provisioners": [……]. Данный блок представляет из себя JSON-массив, где задаются команды, выполняемые на стороне виртуальной машины. К моменту, когда управление передается этому блоку, операционная система уже установлена и с ней уже установлено ssh-соединение.
Каждый элемент массива "provisioners" позволет выполнить произвольное количество команд и выглядит следующим образом:
{
"pause_before": "50s",
"type": "shell",
"valid_exit_codes": [ 0, 100 ],
"expect_disconnect": "true",
"pause_before": "50s",
"inline": [
"echo ============== Комментарий к командам ==============",
"команда 1",
"команда 2",
"команда 3"
]
},
Все команды , указанные в массиве inline будут упакованы в один командный файл, помещены внутрь виртуальной машины в каталог временных файлов и затем выполнены как единый bash-скрипт.
В каждом блоке первой командой у нас будет echo. Эта команда выступает в роли комментария, так как другого способа задать комментарии к отдельным блокам в JSON-файле нет. Также вывод команд команд echo позволяет быстрее находить нужный текст в логах сборки и выполнять отладку.
Следует стараться минимизировать количество команд в каждом таком блоке, не смешивая разные по смыслу последовательности команд. Это позволит не только лучше структурировать файл JSON , но и упростить отладку. Лучше разделить команды на несколько небольших блоков, в каждом из которых будут находиться связанные по смыслу команду:
- Устанавливаем платформу 1С - выделяем отдельный блок
- Устанавливаем графическое окружение - создаём другой блок.
- Устанавливаем Apache - выделяем ещё один блок.
Есть и другие веские причины для разделения команд на разные блоки:
1) Перезагрузка машины
Результат некоторых команд может быть применен к системе только после ее перезагрузки, но при этом будет нужен для выполнения следующих за ними команд. В этом случае команды, приводящие к перезагрузке, требуется выделить в отдельный блок и указать в нем параметр "expect_disconnect": "true". Если не указать этот параметр, то в случае перезагрузки Packer решит, что произошла ошибка и аварийно завершит сборку. Если же этот параметр будет указан, то перезагрузка системы не будет воспринята как ошибка сборки.
Сразу после команд, ведущих к перезагрузке будут идти блоки со свойством "pause_before": "50s". Или другим длительным интервалом. Это необходимо, чтобы сразу после установки ssh-соединения с перезагруженной системой, Packer не торопился выполнять следующие команды, а немного подождал. Это позволит нам дождаться полной загрузки ОС и уменьшить вероятность ошибок.
2) Ненулевой код возврата, не являющийся ошибкой
Ещё один случай , когда следует отделить блок команд от остальных - это возможность ненулевого кода возврата после их выполнения. Packer по умолчанию считает, что если код возврата после выполнения команды не равен нулю, то произошла ошибка, и прерывает процесс сборки. Однако бывает случаи, когда код возврата не нулевой, а команда фактически выполнена корректно.
Например бывали случаи (хотя уже довольно давно) когда выполнялась установка OneScript с сайта oscipt.io и последующая установка его библиотек через команду opm install -all. В целом установка проходила корректно. Но одна из библиотек неожиданно требовала версию OneScript, которая есть на гитхабе, но которая еще не появилась на сайте oscript.io, откуда мы загружаем дистрибутив. Код возврата в этом случае будет 255:
Или мы устанавливаем эмулятор терминала Terminator. Он устанавливается корректно, но жалуется на какую-нибудь мелочь в системе и устанавливает код возврата 100.
Команды, которые несмотря на ненулевой код возврата выполняются успешно, выявляются эмпирически. То есть надо попробовать их выполнить, посмотреть на результат, вывести echo $?. Если результат нас устраивает, а код возврата не нулевой, то записываем полученный код в список разрешенных. Делается это через перечисление допустимых кодов в соответствующем массиве: "valid_exit_codes": [ 0, 100 ].
Далее я не буду специально останавливаться на том, что ту или иную команду надо выделить в отдельный блок по этой причине. Если Вы видите в блоке с командой свойство valid_exit_codes - значит это тот самый случай ))
Разрешаем пользователю выполнять административные действия без ввода пароля
В операционной системе Ubuntu пользователи, входящие в группу sudoers могут выполнять команды с правами суперпользователя, но для этого потребуется явно вводить пароль. В то же время в процессе сборки образа ОС нам требуется выполнять множество команд с правами суперпользователя и делать это необходимо неинтерактивно. Поэтому первое, что требуется сделать - отключить необходимость ввода пароля при выполнении таких команд.
Сделать это можно внеся изменения в файл /etc/sudoers. Но для этого опять же необходимо задавать пароль. Как этого избежать описано в документации к Packer : https://www.packer.io/docs/provisioners/shell.html
Нам достаточно выполнить команду echo '{{user `ssh_password`}}' | {{ .Vars }} sudo -E -S sh '{{ .Path }}'
где
- {{ .Path }} - это в свою очередь команда "echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers", которую Packer возьмёт из свойства inline .
- ssh_password - это переменная, которую мы уже рассматривали, в ней хранится пароль администратора системы.
- и вместо {{ .Vars }} будут автоматически подставлены переменные окружения, что в общем-то не нужно в данном случае, но документация к Packer предлагает такую запись и мы её сохраним.
Таким образом первым элементом в коллекции provisioners будет следующий:
{
"type": "shell",
"execute_command": "echo '{{user `ssh_password`}}' | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
"inline": [
"echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers"
]
},
Графическое окружение
Согласно схемам, рассмотренным в первой части у нас будет два вида узлов. Один предназначен для мониторинга новых версий хранилища, запуска основной задачи сборки и, возможно, для выгрузки версий из хранилища в cf-файлы. Другой тип предназначен для выполнения основной сборки и тестирования, а также подготовки образа тестовой базы.
Очевидно, что для узлов второго типа, выполняющих сценарное тестирование, понадобится графическое окружение. Но также очевидно, что для выполнения консольных команд выгрузки версий хранилища в cf-файлы и получения списка версий хранилища графическое окружение не нужно и для этого достаточно только легковесного Ubuntu Server…...
Как бы не так! ;)) Возможно Вы удивитесь, но даже для выполнения консольных команд конфигуратора 1С, не приводящих к появлению каких-либо окон, необходимо наличие графической среды. Иначе конфигуратор выдаст ошибку. В Linux с этим приходится мириться, как с одной из странностей платформы, рожденной в мире Windows.
Таким образом графическое окружение нам необходимо поставить в любом случае. Выполнить его установку можно следующей командой:
{
"type": "shell",
"inline": [
"echo ============== INSTALLING DESKTOP ==============",
"sudo apt-get update",
"sudo apt-get install -y --no-install-recommends ubuntu-desktop"
]
},
При этом важным является параметр --no-install-recommends. Без него при установке пакета ubuntu-desktop в систему будут затянуто огромное количество ненужных нам приложений, которые с точки зрения мейнтейнеров Ubuntu полезны для десктопной операционной системы, но будут бесполезны на CI. Это не только приведет к излишнему увеличению объема образа нашей ОС, но и может замедлить процесс установки в несколько раз.
Ранее уже упоминалось, что для целей CI самым подходящим является окружение LXDE
- Оно гораздо менее требовательно к ресурсам и является одним из самых легковесных окружений, сохраняя при этом удобства использования.
- В отличие от Gnome оно не обладает "вредной привычкой" сообщать о том, что программа зависла, уже после того как программа не отвечала всего две секунды. Да, сейчас Gnome "из коробки" ведет себя именно так, что очень мешает при работе с 1С.
Если Вы решите установить LXDE вместо Gnome, то сделать это можно аналогичной командой:
- sudo apt-get install -y --no-install-recommends lxde
- или sudo apt-get install -y --no-install-recommends lubuntu-desktop
Но в случае выбора LXDE необходимо будет также изменить настройки автологона, а впоследствии и автозапуска агента Jenkins. Для этого сейчас мы будем применять специфичные механизмы среды Gnome.
Настройка машины как узла CI
Если бы наша виртуальная машина не выступала в качестве узла CI контура, то действия, описанные вы этом блоке, можно было бы пропустить. Но в такой роли она должна сразу после загрузки обеспечить доступ к рабочему столу и не должна ни в коем случае затемнять или блокировать экран. Для этого требуется выполнить ряд специфичных для среды Gnome команд. Также имеет смысл отключить энергосбережение.
На Ubuntu 19.04, и возможно более ранних версиях, выполнение команд вида gsettings set ... , отключающих блокировку экрана, требует запущенного графического окружения, без которого мы получим ошибку:
failed to commit changes to dconf: Cannot autolaunch D-Bus without X11 $DISPLAY
Поэтому после установки пакета ubuntu-desktop выполним перезагрузку системы и подождём примерно 50 секунд пока загрузится графическое окружение:
{"type": "shell", "expect_disconnect": "true", "inline": [ "sudo systemctl reboot"]},
{
"pause_before": "50s",
"type": "shell",
"inline": [
"echo ============== ENABLING AUTOLOGON ==============",
"sudo sed -i \"s/.*AutomaticLoginEnable =.*/AutomaticLoginEnable = true/\" /etc/gdm3/custom.conf",
"sudo sed -i \"s/.*AutomaticLogin =.*/AutomaticLogin = {{user `ssh_username`}}/\" /etc/gdm3/custom.conf",
"echo ====== DISABLING LOCKDOWN, SCREENSAVER, SWITCHING OFF DISPLAY ==============",
"gsettings set org.gnome.desktop.session idle-delay 0",
"gsettings set org.gnome.desktop.lockdown disable-lock-screen 'true'",
"gsettings set org.gnome.desktop.screensaver lock-enabled 'false'",
"echo ====== DISABLING POWER SAVING ==============",
"sudo apt-get install -y pm-utils",
"sudo pm-powersave false"
]
},
Инструменты для конфигурирования и разработки
Здесь мы установим эмулятор терминала Terminator и Visual Studio Code. Разумеется Вы можете заменить их на альтернативы, но в репозитории присутствует код установки именно этих инструментов, поэтому рассмотрим связанные с этим особенности.
Terminator устанавливается всего одной командой. А вот с VSC сложнее. Его репозиторий не включен в список стандартных репозиториев Ubuntu (поддерживаемых мейнтейнерами этого дистрибутива Linux). Поэтому нам необходимо самостоятельно добавить ключ этого репозитория и его адрес в списки репозиториев. Но этого мало. Некоторые пакеты, которые присутствуют в репозитории VSC совпадают по именам с пакетами из стандартных репозиториев и в дальнейшем это будет приводить к лишним предупреждениям от утилит apt и apt-get. Поэтому сразу после установки удалим репозиторий VSC из списков репозиториев в нашей системе.
{
"type": "shell",
"valid_exit_codes": [ 0, 100 ],
"inline": [
"echo ============== INSTALLING TERMINATOR ==============",
"sudo apt-get install terminator -y"
]
},
{
"type": "shell",
"inline": [
"echo ============== INSTALLING VISUAL STUDIO CODE ==============",
"sudo apt-get install -y software-properties-common apt-transport-https wget",
"wget -q https://packages.microsoft.com/keys/microsoft.asc -O- | sudo apt-key add -",
"sudo add-apt-repository \"deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main\"",
"sudo apt-get update",
"sudo apt-get install -y code",
"sudo rm /etc/apt/sources.list.d/vscode.list"
]
},
Сетевые утилиты
Установка Samba позволяет обнаруживать Linux машины по их именам со стороны Windows (по hostname).
Установка Avahi в свою очередь позволяет обнаруживать Windows машины со стороны Linux-машин по их имени.
traceroute может помочь обнаружить проблемы с сетью. Например можно обнаружить потерю части пакетов при фактически стабильном канале связи. Это может свидетельствовать о конфликте IP адресов в подсети, что решится переназначением IP адресов. Понадобиться это может уже после того, как мы запустим виртуальные машины с помощью Vagrant , так как на этапе сборки образа машины через Packer мы используем только один виртуальный сетевой адаптер с типом NAT, а при развертывании набора машин через Vagrant будем осуществлять подключение еще и к физическому адаптеру с типом соединения bridge.
{
"type": "shell",
"inline": [
"echo ============== INSTALLING AVAHI, SAMBA and TRACEROUTE ==============",
"sudo apt-get install -y avahi-discover",
"sudo apt-get install -y samba",
"sudo apt-get install -y traceroute"
]
},
Среды исполнения Java и OneScript
Jenkins работает с версиями Java 8 и Java 11. На хостовой машине Jenkins будет использовать ту JRE, которая идёт в составе дистрибутива самого Jenkins. Но в виртуальной машине мы не будем устанавливать сам Jenkins, а будем только запускать его агентов, поэтому потребуется отдельная установка Java.
Традиционно для Jenkins используется Java 8. Для Linux можно выбрать пакет OpenJKD 8, а именно openjdk-8-jre-headless.
OneScript использоваться в наших скриптах и пайплайнах не будет, поэтому его установку можно пропустить. Но с другой стороны он может пригодиться для самых разных целей в дальнейшем и поэтому здесь приведены команды для его установки. Скачать нужную версию пакета можно воспользовавшись утилитой wget. OneScript также требует установленного mono, так как написан на .Net. Ну и конечно имеет смысл сразу установить библиотеки через команду opm install:
{
"type": "shell",
"inline": [
"echo ============== INSTALLING JAVA 8 FOR JENKINS NODE ==============",
"sudo apt-get install -y openjdk-8-jre-headless",
]
},
{
"type": "shell",
"valid_exit_codes": [ 0, 255 ],
"inline": [
"echo ==================== INSTALLING ONESCRIPT ==============",
"sudo apt-get install -y mono-runtime || true",
"sudo apt-get --fix-broken install -y",
"wget -O one_script.deb http://oscript.io/downloads/1_1_1/onescript-engine_1.1.1_all.deb",
"sudo dpkg -i one_script.deb || true",
"sudo apt-get --fix-broken install -y",
"sudo opm install -all"
]
},
Дополнения VirtualBox
Это то, что позволит нам удобно пользоваться буфером обмена, перетаскивать файлы между машинами, подключать общие каталоги с хостовой машины, устанавливать удобное разрешение экрана.
В разделе builders мы уже дали Packer инструкцию скопировать дополнения в домашний каталог пользователя (у нас им будет пользователь с именем vagrant). Теперь достаточно примонтировать их как отдельный диск, установить и перезагрузиться. Только после перезагрузки мы сможем пользоваться всеми преимуществами дополнений.
Для того, чтобы наш пользователь имел доступ к каталогам хостовой Windows-машины, примонтированным в гостевую систему службами VirtualBox надо добавить пользователя в группу vboxsf.
Для установки высокого разрешения нужно дождаться, пока завершится процесс автологона и завершения запуска графического разрешения. Для этого используется команда xrandr , работающая только в контексте текущего пользователя после того, как будет доступно графическое окружение ( заметьте, что выполняется она при этом через ssh-подключение ).
{
"pause_before": "50s",
"type": "shell",
"valid_exit_codes": [ 0, 2 ],
"inline": [
"echo ============ INSTALLING GUEST ADDITION AND BUILD TOOLS THAT ARE REQUIRED BY GEST ADDITIONS ===========",
"sudo apt-get install -y linux-headers-$(uname -r) build-essential dkms",
"sudo mkdir /media/iso_guest_additions",
"sudo mount -o loop ~/VBoxGuestAdditions.iso /media/iso_guest_additions",
"sudo /media/iso_guest_additions/VBoxLinuxAdditions.run"
]
},
{"type": "shell", "expect_disconnect": "true", "inline": [ "sudo systemctl reboot"]},
{
"pause_before": "50s",
"type": "shell",
"inline": [
"echo ====== ADDING USER TO vboxsf SO IT CAN ACCESS DIRECTORIES MOUNTED BY VirtualBox FROM HOST ==============",
"sudo adduser {{user `ssh_username`}} vboxsf",
"echo ====== CHANGING RESOLUTION. USER MUST BE LOGGED IN USING UBUNTU DESKTOP INTERFACE =======================",
"xrandr -display :0.0 -s 1600x1200"
]
},
Расположение дистрибутивов 1C и PostgreSQL
Прежде чем переходить к рассмотрению процесса установки PostgreSQL и 1С напомню, что мы будем скачивать их с хостовой машины, пользуясь автоматически поднятым специально для этих целей веб-сервером. Packer делает это за нас, ничего предпринимать для работы этого веб-сервера не нужно.
Адрес этого сервера доступен через переменную $PACKER_HTTP_ADDR и увидеть его в логах можно выполнив например такую диагностическую команду:
{
"type": "shell",
"inline": ["echo Diagnostic message - Packer http server pointed to distrs directory is $PACKER_HTTP_ADDR"]
},
Корневым каталогом веб сервера мы указывали каталог хостовой машины http_distr - в разделе builders у нас была строка
"http_directory" : "http_distr" ,
Каталог http_distr находится прямо в корне нашего репозитория, там же, где и конфигурационный JSON-файл для Packer. Скачивать дистрибутивы в виртуальную машину из этого каталога мы будем пользуясь утилитой wget.
При этом расположение дистрибутивов в этом каталоге во многом связано с особенностями установки платформы 1С и PostgreSQL. Алгоритм установки платформы 1С слабо зависит от номера версии и поэтому для ее установки можно использовать один и тот же скрипт и располагать пакеты в одном и том же каталоге.
Устновка пакетов PostgreSQL взятых с сайта https://releases.1c.ru/ гораздо больше зависит от номера версии, поэтому для каждой версии мы будем использовать свой скрипт, и пакеты разместим каждый в своём каталоге.
Разумеется я не могу размещать дистрибутивы 1С и сборки PostgreSQL с сайта ИТС прямо в репозитории на Гитхабе или давать прямые ссылки на них. Уж таковы требования фирмы на этот счёт. Вам придётся скачать их самостоятельно.
Структура каталогов и файлов каталога http_distr в итоге должна выглядеть так:
Важно! Дистрибутивы не будут удаляться из гостевой машины Linux после копирования в неё и установки. Это сделано для удобства отладки, к которой Вам скорее всего придётся прибегнуть хотя бы раз в процессе сборки. Сохранение дистрибутивов в составе машины с Linux увеличивает размер итогового образа примерно на 1 ГБ. Если Вы хотите сэкономить это место на дисках, то добавьте команды по удалению дистрибутивов самостоятельно. Рекомендую сделать это одним из последних этапов сборки, когда будет ясно, что все остальные этапы завершились успешно. Тогда, если сборка прервётся на одном из этапов, то можно будет заглянуть в виртуальную машину и выполнить в ней отладочные действия, при этом имея в ней все необходимые дистрибутивы.
Установка платформы 1С
Установку выполняем следующим образом. Сначала через веб-сервер Packer загружаем необходимые пакеты и установочный скрипт с хостовой машины в домашний каталог нашего пользователя внутри виртуальной машины:
{
"type": "shell",
"inline": [
"echo ====== COPYING 1C INSTALLATION PACKAGES AND SCRIPT ==============",
"wget -P /home/{{user `ssh_username`}}/distrs/1c http://$PACKER_HTTP_ADDR/distrs1c/deb64_{{user `version_of_1c_platform_with_underscores`}}.tar.gz",
"wget -P /home/{{user `ssh_username`}}/distrs/1c http://$PACKER_HTTP_ADDR/distrs1c/client_{{user `version_of_1c_platform_with_underscores`}}.deb64.tar.gz",
"wget -P /home/{{user `ssh_username`}}/distrs/1c http://$PACKER_HTTP_ADDR/distrs1c/install_1c_bandle.sh"
]
},
После чего запустим скрипт на выполнение, указав ему в качестве параметра, с какой именно версией платформы мы будем работать:
{
"type": "shell",
"valid_exit_codes": [ 0, 1 ],
"inline": [
"echo ==================== INSTALLING 1C ==============",
"cd /home/{{user `ssh_username`}}/distrs/1c",
"bash ./install_1c_bundle.sh {{user `version_of_1c_platform_with_underscores`}}"
]
},
Для указания версии платформы во всех командах будем использовать переменную окружения и соответствующую ей пользовательскую переменную Packer с именем version_of_1c_platform_with_underscores. В ней будем хранить значение версии, но не с точками, а с символами подчеркивания в качестве разделителя составных частей версии. То есть вместо 8.3.16.1063 будем указывать 8_3_16_1063. Так проще работать с именами файлов, скачиваемых со страницы релизов платформы - у них в именах файлов именно подчеркивания.
Дистрибутивы платформы Вам необходимо самостоятельно скачать со страницы https://releases.1c.ru/project/Platform83 и разместить их в каталоге http_distr. Скачать необходимо дистрибутивы толстого клиента и сервера нужных вам версий. Установив дистрибутив толстого клиента мы получим возможность запускать 1С и в режиме тонкого клиента.
Скрипт install_1c_bundle.sh, входящий в состав нашего репозитория, рассчитан на установку любого релиза 64-битной платформы. Если у Вас возникнет потребность выполнить установку 32-битной платформы (ну хотя бы потому, что у многих она проще запускается ;)), то её можно выполнить по аналогии. Сам скрипт установки очень похож на те, которые можно в большом количестве встретить в сети. Но при этом есть несколько значительных отличий.
В командном файле мы принимаем на вход параметр - номер версии с символами подчеркивания. Разбиваем версию на составляющие и заново склеиваем ее, чтобы сформировать номер таким образом, как он указывается в файлах внутри архивов в deb-пакетами платформы:
version_of_1c_platform_with_underscores=$1
FIRST_NUMBER_OF_1C_VERSION=`echo $version_of_1c_platform_with_underscores | cut -d "_" -f 1`
SECOND_NUMBER_OF_1C_VERSION=`echo $version_of_1c_platform_with_underscores | cut -d "_" -f 2`
THIRD_NUMBER_OF_1C_VERSION=`echo $version_of_1c_platform_with_underscores | cut -d "_" -f 3`
FORTH_NUMBER_OF_1C_VERSION=`echo $version_of_1c_platform_with_underscores | cut -d "_" -f 4`
PACKAGE_SUBNAME="$FIRST_NUMBER_OF_1C_VERSION.$SECOND_NUMBER_OF_1C_VERSION.$THIRD_NUMBER_OF_1C_VERSION"
PACKAGE_SUBNAME+="-"
PACKAGE_SUBNAME+=$FORTH_NUMBER_OF_1C_VERSION
PACKAGE_SUBNAME+="_amd64"
Особым образом устанавливаются шрифты mscorefonts.
Все примеры, найденные мной в сети на самом деле применимы к системе Debian, хотя авторы приводят их также в контексте установки на Ubuntu. Как это ни странно, репозитории Ubuntu уже очень давно отстают в актуальности этих пакетов от репозиториев Debian. Если мы просто выполним команду sudo apt-get install ttf-mscorefonts-installer, то впоследствии при запуске 1С будет выдавать диалоговые окна с предупреждением о нехватки некоторых шрифтов. Это лишит нас возможности запускать сценарные тесты без лишних сложностей.
Поэтому мы не будем использовать данную команду, а обратимся напрямую к репозиторию Debian и возьмем необходимый пакет из него. Так как мы устанавливаем файл .deb , то имеет смысл после этого выполнить команду sudo apt-get --fix-broken -y install чтобы доустановить зависимости и избежать ошибок при выполнении следующих команд apt-get.
wget http://ftp.de.debian.org/debian/pool/contrib/m/msttcorefonts/ttf-mscorefonts-installer_3.7_all.deb
sudo dpkg -i ttf-mscorefonts-installer_3.7_all.deb
sudo apt-get --fix-broken -y install
Установка libwebkitgtk-3
Начиная с версии 19.04 Disco Dingo пакет libwebkitgtk-3.0 больше не входит в состав репозиториев Ubuntu. Однако для установки платформы 1С он необходим. На Инфостарте можно найти совет, как его установить: https://forum.infostart.ru/forum86/topic218020, а именно добавить в списки пакетного менеджера строку "deb http://ru.archive.ubuntu.com/ubuntu/ cosmic main universe".
До недавнего времени можно было воспользоваться этим советом. Но поддержка версии Ubuntu Cosmic Cuttlefish была прекращена уже очень давно - в июле 2019 года. И вот недавно репозиторий был удален с archive.ubuntu.com. Теперь для установки libwebkitgtk-3.0-0 лучше воспользоваться репозиторием Bionic Beaver. Это LTS релиз и его поддержка заявлена до 2023 года.
Установив пакет libwebkitgtk-3.0-0 снова потребуется выполнить команду sudo apt-get --fix-broken -y install для решения проблем с зависимостями. Таким образом для установки пакета подходят следующие команды:
sudo sh -c 'echo "deb http://ru.archive.ubuntu.com/ubuntu/ bionic main universe" > /etc/apt/sources.list.d/old1c_libs.list'
sudo apt-get update
sudo apt-get install -y libwebkitgtk-3.0-0
sudo apt-get --fix-broken -y install
После установки платформы 1С необходимо выполнить ещё ряд действий, связанных с тем, что наша машина будет функционировать как узел CI-контура.
Во первых, разрешим выполнять небезопасные действия. Это необходимо для возможности инициализировать тестовые базы через запуск внешних обработок из командной строки, для запуска Vanessa Automation, а также для того, чтобы система не блокировала тестовые расширения конфигурации. Сделать это можно записав строку DisableUnsafeActionProtection=.* в конфиуграционный файл conf.cfg. При этом каталог для него /opt/1C/v8.3/x86_64/conf необходимо создать самостоятельно. В отличие от Windows этот каталог не будет создан при установке платформы 1С.
Во вторых, обеспечим автоматический запуск RAS для администрирования сервера 1С и включим возможность отладки на сервере.
Сделать это можно с помощью уже знакомой нам утилиты sed, отредактировав с помощью нее файл, управляющий запуском демонов 1С. Найдем строку, управляющую режимом отладки и присвоим параметру SRV1CV8_DEBUG значение 1
sudo sed -i "s/.*SRV1CV8_DEBUG=.*/SRV1CV8_DEBUG=1/" /etc/init.d/srv1cv83
Далее добавим в конец этого файла команду запуска RAS, задействовав уже объявленные ранее в файле srv1cv83 переменные окружения
sudo sed -i "s/echo \${mypid} > \"\$SRV1CV8_PIDFILE\"/echo \${mypid} > \"\$SRV1CV8_PIDFILE\"\n\n \$G_BINDIR\/ras --daemon cluster/" /etc/init.d/srv1cv83
Это некрасивое и топорное решение. Но для наших ткущих целей вполне подойдёт ))
И в завершении надо не забыть сделать владельцем каталога /opt/1C пользователя под которым запускается демон и группу grp1cv8. Важно сделать это самой последней командой, чтобы поменять права рекурсивно на все файлы и каталоги внутри /opt/1C, включая те файлы, которые мы создаём самостоятельно.
В целом командный файл выглядит следующим образом:
#!/bin/bash
version_of_1c_platform_with_underscores=$1
TAR_SUBNAME=$version_of_1c_platform_with_underscores
echo "TAR_SUBNAME is $TAR_SUBNAME"
FIRST_NUMBER_OF_1C_VERSION=`echo $version_of_1c_platform_with_underscores | cut -d "_" -f 1`
SECOND_NUMBER_OF_1C_VERSION=`echo $version_of_1c_platform_with_underscores | cut -d "_" -f 2`
THIRD_NUMBER_OF_1C_VERSION=`echo $version_of_1c_platform_with_underscores | cut -d "_" -f 3`
FORTH_NUMBER_OF_1C_VERSION=`echo $version_of_1c_platform_with_underscores | cut -d "_" -f 4`
PACKAGE_SUBNAME="$FIRST_NUMBER_OF_1C_VERSION.$SECOND_NUMBER_OF_1C_VERSION.$THIRD_NUMBER_OF_1C_VERSION"
PACKAGE_SUBNAME+="-"
PACKAGE_SUBNAME+=$FORTH_NUMBER_OF_1C_VERSION
PACKAGE_SUBNAME+="_amd64"
echo "PACKAGE_SUBNAME is $PACKAGE_SUBNAME"
wget http://ftp.de.debian.org/debian/pool/contrib/m/msttcorefonts/ttf-mscorefonts-installer_3.7_all.deb
sudo dpkg -i ttf-mscorefonts-installer_3.7_all.deb
sudo apt-get --fix-broken -y install
sudo apt-get install -y imagemagick
sudo apt-get install -y unixodbc
# Installing libwebkitgtk-3.0-0 - old package
sudo sh -c 'echo "deb http://ru.archive.ubuntu.com/ubuntu/ cosmic main universe" > /etc/apt/sources.list.d/old1c_libs.list'
sudo apt-get update
sudo apt-get install -y libwebkitgtk-3.0-0
sudo apt-get --fix-broken -y install
mkdir distrs1c
tar -C ./distrs1c/ -xzf deb64_$TAR_SUBNAME.tar.gz
tar -C ./distrs1c/ -xzf client_$TAR_SUBNAME.deb64.tar.gz
cd distrs1c/
sudo dpkg -i 1c-enterprise83-common_$PACKAGE_SUBNAME.deb
sudo dpkg -i 1c-enterprise83-common-nls_$PACKAGE_SUBNAME.deb
sudo dpkg -i 1c-enterprise83-server_$PACKAGE_SUBNAME.deb
sudo dpkg -i 1c-enterprise83-server-nls_$PACKAGE_SUBNAME.deb
sudo dpkg -i 1c-enterprise83-ws_$PACKAGE_SUBNAME.deb
sudo dpkg -i 1c-enterprise83-ws-nls_$PACKAGE_SUBNAME.deb
sudo dpkg -i 1c-enterprise83-client_$PACKAGE_SUBNAME.deb
sudo dpkg -i 1c-enterprise83-client-nls_$PACKAGE_SUBNAME.deb
sudo mkdir -p /opt/1C/v8.3/x86_64/conf
echo "DisableUnsafeActionProtection=.*" | sudo tee --append /opt/1C/v8.3/x86_64/conf/conf.cfg
# Enabling debug mode for server 1C
sudo sed -i "s/.*SRV1CV8_DEBUG=.*/SRV1CV8_DEBUG=1/" /etc/init.d/srv1cv83
# RAS
sudo sed -i "s/echo \${mypid} > \"\$SRV1CV8_PIDFILE\"/echo \${mypid} > \"\$SRV1CV8_PIDFILE\"\n\n \$G_BINDIR\/ras --daemon cluster/" /etc/init.d/srv1cv83
# Changing ownership only after creating all necessary files
sudo chown -R usr1cv8:grp1cv8 /opt/1C
Порядок установки пакетов самой платформы 1С в нем менять не следует, так как процесс установки чувствителен к нему.
Установка PostgreSQL
Установку PostgreSQL мы будем выполнять не самым простым способом, так как будем брать дистрибутивы с https://releases.1c.ru/project/AddCompPostgre (-s) и ставить их на последние версии Ubuntu 19.x, вместо официально поддерживаемой 16-ой версии.
Вы можете узнать о самых простых способах установки на сайте https://1c.postgres.ru и получить там скрипт для подходящей комбинации версии PostgreSQL и версии Linux . На этом сайте скрипты высылаются на e-mail после запроса и, наверное, это было сделано авторами не просто так ;)) Поэтому не будем копировать их скрипты сюда. При желании Вы можете сделать это в своём репозитории самостоятельно - это займёт всего пять минут.
Установку будем выполнять из deb-пакетов. Нам потребуются пакеты для версий 10.10-4.1C и 11.5-7.1C. Содержимое каталога установки уже рассматривалось выше. Сейчас мы берем каталог с дистрибутивами нужной версии и рекурсивно копируем его в подкаталог distrs/pg в виртуальную машину, в домашний каталог пользователя, под которым выполняем установку. Для этого опять же используем wget , но с полезными для скачивания каталога опциями:
- -r - рекурсивное скачивание директории
- -np - опция гарантирует, что будут скачаны файлы только внутри указанной иерархии, в нашем случае в этой опции нет необходимости, но ее указание является обычным при рекурсивной загрузки директории.
- -P - позволяет указать в какой каталог производить скачивание, если такой каталог не существует, то он будет создан.
- -nH - отключает создание подкаталога с именем сайта
- --cut-dirs количество - отключает создание указанного количества каталогов, идущих после имени сайта.
Таким образом мы поместим файлы в каталог ~/distrs/pg не создавая в нем никаких подкаталогов. После чего запустим из него скрипт установки:
{
"type": "shell",
"inline": [
"echo ====== COPYING POSTGRESQL INSTALLATION PACKAGES AND SCRIPT ==============",
"wget -r -np -nH --cut-dirs 2 -P /home/{{user `ssh_username`}}/distrs/pg \",
" http://$PACKER_HTTP_ADDR/postgresql_for_1c/{{user `version_of_postgresql_with_underscores`}}/"
]
},
{
"type": "shell",
"inline": [
"echo ==================== INSTALLING POSTGRESQL ==============",
"cd /home/{{user `ssh_username`}}/distrs/pg",
"bash ./postgresql_installation_script.sh {{user `ssh_password`}}"
]
},
В начале скрипта выполняем обычные для установки PostgreSQL действия - установим языковые настройки.
Для того, чтобы выводить логи работы сервера в английском языке в операционной системе должна присутствовать английская локаль. Русская в ней присутствует изначально - мы выбирали русский язык на этапе установки ОС. Но для пущей надёжности добавим команду установки русской локали, помимо английской:
sudo locale-gen ru_RU.utf8
sudo locale-gen en_US.utf8
Для вывода логов в процессе установки PostgreSQL на английском языке нужно установить переменную окружения:
export LANG=en_US.UTF-8
В этом случае при возникновении ошибок будет гораздо больше шансов найти описание ошибки и способ её устранения в поисковиках. Вывод логов на русском языке делает почти невозможным поиск причин редких ошибок в интернете. Никогда не настраивайте получение логов PostgreSQL на русском.
LC_COLLATE и LC_CTYPE определяют настройки порядка сортировки в индексах баз (аналог свойства Collation в MS SQL), создаваемых при установке PostgreSQL, а значит и в базах template0 и template1 (это аналог базы model в MS SQL). Чтобы не переопределять их при создании каждой базы необходимо задать их как ru_RU.UTF8 на этапе установки.
export LC_CTYPE=ru_RU.UTF8
export LC_COLLATE=ru_RU.UTF8
tar -xjf postgresql_10.10_4.1C_amd64_addon_deb.tar.bz2 -C ./
tar -xjf postgresql_10.10_4.1C_amd64_deb.tar.bz2 -C ./
Необходимые пакеты libicu55_55.1-7ubuntu0.4_amd64.deb и libssl1.0.0_1.0.1t-1+deb8u11_amd64.deb были скачаны ранее с хостовой машины через wget как и архивы с Postgres. При этом последний из них зависит от пакета multiarch-support, который не был добавлен мейнтейнерами Ubuntu в репозитории релиза 19.10. По крайней мере такой была ситуация на момент написания этого установочного скрипта. Поэтому скачаем пакет multiarch-support_2.29-0ubuntu2_amd64.deb по прямой ссылке и установим его как deb-пакет.
sudo wget -O - http://repo.postgrespro.ru/pgpro-10/keys/GPG-KEY-POSTGRESPRO | sudo apt-key add -
sudo -E sh -c 'echo "deb http://repo.postgrespro.ru/pgpro-10/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/postgrespro.list'
sudo apt-get update -y
sudo apt-get install -y postgresql-client-common
sudo apt-get install -y postgresql-common
sudo dpkg -i libicu55_55.1-7ubuntu0.4_amd64.deb
wget http://cz.archive.ubuntu.com/ubuntu/pool/main/g/glibc/multiarch-support_2.29-0ubuntu2_amd64.deb
sudo dpkg -i multiarch-support_2.29-0ubuntu2_amd64.deb
sudo dpkg -i libssl1.0.0_1.0.1t-1+deb8u11_amd64.deb
Далее нам необходимо установить распакованные пакеты. Обычно для этого используются команды следующего вида
dpkg -i postgresql-client-10_10.10-4.1C_amd64.deb
dpkg -i postgresql-10_10.10-4.1C_amd64.deb
dpkg -i postgresql-10.10-4.1C_amd64_addon_deb/*.deb
И эти команды хорошо сработают с PostgreSQL 11. Но версии 10.x уже считаются устаревшими и при такой установке возникают определенные сложности. Появляется окно, которое требует от пользователя интерактивных действий и подтверждения готовности установить устаревший пакет:
Это рушит процесс автоматической установки. Более того, при установке через Packer этого окна мы даже не увидим. Вместо этого просто зависнет весь процесс установки. Также следует учитывать, что уже вышла версия PostgreSQL 12 и скоро подобное окно может начать появляться и при установке PostgreSQL 11.
Чтобы избежать подобного прерывания установки нужно немного модифицировать команды, явно указав системе, что процесс идет в неинтерактивном режиме установив переменную DEBIAN_FRONTEND=noninteractive. Также сразу после установки основные пакеты необходимо "закрепить" командой apt-mark hold. Иначе последующее устранение проблемы с зависимостями через apt-get --fix-broken -y install или последующая установка pgAdmin 4 приведут к тому, что пакеты, специфичные для 1С, будут заменены "правильными" с точки зрения менеджера apt-get пакетами из официальных репозиториев Ubuntu (с другими дистрибутивами Linux поведение будет похожим):
sudo dpkg -i postgresql-10.10-4.1C_amd64_deb/libpq5_10.10-4.1C_amd64.deb
sudo DEBIAN_FRONTEND=noninteractive dpkg -i postgresql-10.10-4.1C_amd64_deb/postgresql-client-10_10.10-4.1C_amd64.deb
sudo DEBIAN_FRONTEND=noninteractive dpkg -i postgresql-10.10-4.1C_amd64_deb/postgresql-10_10.10-4.1C_amd64.deb
sudo DEBIAN_FRONTEND=noninteractive dpkg -i postgresql-10.10-4.1C_amd64_addon_deb/*.deb
sudo apt-mark hold postgresql-10
sudo apt-mark hold postgresql-client-10
sudo apt-mark hold postgresql-client-common
sudo apt-mark hold postgresql-common
sudo apt-mark hold postgresql-doc-10
sudo apt-mark hold postgresql-server-dev-10
sudo apt-mark hold libpq5
sudo apt-mark hold libicu55
sudo apt-mark hold libssl1.0.0
sudo DEBIAN_FRONTEND=noninteractive apt-get --fix-broken -y install
После установки кластера выполним его конфигурирование, как обычно с помощью утилиты sed . Нам необходимо установить пароль, переданный в скрипт как параметр, пользователю postgres. Для этого сначала разрешим локальные подключения пользователю с именем postgres вообще без ввода пароля. Затем подключимся под ним и изменим пароль. После чего снова запретим локальные подключения пользователю postgres без ввода пароля. Последнее действие (восстановление запрета) на CI выполнять необязательно, но если вы будете использовать этот скрипт для других целей, то конечно такое ограничение на доступ не помешает.
sudo sed -i "s/.*local.*all.*postgres.*/local all postgres trust/" /etc/postgresql/10/main/pg_hba.conf
sudo systemctl restart postgresql.service
psql -U postgres -c "ALTER USER postgres PASSWORD '$postgres_password'"
sudo sed -i "s/.*local.*all.*postgres.*/local all postgres md5/" /etc/postgresql/10/main/pg_hba.conf
Далее заменим конфигурационный файл postgresql.conf файлом из нашего репозитория, который имеет настройки, специфичные для 1С. При этом на всякий случай сохраним и исходный файл:
sudo cp -rf /etc/postgresql/10/main/postgresql.conf /etc/postgresql/10/main/postgresql.conf.bak
sudo cp -rf ./postgresql.conf /etc/postgresql/10/main/postgresql.conf
sudo systemctl restart postgresql.service
При задании параметров postgresql.conf можно пренебречь настройками, повышающими надежность базы при её сборях ценой скорости выполнения операций. Дело в том, что сохранность баз на CI сервере не нужна. В прошлой публикации упоминалась даже возможность переключить все таблицы базы в режим UNLOGGED. Наши процессы будут настроены таким образом, что в случае падения сервера (узла CI-контура) процесс сборки прекратится. А новый процесс начнется с пересоздания базы, а не восстановления уже существующей. Поэтому например нормальными являются настройки отключающие fsync и synchronous_commit. Хотя не нужно надеяться, что это сильно ускорит работу - основные затраты времени приходятся вовсе не на запись WAL.
В то же время, с учетом почти монопольного доступа к базе можно задать такие параметры как shared_buffers , work_mem довольно большими (относительно всего объема оперативной памяти в 3-4 ГБ).
fsync = off
full_page_writes = off
synchronous_commit = off
shared_buffers = 2GB
bgwriter_delay = 100ms
work_mem = 128MB
Эффективность таких настроек будет во многом зависеть от того, хватает ли физической оперативной памяти для виртуальных машин на хостовой машине. При нехватке VirtualBox всё равно будет работать с диском на хостовой машине, имитируя оперативную память для гостевых машин, и не будет большой разницы между работой PostgreSQL с временными файлами при небольшом числе work_mem или работой гипервизора с жестким диском на хостовой машине.
Конечно для большей универсальности нашего образа изменение файла postgresql.conf следовало бы вынести на этап развертывания узла через Vagrant. Но с другой стороны, изменить эти настройки в момент развертывания виртуальной машины достаточно легко, а закладываемые сейчас в образ виртуальной машины настройки можно считать "конфигурацией по умолчанию", наиболее пригодной для наших целей - развертывания узлов для CI.
И последнее действие - это необязательный для нас pgAdmin4. Его наличие в сборке для CI практически бесполезно, но если созданные сейчас механизмы вы планируете использовать и для других целей, то наличие pgAdmin4 пригодится:
sudo wget -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg_for_pg_admin_4.list'
sudo apt-get update -y
sudo apt-get install -y pgadmin4
sudo rm /etc/apt/sources.list.d/pgdg_for_pg_admin_4.list
sudo apt-get update -y
Получившейся в итоге текст можно увидеть по следующим ссылкам:
- для Postgres 11: https://github.com/VladimirLitvinenko84/ci-infrastructure-for-1c/blob/master/http_distr/postgresql_for_1c/11_5_7/postgresql_installation_script.sh
- для Postgres 10: https://github.com/VladimirLitvinenko84/ci-infrastructure-for-1c/blob/master/http_distr/postgresql_for_1c/10_10_4/postgresql_installation_script.sh
Установка Apache
Пожалуй этот простой блок можно оставить без развернутых комментариев. Единственной особенностью здесь является автоматическое включение SSL без какой-либо настройки сертификатов - будут использоваться сертификаты из поставки Apache, включенные в поставку для демонстрационных целей.
Задействовать собственные сертификаты можно добавив ещё несколько команд, к использованным здесь. Сделать это можно воспользовавшись инструкцией https://help.ubuntu.ru/wiki/apache_и_https
Устанавливаем Apache мы для двух целей:
1) Демонстрации простейшего теста web- или http-сервиса 1С,
2) А также для демонстрации возможности автоматической публикации базы 1С и всех веб-сервисов, входящих в состав её конфигурации и расширений конфигурации.
После публикации на веб-сервере работа с базой будет возможна как по http через 80-й порт, так и по https через 443 порт.
{
"type": "shell",
"inline": [
"echo ======= INSTALLING APACHE WITH SSL ON PORT 433 ==============",
"sudo apt install -y apache2",
"sudo sed -i 's/.*ssl_module.*//' /etc/apache2/apache2.conf",
"echo ''| sudo tee -a /etc/apache2/apache2.conf",
"echo 'LoadModule ssl_module \"/usr/lib/apache2/modules/mod_ssl.so\"' | sudo tee -a /etc/apache2/apache2.conf",
"sudo a2enmod ssl",
"sudo a2ensite default-ssl",
"sudo systemctl restart apache2.service"
]
},
Упаковка виртуальной машины в образ для Vagrant
В последнем разделе post-processors мы говорим Packer , что ему необходимо вызвать Vagrant для того, чтобы импортировать собранный им образ виртуальной машины в бокс:
"post-processors": [
{
"type": "vagrant",
"keep_input_artifact": true,
"output": "{{user `vm_name`}}_{{.Provider}}.box"
}
При этом боксу присваивается имя {{user `vm_name`}}_{{.Provider}}, включающее в себя версии основного программного обеспечения, включенного в образ виртуальной машины:
"vm_name": "ci_node_ubuntu_{{env `version_of_vm_os_with_underscore`}}_1c_{{env `version_of_1c_platform_with_underscores`}}_pg_{{env `version_of_postgresql_with_underscores`}}",
{{.Provider}} - это переменная, определяемая самим Packer и хранящая название сборщика. В нашем случае вместо нее подставится текст "virtualbox".
Управляющие командные файлы
Разделим командные файлы, осуществляющие запуск процесса сборки, на два типа:
1) Универсальные и редко меняющиеся. Их текст должен меняться разве что в процессе отладки, но после завершения отладки причин для их изменения быть не должно.
2) Файлы задающие версии программного обеспечения, включаемого в образ виртуальной машины. Таких файлов может быть несколько и например появление необходимости собрать образ с новой версией платформы 1С или PostgreSQL приведет к появлению еще одного такого файла.
Для сборки с версиями Ubuntu 19.10 , платформой 1С версии 8.3.16.1063 и PostgreSQL версии 11.5.7 создадим файл
build_ubuntu_19_04_1c_8_3_15_1656_pg_10_10_4.bat с таким содержимым:
SET version_of_1c_platform_with_underscores=8_3_16_1063
SET version_of_vm_os_with_dot=19.10
SET version_of_vm_os_with_underscore=19_10
SET version_of_postgresql_with_underscores=11_5_7
build.bat | tee log.txt
Для сборки версиями Ubuntu 19.04 , платформой 1С версии 8.3.15.1656 и PostgreSQL версии 10.10.4 создадим следующий файл build_ubuntu_19_10_1c_8_3_16_1063_pg_11_5_7.bat:
SET version_of_1c_platform_with_underscores=8_3_15_1656
SET version_of_vm_os_with_dot=19.04
SET version_of_vm_os_with_underscore=19_04
SET version_of_postgresql_with_underscores=10_10_4
build.bat | tee log.txt
Оба файла запускают общий управляющий файл build.bat. При этом использование утилиты tee из пакета git позволит видеть лог одновременно на экране и выводить его в файл. Вывод лога в файл позволит быстрее расследовать проблемы и устранять их.
Общий командный файл имеет следующее содержание:
SET VAGRANT_HOME=C:/HashiCorp/vagrant_home
echo version_of_1c_platform_with_underscores is %version_of_1c_platform_with_underscores%
echo version_of_vm_os_with_dot is %version_of_vm_os_with_dot%
echo version_of_vm_os_with_underscore is %version_of_vm_os_with_underscore%
SET shutdown_command=sudo systemctl poweroff
SET disk_size_mb=32000
SET iso_checksum_type=none
SET virtual_machine_hostname=vagrant-ci
SET ssh_username=vagrant
SET ssh_password=vagrant
SET iso_url=./iso/ubuntu-%version_of_vm_os_with_dot%-live-server-amd64.iso
grep -v '#' boot_command_%version_of_vm_os_with_underscore%.cfg | sed 's/{{user `ssh_username`}}/%ssh_username%/' | sed 's/{{user `ssh_password`}}/%ssh_password%/' | sed 's/{{user `hostname`}}/%virtual_machine_hostname%/' | tr -d '\n' | tr -d '\r' > boot_command_temp.txt
set /P boot_command=< boot_command_temp.txt
rm -f boot_command_temp.txt
echo Boot command is
echo "%boot_command%"
time /T
rmdir /S /Q output-virtualbox-iso
packer build -force -on-error=ask packer_build.json
if %errorlevel% neq 0 exit /b %errorlevel%
time /T
REM Waiting for box file to be released
ping 127.0.0.1 -n 10 > nul
SET box_name=ci_node_ubuntu_%version_of_vm_os_with_underscore%_1c_%version_of_1c_platform_with_underscores%_pg_%version_of_postgresql_with_underscores%
vagrant box remove %box_name% --force
vagrant box add %box_name% %box_name%_virtualbox.box
time /T
В нем мы делаем следующее
1) Через переменную окружения VAGRANT_HOME явно задаем домашний каталог Vagrant, в который в итоге будет помещаться бокс-образ машины. Сделать это имеет смысл, чтобы избежать ситуации, когда в разных окружениях и на разных машинах итоговые сборки образов помещаются в разные каталоги.
2) Выводим отладочные сообщения, которые позволят убедиться, что сборка стартовала с правильными параметрами, определяющими версии устанавливаемого программного обеспечения.
3) Формируем переменную окружения boot_command для нужной версии операционной системы. Чтобы убедиться, что файл прочитан корректно выводим значение этой переменной на экран.
4) Запускаем сборку виртуальной машины.
5) Ждем 10 секунд пока завершатся процессы сборки и освободят нужные файлы, которые затем будет использовать Vagrant. Если попытаться использовать эти файлы сразу, то можно наткнуться на ошибку монопольного доступа к файлам.
6) Формируем имя образа, которое затем будет использоваться при развертывании виртуальных машин из него.
7) Удаляем образ с тем же именем, если он уже есть в системе. Это действие необходимо чтобы избежать конфликтов имен, если ранее мы уже собирали такой образ и теперь хотим его заменить.
8) Добавляем образ в домашний каталог Vagrant, путь к которому задавали в самом начале командного файла.
Таким образом для сборки нужного нам образа нужно запустить командный файл build_ubuntu_19_10_1c_8_3_16_1063_pg_11_5_7.bat или build_ubuntu_19_04_1c_8_3_15_1656_pg_10_10_4.bat:
Если мы хотим заменить дистрибутивы 1С или PostgreSQL достаточно скачать нужные релизы, затем по образу и подобию создать еще один небольшой командный файл, в котором точно также указать нужные версии ПО, а затем вызвать выполнение файла build.bat.
Если мы хотим использовать PostgreSQL версии 11 версии, то за образец лучше взять файлы, которые сейчас рассчитаны на версию 11.5.7. Аналогично для 10-ой версии. Замена версии ОС на отличную от Ubuntu 19.x конечно потребует больших модификаций.
Если сборка завершилась аварийно
Если один из исполняемых на стороне гостевой машины shell-скриптов при сборке вызвал ошибку, или во время сборки произошла любая другая ошибка, то Packer прервёт сборку, предложив несколько вариантов дальнейших действий.
Не верьте в то, что здесь у Вас есть выбор ;)) Предложение попробовать повторить шаг обманчиво. На самом деле Packer повторит не последние команды, вызвавшие сбой, а начнёт всю сборку заново, не очистив мусор от предыдущей попытки. Поэтому вариант "retry step" не следует выбирать. Единственный подходящий вариант, который минимизирует вероятность ошибки при следующей попытке сборки - это "Clean up and exit". В этом случае Packer постарается удалить созданную им временную виртуальную машину и временные файлы:
Процесс сборки чувствителен ко временным файлам, созданным Packer во время предыдущих сборок. Эти временные файлы представляют собой кэш, который по идее должен ускорять сборку. В частности, если путь к ISO файлу задаётся не как путь к локальному файлу, а как http-адрес файла в интернете, то кэш позволяет не скачивать его при каждой сборке, а загрузить его только один раз и при следующих сборках брать скачанный ISO уже с локального диска.
Но если ISO файл мы скачали заранее, то кэширование будет только повышать риск ошибок сборки, и почти не приведёт к ускорению процесса. Поэтому кэши и временные файлы, созданные Packer следует очищать.
В репозитории присутствует командный файл, осуществляющий очистку результатов прошлой сборки - delete_build_artifacts.bat. В этом файле выполняются всего три команды по очистке каталогов с кэшами Packer
- Каталога output-virtualbox-iso
- Каталога packer_cache
- Файлов *.box, являющихся результатами сборки в текущем каталоге.
Данный командный файл автоматически вызывается в начале каждой сборки из управляющего командного файла build.bat . Поэтому запускать его вручную перед сборкой нет необходимости. Выполнить его вручную можно уже после сборки, чтобы освободить место на диске от промежуточных файлов, созданных Packer.
Автоматический или ручной запуск файла delete_build_artifacts.bat решает большинство проблем, которые могут возникнуть при повторной сборке образа. Но всё же не все.
Если сборка завершилась с ошибкой, то даже несмотря на выбор "Clean up and exit", как завершающего действия иногда Packer не сможет очистить все выделенные гипервизором ресурсы. Тогда приходится вручную удалять файлы оставшиеся от предыдущей неудачной сборки. Сообщения о подобных ошибка появляются в начале сборки, что на самом деле хорошо. Это позволяет сразу обнаружить и устранить возникшие ошибки.
На практике я встречал всего три подобные ошибки.
Первая - это не до конца удаленные файлы виртуальной машины:
В этом случае достаточно удалить весь каталог, содержащий файлы, на наличие которых жалуется Packer:
Вторая ошибка - это не удаленная временная виртуальная машина. В этом случае её можно удалить вручную из графического интерфейса гипервизора:
Третья и самая редкая ошибка - это "зависший" диск от удалённой виртуальной машины. Сейчас не могу привести точное сообщение об ошибке и скриншот, так как давно не сталкивался с ней. Но текст будет похож на следующий:
==> virtualbox-iso: Progress state: E_INVALIDARG
==> virtualbox-iso: VBoxManage.exe: error: Failed to create medium
==> virtualbox-iso: VBoxManage.exe: error: Cannot register the hard disk 'C:\packer\output-virtualbox-iso\1_hdd2.vdi' {39d5abf0-91b7-42c9-8b71-cc5dbbbaefd9} because a hard disk 'C:\packer\output-virtualbox-iso\1_hdd2.vdi' with UUID {d5c717f2-c86b-460b-a8b4-6b8d708c1233} already exists
==> virtualbox-iso: VBoxManage.exe: error: Details: code E_INVALIDARG (0x80070057), component VirtualBoxWrap, interface IVirtualBox
В этом случае нужно зайти в менеджер виртуальных носителей и удалить ошибочный жесткий диск. Он при этом может быть выделен в списке предупреждающим знаком:
Ну и конечно нужно помнить о необходимости стабильного канала связи (выхода в интернет). Если возникнет ошибка загрузки пакетов из репозиториев Linux, то сборку нужно будет начать заново. Вот например ошибка, возникшая из за нестабильной связи уже при установке графического окружения (пакета ubuntu-desktop):
Проверка результата
После завершения сборки можно проверить её результат. Для этого нужно в любом пустом каталоге выполнить несколько команд.
Создать файл Vagrantfile в этом каталоге выполнив команду vagrant init или просто создав такой файл вручную. Затем надо задать содержимое этого файла следующим образом:
Vagrant.configure("2") do |config|
config.vm.box = "ci_node_ubuntu_19_10_1c_8_3_16_1063_pg_11_5_7"
config.vm.communicator = "ssh"
config.ssh.username = 'vagrant'
config.ssh.password = 'vagrant'
config.vm.provider :virtualbox do |v, override|
v.gui = true
end
end
Здесь мы задаём имя созданного нами образа-бокса с нужными версиями программного обеспечения, имя пользователя и пароль, которые нужно использовать для взаимодействия с машиной по ssh, и говорим, что при запуске машины нам нужно показать графический интерфейс для взаимодействия с ней :
При сборке боксы мы размещаем в каталоге, путь к которому явно задавали в командном файле в переменной VAGRANT_HOME. Поэтому чтобы Vagrant знал где искать файлы в этот раз также нужно задать значение этой переменной окружения. После чего можно запустить виртуальную машину командой vagrant up.
SET VAGRANT_HOME=C:\HashiCorp\vagrant_home
vagrant up
Первый запуск через команду vagrant up всегда выполняется дольше, чем последующие, так как при этом не только запускается, но и создается новая виртуальная машина путем импорта из бокса:
После запуска выполняется автологон. Если лицензии раздает непосредственно хостовая машина, то запуск клиента 1С можно выполнить уже сейчас (хотя с NAT здесь могут возникнуть проблемы). Если же нет, то придется сначала включить нашу виртуальную машину через "мост" в общую локальную сеть, где один из компьютеров раздаёт лицензии, и загрузить в виртуальную машину файл nethasp.ini с указанием IP-адреса раздающей машины. Включение в общую локальную сеть будем делать в следующий раз, разбирая работу с Vagrant.
В то же время создать базу данных через RAS и RAC всегда возможно сразу после запуска операционки. После создания базы через RAS можно поверить доступ к этой базе через PostgreSQL, точнее утилиту psql:
CLUSTER_ID=$(/opt/1C/v8.3/x86_64/rac localhost cluster list | head -1 | tr -d ' ' | cut -d ':' -f 2)
/opt/1C/v8.3/x86_64/rac localhost infobase --cluster $CLUSTER_ID create --create-database --name=test_db1 --dbms=PostgreSQL --db-server=localhost --db-name=test_db1 --locale=ru --db-user=postgres --db-pwd=vagrant
export PGPASSWORD=vagrant
psql -U postgres -d test_db1 -c "\d " | head -n 15
Можно также запросить данные от Apache через curl и убедиться, что возвращаются данные html-страницы. Но при настройке Apache мы не стали создавать SSL-сертификаты и используем устаревшие сертификаты из поставки Apache. Поэтому чтобы утилита curl не вызвала ошибок надо будет указать опцию --insecure. Тем не менее для последующей работы с базами 1С такая конфигурация Apache нам подходит и при отправки запроса через объекты платформы 1С HTTPЗапрос и HTTPСоединение ошибок возникать не будет.
Выполним следующие команды и убедимся в корректности ответов от Apache :
curl http://localhost:80 | head -n 15
# Команда без параметра --insecure должна выдать ошибку
curl https://localhost:443 | head -n 15
curl --insecure https://localhost:443 | head -n 15
Итоги
Итак, на данном этапе у нас есть механизм, позволяющий собирать образ виртуальной машины, которой является основой для дальнейшего построения инфраструктуры CI. При сборке образа мы можем заменять:
- Версию платформы 1С. Для этого достаточно загрузить дистрибутивы платформы и разместить их в каталоге дистрибутивов на хостовой машине, а также в командном файле сборки изменить значение переменной version_of_1c_platform_with_underscores
- Версию PostgreSQL. Для этого нужно загрузить дистрибутивы сборки для 1С, адаптировать под новую версию файл postgresql_installation_script (готовые примеры которого уже есть для 10.10.4 и 11.5.7) и в командном файле установки заменить значение переменной version_of_postgresql_with_underscores
- Версию операционной системы Ubuntu Server. Для этого нужно загрузить ISO-файл нужной версии, задать значение переменной version_of_vm_os_with_dot и создать файл с boot_command по образцу существующих.
- Администратора системы и его пароль. Для этого достаточно задать значения переменных ssh_username и ssh_password.
Скачать дистрибутивы платформы 1С и сборки PostgreSQL для 1С нужно самостоятельно. Для загрузки дистрибутива операционной системы достаточно запустить скрипт.
На этом мы заканчиваем разработку механизма сборки образов виртуальных машин, выполняем очередные коммиты
и переходим к следующему этапу - развертыванию набора узлов для CI-контура с помощью Vagrant.