Хабрахабр

GitLab для Continuous Delivery проекта на технологиях InterSystems: Контейнеры

Эта статья — продолжение статьи про организацию процессов Continuous Integration / Continuous Delivery, автоматизирующих сборку, тестирование и доставку приложений применимо к решениям на платформе InterSystems.

Рассмотрим такие темы как:

  • Контейнеры 101
  • Контейнеры на разных этапах цикла разработки ПО
  • Continuous Delivery с контейнерами

Итак, начнём. Про контейнеры и контейнеризацию написано много статей и книг, поэтому тут я сделаю небольшое вступление, которое, впрочем, не претендует на какую-либо окончательность.

Наглядно это выглядит так: Контейнеры, технически, это метод виртуализации, при котором ядро операционной системы поддерживает несколько изолированных экземпляров пространства пользователя (контейнеров), вместо одного.

Docker vs VM

При этом важно отметить что контейнеры — это не виртуальные машины, вот хорошая статья об их различиях.

Преимущества контейнеров

Существует ряд преимуществ использования контейнеров:

  • Портативность
  • Эффективность
  • Изоляция
  • Лёгкость
  • Неизменность (Immutability)

Портативность

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

на серверах Windows, Linux и MacOS. Также портативность состоит в том, что после того, как Docker образ собран и он работает правильно, он будет работать где угодно, если там работает Docker т.е.

Эффективность

Как правило нет, интересен только процесс вашего приложения. При работе с приложениями виртуальных машин действительно ли нужны процессы ОС, системные программы и т.п.? Поскольку контейнеры не требуют отдельной операционной системы, они используют меньше ресурсов. Контейнеры обеспечивают именно это: в контейнере запускаются только те процессы, которые явно нужны, и ничего более. Виртуальная машина часто занимает несколько гигабайт, контейнер же может быть размером всего в несколько мегабайт, что позволяет запускать гораздо больше контейнеров, чем виртуальных машин на одном сервере.

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

Изоляция

Любое взаимодействие между контейнерами должно быть явно объявлено. Контейнеры изолируют приложение от всех остальных процессов, и, хотя несколько контейнеров могут работать на одном сервере, они могут быть полностью независимы друг от друга. Безопасность также повышается благодаря такой изоляции. Если один контейнер выходит из строя, он не влияет на другие контейнеры и может быть быстро перезапущен. Например, использование уязвимости веб-сервера на хосте может дать злоумышленнику доступ ко всему серверу, но в случае контейнера злоумышленник получит доступ только к контейнеру веб-сервера.

Лёгкость

Вы можете начать разрабатывать быстрее и не тратить время на настройку окружения. Поскольку для контейнеров не требуется отдельная ОС, их можно запустить, остановить или перезагрузить в считанные секунды, что ускорит все связанные процессы, в том числе и процессы Continuous Integration.

Неизменность (Immutability)

Неизменность уменьшает несогласованность и позволяет легко и быстро реплицировать и перемещаться между различными состояниями вашего приложения. Неизменяемая инфраструктура состоит из неизменяемых компонентов, которые заменяются для каждого развертывания, а не обновляются. Подробнее о неизменности.

Новые возможности

Все эти преимущества позволяют управлять инфраструктурой и приложениями по-новому.

Оркестрация

Одним из вариантов решения данной проблемы является Инфраструктура как код (IoC) — управление инфраструктурой с помощью описательной модели, используя систему контроля версий. Виртуальные машины и сервера с течением времени часто обретают "индивидуальность", что приводит ко множеству как правило неприятных сюрпризов в будущем.

Это достигается путем автоматической настройки существующей среды или путем пересоздания среды с нуля. При использовании IoC команда развертывания окружения всегда приводит целевую среду в одну и ту же конфигурацию, независимо от исходного состояния среды.

Впоследствии целевые среды модифицируются до нового состояния. С помощью IoC разработчики вносят изменения в описание среды. Если в среду необходимо внести изменения, редактируется её описание.

Выключение контейнера и запуск нового занимает несколько секунд, а выделение новой виртуальной машины занимает несколько минут. Все это гораздо проще делать с контейнерами.

Масштабирование

Возможно запускать столько контейнеров, сколько требуется в настоящее время требуется, и масштабировать приложение соответствующе. Инструменты оркестрации также могут обеспечивать горизонтальное масштабирование на основе текущей нагрузки. Всё это также снижает затраты на работу приложения.

Рассмотрим преимущества контейнеров на различных этапах жизненного цикла ПО.

Жизненный цикл ПО

Разработка

После установки Docker, достаточно выполнить две команды: docker pull для загрузки образа и docker run для его запуска. Самое главное преимущество — это простота начала разработки. Все зависимости уже разрешены на этапе сборки приложения.

Отладка

Достаточно сделать docker pull интересующего контейнера и запустить его. Все окружения консистентны и существуют их определения, кроме того легко развернуть необходимое окружение.

Тестирование / QA

Все изменения инфраструктуры «задокументированы». В случае возникновения ошибки, проблемное окружения и условия воспроизведения ошибки можно передать с контейнером. Уменьшается число переменных – версий библиотек, фреймворков, ОС… Возможен запуск нескольких контейнеров для параллелизации тестов.

Доставка

Доставка приложения с помощью контейнеров может быть более безопасна за счёт дополнительной изоляции. Использование контейнеров позволяет проводить сборку один раз, кроме того для использования контейнеров необходим высокий уровень автоматизации процессов сборки и развёртывания приложения.

Вот общий вид нашего решения по автоматизации сборки и доставки: Перейдём от теории к практике.

CD

Можно выделить три основных этапа:

  • Сборка
  • Доставка
  • Запуск

Сборка

С контейнерами каждая сборка является полной. В предыдущей статье сборка была инкрементальной — мы считали разницу между текущей средой и новой кодовой базой и изменяли нашу среду так, чтобы она соответствовала новой кодовой базе. Результатом сборки является образ Docker Image, который можно запускать где угодно.

Доставка

Там он может заменить предыдущий образ с тем же именем (тегом). После того, как наш образ собран и протестирован, он загружается в Docker Registry — специализированное приложение для размещения Docker Image. Например, из-за нового коммита в ветку master мы собрали новый образ (MyProject/MyApp:master), и если тесты пройдены, мы можем обновить образ в Docker Registry и все, кто скачивает MyProject/MyApp:master получат новую версию.

Запуск

Система CD, такая как GitLab, может этим управлять как напрямую, так и с помощью специализированного оркестратора, но процесс, в общем, одинаков — некоторые образы запускаются, периодически проверяются на работоспособность и обновляются, если новая версия становится доступной. Наконец, образ необходимо запустить.

Посмотрите вебинар, объясняющий эти этапы.

Альтернативно, с точки зрения коммита:

В нашей конфигурации непрерывной доставки мы:

  • Коммитим код в репозиторий GitLab
  • Собераем образ
  • Тестируем его
  • Публикуем новый образ в нашем Docker Registry
  • Обновим старый контейнером на новую версию из Docker Registry

Для этого нам понадобятся:

  • Docker
  • Docker Registry
  • Зарегистрированный домен (необязательно, но желательно)
  • GUI инструменты (по желанию)

Docker

Я бы посоветовал начать с одного сервера с распространенной версией Linux, такой как Ubuntu, RHEL или Suse. Прежде всего, нам нужно запустить Docker. д. Не рекомендую начинать с таких дистрибутивов как CoreOS, RancherOS и т. Не забудьте переключить драйвер хранилища на devicemapper. — они нацелены не на начинающих.

Если же говорить о широкомасштабных развертываниях, то с помощью инструментов оркестрации, таких как Kubernetes, Rancher или Swarm, можно автоматизировать большинство задач, но мы не будем обсуждать их (по крайней мере, в рамках этой статьи).

Docker Registry

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

  • Контролировать, где хранятся ваши образы
  • Владеть сервером распространения образов
  • Интегрировать хранение и распространение образов в процесс разработки

Вот документация по запуску и настройке Docker Registry.

Подключение Docker Registry и GitLab

Я использую Let's Encrypt для получения сертификатов, и я следовал этой инструкции, для получения сертификата. Чтобы подключить Docker Registry к GitLab, необходимо запустить Docker Registry с поддержкой HTTPS. Эти инструкции отличаются в зависимости от вашей установки GitLab и необходимой конфигурации. Убедившись, что Docker Registry доступен по HTTPS (вы можете проверить это в браузере), следуйте этим инструкциям по подключению Docker Registry к GitLab. В моем случае настройка заключалась в добавлении сертификата Docker Registry и ключа в /etc/gitlab/ssl, а этих строк в /etc/gitlab/gitlab.rb:

registry_external_url 'https://docker.domain.com'
gitlab_rails ['registry_api_url'] = "https://docker.domain.com"

После переконфигурации GitLab появилась новая вкладка Registry, на которой предоставлена информация о том, как правильно назвать созданные образы, чтобы они тут появились.

Домен

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

  • Несколько веток фич по адресу <featureName>.docker.domain.com
  • Тестовая версия на master.docker.domain.com
  • Опытная версия на preprod.docker.domain.com
  • Продуктовая версия на prod.docker.domain.com

Как вариант можно использовать различные порты. Для этого нам нужно доменное имя и wildcard DNS-запись, которая перенаправляет запросы к * .docker.domain.com на IP-адрес docker.domain.com.

Nginx

Для этого мы можем использовать Nginx в качестве обратного прокси. Поскольку у нас есть несколько окружений, нам необходимо автоматически перенаправлять запросы к поддоменам в правильный контейнер. Вот руководство.

GUI Инструменты

Есть много доступных, например: Чтобы начать работу с контейнерами, вы можете использовать либо командную строку, либо один из графических интерфейсов.

  • Rancher
  • MicroBadger
  • Portainer
  • Simple Docker UI
  • ...

Вот как выглядит Rancher: Они позволяют создавать контейнеры и управлять ими из GUI вместо CLI.

Rancher

GitLab runner

Подробно этот вопрос описан в предыдущей статье. Как и раньше, для выполнения скриптов на других серверах нам нужно установить GitLab runner.

Executor Docker используется, когда нужно что-то изнутри образа, например, при создании приложение для Android в java контейнере, и нужен только apk. Обратите внимание, что нужно использовать executor Shell, а не Docker. В нашем случае артефакт — контейнер целиком, и для этого нужен executor Shell.

Теперь, когда все необходимые компоненты настроены, можно приступать к созданию конфигурации непрерывной доставки.

Сборка

Во-первых, нам нужно собрать образ.

Наш код, как и всегда, хранится в репозитории, конфигурация CD в gitlab-ci.yml, но кроме того (для повышения безопасности) мы будем хранить несколько файлов, относящихся к образу, на сервере сборки.

GitLab.xml

Он был разработан в предыдущей статье и доступен на GitHub. Содержит код коллбэков для CD. Предпочтительней использовать подмодули git, чтобы включить этот проект или что-то подобное в ваш репозиторий. Это небольшая библиотека для загрузки кода, запуска различных коллбэков и тестового кода. Еще одна альтернатива — создать релиз на GitLab и загрузить его с помощью команды ADD уже при сборке. Подмодули лучше, потому что легче поддерживать их в актуальном состоянии.

iris.key

Он может быть загружен во время сборки контейнера, а не храниться на сервере. Лицензионный ключ. Вы можете получить пробный ключ на WRC или попробовать InterSystems IRIS Experience. Небезопасно хранить ключ в репозитории.

pwd.txt

Опять же, хранить пароль в репозитории довольно небезопасно. Файл, содержащий пароль по умолчанию.

load_ci.script

Скрипт, который:

  • Включает ОС аутентификацию в InterSystems IRIS
  • Загружает GitLab.xml
  • Инициализирует настройки GitLab коллбэков
  • Загружает код

set sc = ##Class(Security.System).Get("SYSTEM",.Properties)
write:('sc) $System.Status.GetErrorText(sc)
set AutheEnabled = Properties("AutheEnabled")
set AutheEnabled = $ZBOOLEAN(+AutheEnabled,16,7)
set Properties("AutheEnabled") = AutheEnabled
set sc = ##Class(Security.System).Modify("SYSTEM",.Properties)
write:('sc) $System.Status.GetErrorText(sc)
zn "USER"
do ##class(%SYSTEM.OBJ).Load(##class(%File).ManagerDirectory() _ "GitLab.xml","cdk")
do ##class(isc.git.Settings).setSetting("hooks", "MyApp/Hooks/")
do ##class(isc.git.Settings).setSetting("tests", "MyApp/Tests/")
do ##class(isc.git.GitLab).load()
halt

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

gitlab-ci.yml

Теперь, перейдём к конфигурации непрерывной доставки:

build image: stage: build tags: - test script: - cp -r /InterSystems/mount ci - cd ci - echo 'SuperUser' | cat - pwd.txt load_ci.script > temp.txt - mv temp.txt load_ci.script - cd .. - docker build --build-arg CI_PROJECT_DIR=$CI_PROJECT_DIR -t docker.domain.com/test/docker:$CI_COMMIT_REF_NAME .

Что здесь происходит?

Прежде всего, поскольку процесс сборки образа может получить доступ только к подкаталогам базового каталога — в нашем случае корневого каталога репозитория, нужно скопировать «секретный» каталог (в котором есть GitLab.xml, iris.key, pwd.txt и load_ci.skript) в клонированный репозиторий.

Далее, для доступа к терминалу требуется пользователь/пароль, поэтому мы добавим их к load_ci.script (для этого нам и нужна пустая строка в начале load_ci.script).

Наконец, мы создаем Docker Image и называем его: docker.domain.com/test/docker:$CI_COMMIT_REF_NAME

Обратите внимание: первая часть тега образа должна совпадать с именем репозитория в GitLab, чтобы ее можно было увидеть на вкладке Registry (более полные инструкции по корректному тегированию доступны там же). где $CI_COMMIT_REF_NAME — это имя ветви.

Dockerfile

Docker Image создаётся с помощью Dockerfile, вот он:

FROM docker.intersystems.com/intersystems/iris:2018.1.1.613.0 ENV SRC_DIR=/tmp/src
ENV CI_DIR=$SRC_DIR/ci
ENV CI_PROJECT_DIR=$SRC_DIR COPY ./ $SRC_DIR RUN cp $CI_DIR/iris.key $ISC_PACKAGE_INSTALLDIR/mgr/ \ && cp $CI_DIR/GitLab.xml $ISC_PACKAGE_INSTALLDIR/mgr/ \ && $ISC_PACKAGE_INSTALLDIR/dev/Cloud/ICM/changePassword.sh $CI_DIR/pwd.txt \ && iris start $ISC_PACKAGE_INSTANCENAME \ && irissession $ISC_PACKAGE_INSTANCENAME -U%SYS < $CI_DIR/load_ci.script \ && iris stop $ISC_PACKAGE_INSTANCENAME quietly

Выполняются следующие действия:

  • За основу берём образ InterSystems IRIS. Он должен быть в вашем Docker Registry. Если вы раньше не работали с Docker, попробуйте First Look: Docker, где описывается получение образа InterSystems IRIS, его добавление в Docker Registry и ручной запуск.
  • Прежде всего, копируем наш репозиторий (и «секретный» каталог) внутрь контейнера.
  • Копируем лицензионный ключ и GitLab.xml в каталог mgr.
  • Меняем пароль на значение из pwd.txt. Обратите внимание, что pwd.txt удаляется при этой операции.
  • Запускается InterSystems IRIS.
  • Выполняется load_ci.script.
  • InterSystems IRIS останавливается.

Вот частичный лог сборки

Running with gitlab-runner 10.6.0 (a3543a27) on docker 7b21e0c4
Using Shell executor...
Running on docker...
Fetching changes...
Removing ci/
Removing temp.txt
HEAD is now at 5ef9904 Build load_ci.script
From http://gitlab.eduard.win/test/docker 5ef9904..9753a8d master -> origin/master
Checking out 9753a8db as master...
Skipping Git submodules setup
$ cp -r /InterSystems/mount ci
$ cd ci
$ echo 'SuperUser' | cat - pwd.txt load_ci.script > temp.txt
$ mv temp.txt load_ci.script
$ cd ..
$ docker build --build-arg CI_PROJECT_DIR=$CI_PROJECT_DIR -t docker.eduard.win/test/docker:$CI_COMMIT_REF_NAME .
Sending build context to Docker daemon 401.4kB Step 1/6 : FROM docker.intersystems.com/intersystems/iris:2018.1.1.613.0 ---> cd2e53e7f850
Step 2/6 : ENV SRC_DIR=/tmp/src ---> Using cache ---> 68ba1cb00aff
Step 3/6 : ENV CI_DIR=$SRC_DIR/ci ---> Using cache ---> 6784c34a9ee6
Step 4/6 : ENV CI_PROJECT_DIR=$SRC_DIR ---> Using cache ---> 3757fa88a28a
Step 5/6 : COPY ./ $SRC_DIR ---> 5515e13741b0
Step 6/6 : RUN cp $CI_DIR/iris.key $ISC_PACKAGE_INSTALLDIR/mgr/ && cp $CI_DIR/GitLab.xml $ISC_PACKAGE_INSTALLDIR/mgr/ && $ISC_PACKAGE_INSTALLDIR/dev/Cloud/ICM/changePassword.sh $CI_DIR/pwd.txt && iris start $ISC_PACKAGE_INSTANCENAME && irissession $ISC_PACKAGE_INSTANCENAME -U%SYS < $CI_DIR/load_ci.script && iris stop $ISC_PACKAGE_INSTANCENAME quietly ---> Running in 86526183cf7c
.
Waited 1 seconds for InterSystems IRIS to start
This copy of InterSystems IRIS has been licensed for use exclusively by:
ISC Internal Container Sharding
Copyright (c) 1986-2018 by InterSystems Corporation
Any other use is a violation of your license agreement %SYS>
1 %SYS>
Using 'iris.cpf' configuration file This copy of InterSystems IRIS has been licensed for use exclusively by:
ISC Internal Container Sharding
Copyright (c) 1986-2018 by InterSystems Corporation
Any other use is a violation of your license agreement 1 alert(s) during startup. See messages.log for details.
Starting IRIS Node: 39702b122ab6, Instance: IRIS Username:
Password: Load started on 04/06/2018 17:38:21
Loading file /usr/irissys/mgr/GitLab.xml as xml
Load finished successfully. USER> USER> [2018-04-06 17:38:22.017] Running init hooks: before [2018-04-06 17:38:22.017] Importing hooks dir /tmp/src/MyApp/Hooks/ [2018-04-06 17:38:22.374] Executing hook class: MyApp.Hooks.Global [2018-04-06 17:38:22.375] Executing hook class: MyApp.Hooks.Local [2018-04-06 17:38:22.375] Importing dir /tmp/src/ Loading file /tmp/src/MyApp/Tests/TestSuite.cls as udl Compilation started on 04/06/2018 17:38:22 with qualifiers 'c'
Compilation finished successfully in 0.194s. Load finished successfully. [2018-04-06 17:38:22.876] Running init hooks: after [2018-04-06 17:38:22.878] Executing hook class: MyApp.Hooks.Local [2018-04-06 17:38:22.921] Executing hook class: MyApp.Hooks.Global
Removing intermediate container 39702b122ab6 ---> dea6b2123165
[Warning] One or more build-args [CI_PROJECT_DIR] were not consumed
Successfully built dea6b2123165
Successfully tagged docker.domain.com/test/docker:master
Job succeeded

Запуск

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

Сначала скрипт удаления старого контейнера.

destroy old: stage: destroy tags: - test script: - docker stop iris-$CI_COMMIT_REF_NAME || true - docker rm -f iris-$CI_COMMIT_REF_NAME || true

Этот скрипт уничтожает запущенный контейнер и всегда завершается успешно (по умолчанию Docker возвращает ошибку, при попытке остановить/удалить несуществующий контейнер).

После этого мы запускаем новый контейнер и регистрируем его как окружение.

run image: stage: run environment: name: $CI_COMMIT_REF_NAME url: http://$CI_COMMIT_REF_SLUG.docker.eduard.win/index.html tags: - test script: - docker run -d --expose 52773 --volume /InterSystems/durable/$CI_COMMIT_REF_SLUG:/data --env ISC_DATA_DIRECTORY=/data/sys --env VIRTUAL_HOST=$CI_COMMIT_REF_SLUG.docker.eduard.win --name iris-$CI_COMMIT_REF_NAME docker.eduard.win/test/docker:$CI_COMMIT_REF_NAME --log $ISC_PACKAGE_INSTALLDIR/mgr/messages.log

Контейнер Nginx автоматически перенаправляет запросы с использованием переменной среды VIRTUAL_HOST на указанный порт — в данном случае 52773.

Так как необходимо хранить некоторые данные (пароли, %SYS, данные приложения) на хосте в InterSystems IRIS существует функциональность Durable %SYS, позволяющая хранить на хосте такие данные, как:

  • iris.cpf — основной файл конфигурации.
  • Директорию /csp с файлами веб-приложений.
  • /httpd/httpd.conf с конфигурацией приватного сервера Apache.
  • Директорию /mgr, в которой хранятся:
    • Базы данных IRISSYS, IRISTEMP, IRISAUDIT, IRIS, USER.
    • IRIS.WIJ.
    • Директорию /journal хранящую журналы.
    • Директорию /temp для временных файлов.
    • Логи messages.log, journal.log, SystemMonitor.log.

Эта директория не должна существовать, она создастся автоматически. Для включения Durable %SYS указывается аргумент volume монтирующий директорию хоста и переменная ISC_DATA_DIRECTORY устанавливающая директорию для хранения файлов Durable %SYS.

Таким образом архитектура нашего контейнеризированного приложения следующая:

архитектура контейнеризированного приложения

Я использовал область USER для хранения данных приложения, поскольку эта область по умолчанию добавлена в Durable %SYS. Чтобы собрать такое приложение, мы, как минимум, должны создать одну дополнительную базу данных (чтобы сохранить код приложения) и создать её маппинг в область приложения. Код приложения хранится в контейнере чтобы можно было его обновлять.

Исходя из вышесказанного, %Installer должен:

  • Создать область/базу данных APP
  • Загрузить код в область APP
  • Создать маппинг классов нашего приложения в область USER
  • Выполнить прочую настройку (я создал CSP веб-приложение и REST веб-приложение)

Код %Installer

Class MyApp.Hooks.Local
{ Parameter Namespace = "APP"; /// See generated code in zsetup+1^MyApp.Hooks.Local.1
XData Install [ XMLNamespace = INSTALLER ]
{
<Manifest> <Log Text="Creating namespace $" Level="0"/>
<Namespace Name="${Namespace}" Create="yes" Code="${Namespace}" Ensemble="" Data="IRISTEMP">
<Configuration>
<Database Name="${Namespace}" Dir="/usr/irissys/mgr/${Namespace}" Create="yes" MountRequired="true" Resource="%DB_${Namespace}" PublicPermissions="RW" MountAtStartup="true"/>
</Configuration> <Import File="${Dir}Form" Recurse="1" Flags="cdk" IgnoreErrors="1" />
</Namespace>
<Log Text="End Creating namespace ${Namespace}" Level="0"/> <Log Text="Mapping to USER" Level="0"/>
<Namespace Name="USER" Create="no" Code="USER" Data="USER" Ensemble="0">
<Configuration>
<Log Text="Mapping Form package to USER namespace" Level="0"/>
<ClassMapping From="${Namespace}" Package="Form"/>
<RoutineMapping From="${Namespace}" Routines="Form" />
</Configuration> <CSPApplication Url="/" Directory="${Dir}client" AuthenticationMethods="64" IsNamespaceDefault="false" Grant="%ALL" Recurse="1" />
</Namespace> </Manifest>
} /// This is a method generator whose code is generated by XGL.
/// Main setup method
/// set vars("Namespace")="TEMP3"
/// do ##class(MyApp.Hooks.Global).setup(.vars)
ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 0, pInstaller As %Installer.Installer) As %Status [ CodeMode = objectgenerator, Internal ]
{ Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "Install")
} /// Entry point
ClassMethod onAfter() As %Status
{ try { write "START INSTALLER",! set vars("Namespace") = ..#Namespace set vars("Dir") = ..getDir() set sc = ..setup(.vars) write !,$System.Status.GetErrorText(sc),! set sc = ..createWebApp() } catch ex { set sc = ex.AsStatus() write !,$System.Status.GetErrorText(sc),! } quit sc
} /// Modify web app REST
ClassMethod createWebApp(appName As %String = "/forms") As %Status
{ set:$e(appName)'="/" appName = "/" _ appName #dim sc As %Status = $$$OK new $namespace set $namespace = "%SYS" if '##class(Security.Applications).Exists(appName) { set props("AutheEnabled") = $$$AutheUnauthenticated set props("NameSpace") = "USER" set props("IsNameSpaceDefault") = $$$NO set props("DispatchClass") = "Form.REST.Main" set props("MatchRoles")=":" _ $$$AllRoleName set sc = ##class(Security.Applications).Create(appName, .props) } quit sc
} ClassMethod getDir() [ CodeMode = expression ]
{
##class(%File).NormalizeDirectory($system.Util.GetEnviron("CI_PROJECT_DIR"))
} }

ManagerDirectory() возвращает путь к директории для Durable %SYS. Отмечу, что для создания базы данных не на хосте я использую директорию /usr/irissys/mgr, так как вызов ##class(%File).

Тесты

Теперь запустим тесты.

test image: stage: test tags: - test script: - docker exec iris-$CI_COMMIT_REF_NAME irissession iris -U USER "##class(isc.git.GitLab).test()"

Доставка

Тесты пройдены, опубликуем наш образ в Docker Registry.

publish image: stage: publish tags: - test script: - docker login docker.domain.com -u user -p pass - docker push docker.domain.com/test/docker:$CI_COMMIT_REF_NAME

Логин/пароль можно передать с использованием секретных переменных.

Теперь образ отображается на GitLab.

На вкладке Environments все наши окружения доступны для просмотра: И другие разработчики могут скачать его из Docker Registry.

Автоматизация сборки, тестирования и доставки вашего приложения на платформах InterSystems возможна и легко реализуема. В этой серии статей рассмотрены общие подходы к непрерывной интеграции.

Устранение несоответствий между окружениями позволяет упростить тестирование и отладку. Применение технологий контейнеризации поможет оптимизировать процессы разработки и развёртывания приложений. Оркестрация позволяет создавать масштабируемые приложения.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть