在这一系列文章中,我想向大家介绍并探讨使用 InterSystems 技术和 GitLab 进行软件开发可以采用的几种方式。 我将介绍以下主题:
- Git 101
- Git 流程(开发流程)
- GitLab 安装
- GitLab 工作流
- 持续交付
- GitLab 安装和配置
- GitLab CI/CD
- 为何使用容器?
- 容器基础架构
- 使用容器的 CD
- 使用 ICM 的 CD
- 容器架构
在本文中,我们将讨论如何构建并部署您自己的容器。
Durable %SYS
由于容器是临时的,它们不应存储任何应用程序数据。 持久化 %SYS 功能让我们能够实现这一点 – 将设置、配置、%SYS 数据等存储到主机卷上,即:
- iris.cpf 文件。
- /csp 目录,包含 Web 网关配置和日志文件。
- /httpd/httpd.conf 文件,实例的私有 Web 服务器的配置文件。
- /mgr 目录,包含以下内容:
- IRISSYS 系统数据库,包括 IRIS.DAT 和 iris.lck 文件、流目录,以及包含 IRISTEMP、IRISAUDIT、IRIS 和 USER 系统数据库的 iristemp、irisaudit、iris 和 user 目录。
- 写入镜像日志文件,IRIS.WIJ。
- /journal 目录,包含日志文件。
- /temp 目录,用于存储临时文件。
- 日志文件,包括 messages.log、journal.log 和 SystemMonitor.log。
容器架构
另一方面,我们需要将应用程序代码存储在我们的容器内,以便在需要时进行升级。
这一切使我们实现了如下所示的架构:
为了在构建过程中实现这一点,我们至少需要创建一个额外的数据库(用于存储应用程序代码)并将其映射到我们的应用程序命名空间。 在我的示例中,我将使用 USER 命名空间来保存应用程序数据,因为它已经存在且是持久化的。
安装程序
基于上述内容,我们的安装程序需要执行以下任务:
- 创建 APP 命名空间/数据库
- 将代码加载到 APP 命名空间
- 将我们的应用程序类映射到 USER 命名空间
- 完成所有其他安装(在本例中,我创建了 CSP Web 应用和 REST 应用)
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 ${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")) } }
为了创建非持久化数据库,我会使用 /usr/irissys/mgr 的一个子目录,它不是持久的。 请注意,调用 ##class(%File).ManagerDirectory() 会返回持久化目录的路径,而不是内部容器目录的路径。
持续交付配置
查看第 7 部分以了解完整信息,但我们需要做的就是在现有配置中添加这两行(加粗)代码。
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
volume 参数将主机目录挂载到容器中,ISC_DATA_DIRECTORY 变量告诉 InterSystems IRIS 使用哪个目录。 引用文档内容:
当您使用这些选项运行 InterSystems IRIS 容器时,会发生以下情况:
如果 ISC_DATA_DIRECTORY 环境变量指定的持久化 %SYS 目录已经存在但不包含持久化 %SYS 数据,则不会复制数据,实例使用容器内安装树中的数据运行,这意味着实例特定的数据不是持久的。 因此,您可能需要在脚本中包含对此条件的检查,然后再运行容器。
将持久化 %SYS 目录内容中列出的目录和文件从其安装位置复制到持久化 %SYS 目录(原始文件仍留在原位)。
更新
当应用程序演进并发布新版本(容器)时,有时您可能需要运行一些代码。 这可能是预编译/后编译挂钩、架构迁移、单元测试,但归根结底,您需要运行任意代码。 这就是为什么您需要一个管理应用程序的框架。 在之前的文章中,我概述了这种框架的基本结构,但它当然可以大幅度扩展以满足特定应用程序的需求。
结论
创建容器化应用程序需要一些思考,但 InterSystems IRIS 提供了几个功能,可以让此流程更加轻松。