Entrega contínua de sua solução InterSystems usando GitLab – Parte IX: Arquitetura do contêiner
Nesta série de artigos, quero apresentar e discutir várias abordagens possíveis para o desenvolvimento de software com tecnologias da InterSystems e do GitLab. Vou cobrir tópicos como:
- Git básico
- Fluxo Git (processo de desenvolvimento)
- Instalação do GitLab
- Fluxo de trabalho do GitLab
- Entrega contínua
- Instalação e configuração do GitLab
- CI/CD do GitLab
- Por que contêineres?
- Infraestrutura dos contêineres
- CD usando contêineres
- CD usando ICM
- Arquitetura do contêiner
Neste artigo, falaríamos sobre como criar e implantar seu próprio contêiner.
%SYS durável
Como os contêineres são bastante efêmeros, eles não devem armazenar nenhum dado do aplicativo. O recurso %SYS Durável permite exatamente isso — armazenar configurações, definições, dados %SYS, etc. em um volume de host, especificamente:
- O arquivo iris.cpf.
- O diretório /csp, contendo a configuração do web gateway e os arquivos do log.
- O arquivo /httpd/httpd.conf, o arquivo de configuração do servidor Web privado da instância.
- O diretório /mgr, contendo o seguinte:
- O banco de dados do sistema IRISSYS, composta pelos arquivos IRIS.DAT e iris.lck e diretório de stream, e iristemp, irisaudit, iris e os diretórios do usuário, com os bancos de dados do sistema IRISTEMP, IRISAUDIT, IRIS e USER.
- O arquivo do registro de log de imagem de gravação, IRIS.WIJ.
- O diretório /journal com os arquivos do registro de log.
- O diretório /temp para arquivos temporários.
- Arquivos de registro, incluindo messages.log, journal.log e SystemMonitor.log.
Arquitetura do contêiner
Por outro lado, precisamos armazenar o código do aplicativo dentro do nosso contêiner para atualizá-lo quando necessário.
Tudo isso nos leva a esta arquitetura:

Para fazer isso durante o tempo de compilação, precisamos, no mínimo, criar um banco de dados adicional (para armazenar o código do aplicativo) e mapeá-lo no namespace do aplicativo. No meu exemplo, eu usaria o namespace USER para manter os dados do aplicativo, como ele já existe e é durável.
Instalador
Com base no descrito acima, nosso instalador precisa:
- Criar o namespace/banco de dados APP
- Carregar o código no namespace APP
- Mapear as classes do aplicativo para o namespace USER
- Fazer todas as outras instalações (nesse caso, criei o web app CSP e o app 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"))
}
}Para criar o banco de dados não durável, usei um subdiretório de /usr/irissys/mgr, que não é persistente. Observe que a chamada para ##class(%File).ManagerDirectory() retorna um caminho para o diretório durável, e não para o diretório do contêiner interno.
Configuração da entrega contínua
Confira a parte VII para ver as informações completas, mas tudo o que você precisa fazer é adicionar estas duas linhas (em negrito) à configuração existente.
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.logO argumento do volume monta o diretório do host para o contêiner e a variável ISC_DATA_DIRECTORY mostra ao InterSystems IRIS qual diretório usar. Para citar a documentação:
- Ao executar um contêiner InterSystems IRIS usando essas opções, ocorre o seguinte:
- O volume externo especificado é montado.
- Se o diretório %SYS durável especificado pela variável de ambiente ISC_DATA_DIRECTORY, iconfig/ no exemplo anterior, já existe e contém os dados %SYS duráveis, todos os ponteiros internos da instância são redefinidos para esse diretório e a instância usa os dados que contém.
- Se o diretório %SYS durável especificado na variável de ambiente ISC_DATA_DIRECTORY já existir, mas não conter os dados %SYS duráveis, nenhum dado é copiado e a instância é executada usando os dados na árvore de instalação dentro do contêiner, ou seja, os dados específicos da instância não são persistentes. Por esse motivo, é recomendável incluir nos scripts uma verificação para essa condição antes de executar o contêiner.
- Se o diretório %SYS durável especificado por ISC_DATA_DIRECTORY não existir:
- É criado o diretório %SYS durável.
- Os diretórios e arquivos listados no conteúdo do Diretório %SYS Durável são copiados dos locais instalados para o diretório %SYS durável (os originais permanecem no local).
- Todos os ponteiros internos da instância são redefinidos para o diretório %SYS durável e a instância usa os dados que contém.
Atualizações
Quando o aplicativo evoluir e uma nova versão (contêiner) for lançada, às vezes é necessário executar algum código. Pode ser antes ou depois dos hooks de compilação, das migrações do esquema e dos testes de unidade, mas é necessário executar código arbitrário. Por isso, você precisa de um framework que gerencie seu aplicativo. Em artigos anteriores, descrevi a estrutura básica desse framework, mas, é claro, ele pode ser consideravelmente ampliado para atender a requisitos específicos do aplicativo.
Conclusão
A criação de um aplicativo em contêiner requer algumas considerações, mas o InterSystems IRIS oferece vários recursos para facilitar esse processo.