#Integração Contínua

0 Seguidores · 21 Postagens

Na engenharia de software, a integração contínua (CI) é a prática de mesclar todas as cópias de trabalho do desenvolvedor em uma linha principal compartilhada várias vezes ao dia.

Artigo Heloisa Paiva · Out. 19, 2025 14m read

Visão Geral

Esta interface web foi projetada para facilitar o gerenciamento de Tabelas de Pesquisa de Dados (Data Lookup Tables) por meio de uma página web amigável. É particularmente útil quando os valores da sua tabela de pesquisa são grandes, dinâmicos e mudam frequentemente. Ao conceder aos usuários finais acesso controlado a esta interface web (permissões de leitura, escrita e exclusão limitadas a esta página), eles podem gerenciar os dados da tabela de pesquisa de forma eficiente, de acordo com suas necessidades.

Os dados gerenciados por meio desta interface podem ser utilizados perfeitamente em regras ou transformações de dados do HealthConnect, eliminando a necessidade de constante monitoramento e gerenciamento manual das tabelas de pesquisa, economizando tempo significativo.

Nota: 

Se a Tabela de Pesquisa de Dados padrão não atender aos seus requisitos de mapeamento, você pode criar uma tabela personalizada e adaptar esta interface web, juntamente com sua classe de suporte, com modificações mínimas. O código de exemplo da classe está disponível mediante solicitação.

0
0 15
Artigo Heloisa Paiva · jan 10, 2025 1m read

Quando você implanta código de um repositório, a deleção de classes (arquivos) pode não ser refletida pelo seu sistema CICD.

Aqui está um simples código para automaticamente deletar todas as classes em um pacote específico que não foi importado; Ele pode ser facilmente ajustado para uma variedade de tarefas adjuntas:

set packages = "USER.*,MyCustomPackage.*"set dir = "C:\InterSystems\src\"set sc = $SYSTEM.OBJ.LoadDir(dir,"ck", .err, 1, .loaded)
set sc = $SYSTEM.OBJ.Delete(packages _ ",'" _ $LTS($LI($LFS(loaded_",",".cls,"), 1, *-1), ",'"),, .err2)

O primeiro comando compila classes e também retorna uma lista de classes carregadas. O segundo comando deleta todas as classes de pacotes específicos, com exceção às classes carregadas anteriormente a ele.

0
0 38
Pergunta Flávio Lúcio Naves Júnior · Nov. 7, 2023

Olá pessoal,

Estou tentando implementar integração contínua usando Docker com o Caché 2018.1, e estou no processo de criar uma imagem para o nosso cliente. Já instalei o Caché 2018.1 no servidor RedHat, mas estou trabalhando em um script para criar o banco de dados e o namespace. Para o banco de dados, utilizei o código a seguir:

do ##class(SYS.Database).CreateDatabase("/usr/cachepoc/cache2018/mgr/poc/")
5
0 141
Artigo Danusa Calixto · Abr. 4, 2023 13m read

Bem-vindo ao capítulo seguinte da minha série sobre CI/CD, onde discuto possíveis abordagens de desenvolvimento de software com tecnologias da InterSystems e GitLab.

Hoje, vamos falar sobre interoperabilidade.

Problema

Em uma produção de interoperabilidade ativa, há dois fluxos de processo separados: uma produção em funcionamento que processa as mensagens e um fluxo de processo CI/CD que atualiza o código, a configuração da produção e as configurações padrão do sistema.

Claramente, os processos CI/CD afetam a interoperabilidade. No entanto, as perguntas são:

  • O que acontece exatamente durante uma atualização?
  • O que precisamos fazer para minimizar ou eliminar o tempo de inatividade da produção durante uma atualização?

Terminologia

  • Host de Negócio (Business Host - BH) - um elemento configurável da Produção da Interoperabilidade: Serviço de Negócio (Business Service - BS), Processo de Negócio ( Business Process - BP, BPL) ou Operação de Negócio (Business Operation, BO).
  • Job do Host de Negócio (Business Host Job) - job do InterSystems IRIS que executa o código do Host de Negócio e é gerenciado pela produção de interoperabilidade.
  • Produção - coleção interconectada de Hosts de Negócio.
  • Configurações Padrão do Sistema (System Default Settings - SDS) - valores específicos do ambiente de instalação do InterSystems IRIS.
  • Mensagem Ativa - uma solicitação que está sendo processada por um Job do Host de Negócio. Um Job do Host de Negócio só pode ter uma Mensagem Ativa. O Job do Host de Negócio que não tem uma Mensagem Ativa está inativo.

O que está acontecendo?

Vamos começar com o ciclo de vida da produção.

Início da Produção

Primeiro, a Produção pode ser iniciada. Só pode ser executada uma produção por namespace ao mesmo tempo, e em geral (a menos que você saiba o que e porque está fazendo isso), apenas uma produção deve ser executada por namespace. Alternar várias vezes em um namespace entre duas ou mais produções diferentes não é recomendado. Ao iniciar a produção, todos os Hosts de Negócio habilitados definidos nela são inicializados. Se alguns Hosts de Negócio não inicializarem, isso não afeta a inicialização da Produção.

Dicas:

  • Comece a produção no Portal de Gerenciamento de Sistemas ou ao chamar: ##class(Ens.Director).StartProduction("ProductionName")
  • Execute código arbitrário na inicialização da Produção (antes que qualquer Job do Host de Negócio seja inicializado) ao implementar um método OnStart
  • A inicialização da Produção é um evento auditável. Você sempre pode ver quem e quando fez o que no Log de Auditoria.

Atualização da Produção

Após a inicialização da Produção, Ens.Director monitora continuamente a produção em execução. Há dois estados de produção: o estado desejado, definido na classe da produção e nas Configurações Padrão do Sistema, e o estado em execução, os jobs atualmente em execução com configurações aplicadas quando os jobs foram criados. Se os estados desejado e atual forem idênticos, está tudo bem, mas a produção pode (e deve) ser atualizada se houver uma diferença. Geramente, você vê isso como um botão vermelho Update na página de Configurações da Produção no Portal de Gerenciamento de Sistemas.

A atualização da produção significa uma tentativa de corresponder o estado atual da Produção ao estado visado.

A execução de ##class(Ens.Director).UpdateProduction(timeout=10, force=0) para atualizar a produção faz o seguinte com cada Host de Negócio:

  1. Compara as configurações ativas às configurações de produção/SDS/classe
  2. Se, e apenas se, (1) apresentar uma discrepância, o Host de Negócio será marcado como desatualizado, exigindo uma atualização.

Depois de executar isso para cada Host de Negócio, UpdateProduction cria o conjunto de mudanças:

  • Hosts de Negócio para interromper
  • Hosts de Negócio para inicializar
  • Configurações da produção para atualizar

E, depois disso, aplica essas mudanças.

Dessa forma, "atualizar" as configurações sem mudar nada resulta em nenhum tempo de inatividade da produção.

Dicas:

  • Atualize a produção no Portal de Gerenciamento de Sistemas ou ao chamar: ##class(Ens.Director).UpdateProduction(timeout=10, force=0)
  • O tempo limite de atualização padrão do Portal de Gerenciamento de Sistemas é 10 segundos. Se você sabe que o processamento das mensagens leva mais do que isso, chame Ens.Director:UpdateProduction com um tempo limite maior.
  • O tempo limite da atualização é uma configuração da produção, e você pode mudar para um valor maior. Essa configuração se aplica ao Portal de Gerenciamento de Sistemas.

Atualização do código

UpdateProduction NÃO ATUALIZA BHs com código desatualizado. Esse é um comportamento voltado para a segurança, mas, se você quiser atualizar todos os BHs em execução automaticamente se o código subjacente mudar, siga estas etapas:

Primeiro, carregue e compile desta maneira:

do $system.OBJ.LoadDir(dir, "", .err, 1, .load)
do $system.OBJ.CompileList(load, "curk", .errCompile, .listCompiled)

Agora, listCompiled teria todos os itens que foram realmente compilados (use git diffs para minimizar o conjunto carregado) devido à flag u. Use listCompiled para obter um $lb de todas as classes que foram compiladas:

set classList = ""
set class = $o(listCompiled(""))
while class'="" { 
  set classList = classList _ $lb($p(class, ".", 1, *-1))
  set class=$o(listCompiled(class))
}

Depois disso, calcule uma lista de BHs que precisam de uma reinicialização:

SELECT %DLIST(Name) bhList
FROM Ens_Config.Item 
WHERE 1=1
  AND Enabled = 1
  AND Production = :production
  AND ClassName %INLIST :classList

Por fim, após obter bhList, interrompa e inicie os hosts afetados:

for stop = 1, 0 {
  for i=1:1:$ll(bhList) {
    set host = $lg(bhList, i)
    set sc = ##class(Ens.Director).TempStopConfigItem(host, stop, 0)
  }
  set sc = ##class(Ens.Director).UpdateProduction()
}

Interrupção da produção

As produções podem ser interrompidas, ou seja, uma solicitação pode ser enviada para desativar todos os Jobs do Host de Negócio (com segurança, após lidarem com as mensagens ativas, se houver alguma).

Dicas:

  • Interrompa a produção no Portal de Gerenciamento de Sistemas ou ao chamar: ##class(Ens.Director).StopProduction(timeout=10, force=0)
  • O tempo limite de interrupção padrão do Portal de Gerenciamento de Sistemas é 120 segundos. Se você sabe que o processamento das mensagens leva mais do que isso, chame Ens.Director:StopProduction com um tempo limite maior.
  • O tempo limite de interrupção é uma configuração da produção. Você pode alterar isso para um valor maior. Essa configuração se aplica ao Portal de Gerenciamento de Sistemas.
  • Execute código arbitrário na interrupção da produção ao implementar um método OnStart
  • A interrupção da produção é um evento auditável. Você sempre pode ver quem e quando fez o que no Log de Auditoria.

O importante aqui é que a produção seja a soma total dos Hosts de Negócio:

  • Ao iniciar a produção, todos os Hosts de Negócio habilitados são inicializados.
  • A interrupção da produção também interrompe todos os Hosts de Negócio em execução.
  • A atualização da produção significa calcular um subconjunto de Hosts de Negócio que estão desatualizados, para que sejam interrompidos e, imediatamente depois disso, inicializados novamente. Além disso, um Host de Negócio recém-adicionado é inicializado, e um Host de Negócio excluído da produção é interrompido.

Isso nos leva ao ciclo de vida dos Hosts de Negócio.

Inicialização do Host de Negócio

Os Hosts de Negócio são compostos de Jobs de Hosts de Negócio idênticos (de acordo com um valor de configuração de tamanho do pool). Ao inicializar um Host de Negócio, todos os Jobs de Hosts de Negócio também são inicializados. Eles são inicializados em paralelo.

Jobs de Host de Negócio individuais são inicializados desta maneira:

  1. A interoperabilidade define como job um novo processo que se tornaria um Job de Host de Negócio.
  2. O novo processo é registrado como um job de interoperabilidade.
  3. O código de Host de Negócio e o código do Adapter são carregados na memória do processo.
  4. As configurações relacionadas a um Host de Negócio e Adapter são carregadas na memória. A ordem de precedência é: a. Configurações da Produção (substituem as Configurações de Classe e Padrão do Sistema). b. Configurações Padrão do Sistema (substituem as Configurações de Classe). c. Configurações de classe.
  5. O job está pronto e começa a aceitar mensagens.

Após a conclusão de (4), o Job não pode alterar as configurações ou o código, então quando você importa código novo/igual e configurações padrão do sistema novas/iguais, isso não afeta os jobs de interoperabilidade atualmente em execução.

Interrupção do Hosts de Negócio

Interromper um Job de Host de Negócio significa o seguinte:

  1. A interoperabilidade pede que o Job pare de aceitar mensagens/entradas.
  2. Se houver uma mensagem ativa, o Job de Host de Negócio tem segundos de tempo limite para processar (ao concluir, finalizando o método OnMessage para BO, OnProcessInput para BS, S<int> para BPL BPs e On* para BPs).
  3. Se uma mensagem ativa não for processada até o tempo limite e force=0, ocorrerá a falha da atualização da produção para esse Host de Negócio (voce verá um botão "Update" vermelho no Portal de Gerenciamento de Sistemas).
  4. A interrupção é bem-sucedida se algo nesta lista for verdadeiro:
    • Nenhuma mensagem ativa
    • A mensagem ativa foi processada antes de timeout
    • A mensagem ativa não foi processada antes do tempo limite, MAS force=1
  5. O job é cancelado com interoperabilidade e é interrompido.

Atualização do Host de Negócio

A atualização do Host de Negócio significa a interrupção de todos os Jobs em execução para o Host de Negócio e a inicialização de novos Jobs.

Regras de negócios, de roteamento e DTLs

Todos os Hosts de Negócio são inicializados imediatamente usando as novas versões das Regras de negócios, de roteamento e DTLs assim que ficarem disponíveis. A reinicialização de um Host de Negócio não é necessária nesse caso.

Atualizações offline

Às vezes, no entanto, as atualizações da produção exigem tempo de inatividade de Hosts de Negócio individuais.

Regras dependem de novo código

Considere a situação. Você tem uma Regra de Roteamento X atual que encaminha as mensagens para o Processo de Negócio A ou B com base em critérios arbitrários. Em um novo commit, você adiciona, simultaneamente:

  • Processo de Negócio C
  • Uma nova versão da Regra de Roteamento X, que encaminha mensagens para A, B ou C.

Nesse caso, você não pode só carregar a regra primeiro e depois atualizar a produção. A regra recém-copilada imediatamente começaria a encaminhar as mensagens para o Processo de Negócio C, que o InterSystems IRIS talvez ainda não tenha compilado ou a interoperabilidade ainda não tenha atualizado para usar. Nesse caso, você precisa desativar o Host de Negócio com uma Regra de Roteamento, atualizar o código, atualizar a produção e ativar o Host de Negócio novamente.

Observações:

  • Se você atualizar uma produção usando um arquivo de implantação de produção, todos os BHs afetados são desativados/ativados automaticamente.
  • Para hosts invocados InProc, a compilação invalida o cache de um host específico mantido pelo autor da chamada.

Dependências entre Hosts de Negócio

As dependências entre Hosts de Negócio são fundamentais. Suponha que você tenha os Processos de Negócio A e B, em que A envia mensagens a B. Em um novo commit, você adiciona, simultaneamente:

  • Uma nova versão do Processo A, que define uma nova propriedade X em uma solicitação para B
  • Uma nova versão do Processo B que pode processar uma nova propriedade X

Nesse caso, PRECISAMOS atualizar o Processo B primeiro e o A depois. Você pode fazer isso de uma das seguintes maneiras:

  • Desativar Hosts de Negócio durante a atualização
  • Divida a atualização em duas partes: primeiro, atualize apenas o Processo B e, depois, em uma atualização separada, comece a enviar mensagens para ele do Processo A.

Uma variação mais desafiadora desse tema, em que as novas versões dos Processos A e B são incompatíveis com as versões antigas, exige tempo de inatividade do Host de Negócio.

Filas

Se você sabe que, após a atualização, um Host de Negócio não conseguirá processar mensagens antigas, você precisa garantir que a Fila do Host de Negócio esteja vazia antes da atualização. Para isso, desative todos os Hosts de Negócio que enviam mensagens para o Host de Negócios e espere até que a fila fique vazia.

Mudança de estado nos Processos de Negócio BPL

Primeiro, uma pequena introdução sobre como funcionam os BPs do BPL. Depois de compilar um BP do BPL, duas classes são criadas no pacote com o mesmo nome que o da classe BPL completa:

  • A classe Thread1 contém os métodos S1, S2, ... SN, que corresponde às atividades no BPL
  • A classe Context tem todas as variáveis de contexto, além do próximo estado que o BPL executaria (ou seja, S5)

Além disso, a classe BPL é persistente e armazena as solicitações que estão sendo processadas.

O BPL funciona ao executar os métodos S em uma classe Thread e atualizando de maneira correspondente a tabela da classe BPL, Context e Thread1, em que uma mensagem "em processamento" é uma linha em uma tabela BPL. Após o processamento da solicitação, o BPL exclui as entradas do BPL, Context e Thread. Como os BPs do BPL são assíncronos, um job BPL pode processar simultaneamente várias solicitações ao salvar as informações entre chamadas S e alternar entre diferentes solicitações. Por exemplo, o BPL processou uma solicitação até chegar a uma atividade sync, aguardando uma resposta da BO. Ele salvaria o contexto atual no disco, com a propriedade %NextState (na classe Thread1) definida para o método S de atividade de resposta e trabalharia em outras solicitações até a BO responder. Após a resposta da BO, o BPL carregaria "Context" na memória e executaria o método correspondente a um estado salvo na propriedade %NextState.

Agora, o que acontece quando atualizamos o BPL? Primeiro, precisamos conferir se pelo menos uma destas condições é atendida:

  • Durante a atualização, a tabela Context está vazia, o que significa que nenhuma mensagem ativa está em trabalho.
  • Os Novos Estados são os mesmos que os antigos ou os novos Estados são adicionados após os antigos.

Se pelo menos uma condição for atendida, podemos continuar. Não há solicitações de pré-atualização para processar o BPL pós-atualização ou os Estados são adicionados no final, o que significa que as solicitações antigas também podem ir para lá (supondo que as solicitações de pré-atualização sejam compatíveis com as atividades e o processamento do BPL pós-atualização).

Mas e se você tiver solicitações ativas em processamento e o BPL mudar a ordem dos estados? O ideal é, se você puder esperar, desativar os autores de chamada do BPL e esperar até que a fila esteja vazia. Valide se a tabela Context também está vazia. Lembre-se de que a Fila mostra apenas as solicitações não processadas e a tabela Context armazena as solicitações em trabalho, então um BPL muito ocupado pode mostrar o tamanho da Fila como zero e isso é normal. Depois disso, desative o BPL, realize a atualização e ative todos os Hosts de Negócio desativados anteriormente.

Se isso não for possível (geralmente quando o BPL é muito longo, lembro de atualizar um que demorou cerca de uma semana para processar uma solicitação, ou a janela de atualização é muito curta), use o versionamento do BPL.

Como alternativa, você pode escrever um script de atualização. No script de atualização, mapeie os próximos estados antigos para os próximos estados novos e execute na tabela Thread1 para que o BPL atualizado possa processar solicitações antigas. O BPL precisa ser desativado durante a atualização. Dito isso, é uma situação extremamente rara e geralmente desnecessária, mas, se precisar fazer isso, é dessa maneira.

Conclusão

A interoperabilidade implementa um algoritmo sofisticado para minimizar o número de ações necessárias para atualizar a produção após a alteração do código subjacente. Chame UpdateProduction com um tempo limite seguro em cada atualização de SDS. Para cada atualização de código, você precisa decidir uma estratégia.

Minimizar a quantidade de código compilado usando git diffs ajuda no tempo de compilação, mas "atualizar" o código com ele mesmo e compilá-lo novamente ou "atualizar" as configurações com os mesmos valores não aciona ou exige uma atualização da produção.

Atualizar e compilar Regras de Negócio, Regras de Roteamento e DTLs os torna imediatamente acessíveis sem a atualização da produção.

Por fim, a atualização da produção é uma operação segura e geralmente não requer tempo de inatividade.

Links

O autor gostaria de agradecer a @James MacKeith, @Dmitry Zasypkin e @Regilo Regilio Guedes de Souza pela ajuda inestimável com este artigo.

0
0 65
Artigo Danusa Calixto · Abr. 3, 2023 7m read

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.log

O 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.

0
0 77
Artigo Danusa Calixto · Fev. 23, 2023 9m read

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

Neste artigo, vamos desenvolver a entrega contínua com o InterSystems Cloud Manager. O ICM é uma solução de provisionamento e implantação na nuvem para aplicativos baseados no InterSystems IRIS. Ele permite definir a configuração de implantação desejada e o ICM provisiona de maneira automática. Para mais informações, consulte First Look: ICM.

Fluxo de trabalho

Na nossa configuração de entrega contínua:

  • Enviamos código para o repositório do GitLab
  • Criamos a imagem docker
  • Publicamos a imagem no registro docker
  • Testamos em um servidor de teste
  • Se os testes forem aprovados, implantamos em um servidor de produção

Ou em formato gráfico:

Como você pode ver, é praticamente igual, exceto que usaríamos o ICM em vez de gerenciar os contêineres do Docker manualmente.

Configuração do ICM

Antes de atualizar os contêineres, eles devem ser provisionados. Para isso precisamos definir defaults.json e definitions.json, descrevendo nossa arquitetura. Vou fornecer esses 2 arquivos para um servidor LIVE, as definições para um servidor TEST são as mesmas, e os padrões são os mesmos, exceto para os valores Tag e SystemMode.

defaults.json:

{
    "Provider": "GCP",
    "Label": "gsdemo2",
    "Tag": "LIVE","SystemMode": "LIVE",
    "DataVolumeSize": "10",
    "SSHUser": "sample",
    "SSHPublicKey": "/icmdata/ssh/insecure.pub",
    "SSHPrivateKey": "/icmdata/ssh/insecure",
    "DockerImage": "eduard93/icmdemo:master",
    "DockerUsername": "eduard93",
    "DockerPassword": "...",
    "TLSKeyDir": "/icmdata/tls",
    "Credentials": "/icmdata/gcp.json",
    "Project": "elebedyu-test",
    "MachineType": "n1-standard-1",
    "Region": "us-east1",
    "Zone": "us-east1-b",
    "Image": "rhel-cloud/rhel-7-v20170719",
    "ISCPassword": "SYS",
    "Mirror": "false"
}

definitions.json

[
    {
    "Role": "DM",
    "Count": "1",
    "ISCLicense": "/icmdata/iris.key"
    }
]

Dentro do contêiner ICM, a pasta /icmdata é montada a partir do host e:

  • As definições do servidor TEST são colocadas na pasta /icmdata/test
  • As definições do servidor LIVE são colocadas na pasta /icmdata/live

Depois de obter todas as chaves necessárias:

keygenSSH.sh /icmdata/ssh
keygenTLS.sh /icmdata/tls

E colocar os arquivos necessários em /icmdata:

  • iris.key
  • gcp.json (para a implantação no Google Cloud Platform)

Chame o ICM para provisionar suas instâncias:

cd /icmdata/test
icm provision
icm run
cd /icmdata/live
icm provision
icm run

Um servidor TEST e um servidor LIVE seriam provisionados com uma instância do InterSystems IRIS independente em cada um.

Consulte ICM First Look para ver um guia mais detalhado.

Criação

Primeiro, precisamos criar nossa imagem.

Nosso código seria, como sempre, armazenado no repositório, a configuração de CD em gitlab-ci.yml. No entanto, além disso (para aumentar a segurança), armazenaríamos vários arquivos específicos do servidor em um servidor de compilação.

iris.key

Chave de licença. Como alternativa, ela pode ser baixada durante a compilação do contêiner em vez de armazenada em um servidor. É bastante arriscado armazenar no repositório.

pwd.txt

Arquivo contendo a senha padrão. Novamente, é bastante arriscado armazená-lo no repositório. Além disso, se você estiver hospedando um ambiente de produção em um servidor separado, ele poderá ter uma senha padrão diferente.

load_ci_icm.script

O script inicial:

  • Carrega o instalador
  • O instalador inicializa o aplicativo
  • Carrega o código
set dir = ##class(%File).NormalizeDirectory($system.Util.GetEnviron("CI_PROJECT_DIR"))
do ##class(%SYSTEM.OBJ).Load(dir _ "Installer/Global.cls","cdk")
do ##class(Installer.Global).init()
halt

Observe que a primeira linha é deixada em branco de maneira intencional.

Várias coisas diferem dos exemplos anteriores. Em primeiro lugar, não habilitamos a autenticação do SO, pois o ICM interagiria com o contêiner em vez do GitLab diretamente. Segundo, estou usando o manifesto do instalador para inicializar nosso aplicativo para mostrar diferentes abordagens de inicialização. Leia mais sobre o Instalador neste artigo. Por fim, publicaremos nossa imagem em um Docher Hub como um repositório privado.

 

Installer/Global.cls

Nosso manifesto do instalador fica desta forma:

E implementa as seguintes mudanças:

  1. Cria o namespace do aplicativo.
  2. Cria o banco de dados de código do aplicativo (os dados seriam armazenados no banco de dados USER).
  3. carrega o código no banco de dados de código do aplicativo.
  4. Mapeia o pacote MyApp para o namespace USER.
  5. Cria dois aplicativos para a Web: para HTML e para REST.

gitlab-ci.yml

Agora, para a configuração da entrega contínua:

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

O que está acontecendo aqui?

Primeiro, como o docker build pode acessar apenas subdiretórios de um diretório de compilação base — na raiz do repositório do nosso caso, precisamos copiar nosso diretório "secreto" (aquele com iris.keypwd.txt e load_ci_icm.script) no repositório clonado.

Em seguida, o primeiro acesso ao terminal requer um usuário/senha, então nós os adicionamos a load_ci.script (por isso a linha vazia no início de load_ci.script).

Por fim, criamos a imagem do docker e a marcamos adequadamente:  eduard93/icmdemo:$CI_COMMIT_REF_NAME

onde $CI_COMMIT_REF_NAME é o nome de um branch atual. Observe que a primeira parte da tag de imagem deve ter o mesmo nome do nome do projeto no GitLab, para que possa ser vista na guia GitLab Registry (instruções sobre a marcação estão disponíveis na guia Registry).

Dockerfile

A criação de uma imagem docker é feita usando o Dockerfile:

FROM intersystems/iris:2018.1.1-released

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

Começamos a partir do contêiner básico iris.

Primeiro, copiamos nosso repositório (e diretório "secreto") dentro do contêiner.

Em seguida, copiamos a chave de licença para o diretório mgr.

Em seguida, alteramos a senha para o valor de pwd.txt. Observe que pwd.txt é excluído nessa operação.

Depois disso, a instância é iniciada e load_ci.script é executado.

Por fim, a instância iris é interrompida.

Estou usando o executor GitLab Shell, e não o executor Docker. O executor Docker é usado quando você precisa de algo de dentro da imagem, por exemplo, você está criando um aplicativo Android em um contêiner java e precisa apenas de um apk. No nosso caso, precisamos de um contêiner inteiro e, para isso, precisamos do executor Shell. Então, estamos executando comandos do Docker pelo executor GitLab Shell.

Publicar

Agora, vamos publicar nossa imagem em um Docker Hub

publish image:
  stage: publish
  tags:
    - master
  script:
    - docker login -u eduard93 -p ${DOCKERPASSWORD}
    - docker push eduard93/icmdemo:$CI_COMMIT_REF_NAME

Observe a variável ${DOCKERPASSWORD}, é uma variável secreta do GitLab. Podemos adicioná-la em GitLab > Project > Settings > CI/CD > Variables:

Os logs de job também não contêm valor de senha:

Running with gitlab-runner 10.6.0 (a3543a27)
  on icm 82634fd1
Using Shell executor...
Running on docker...
Fetching changes...
Removing ci/
HEAD is now at 8e24591 Add deploy to LIVE
Checking out 8e245910 as master...Skipping Git submodules setup$ docker login -u eduard93 -p ${DOCKERPASSWORD}
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
Login Succeeded
$ docker push eduard93/icmdemo:$CI_COMMIT_REF_NAME
The push refers to repository [docker.io/eduard93/icmdemo]
master: digest: sha256:d1612811c11154e77c84f0c08a564a3edeb7ddbbd9b7acb80754fda97f95d101 size: 2620
Job succeeded

e no Docker Hub podemos ver nossa nova imagem:

 

Executar

Temos nossa imagem, agora vamos executá-la em nosso servidor de teste. Aqui está o script.

run image:
  stage: run
  environment:
    name: $CI_COMMIT_REF_NAME
  tags:
    - master
  script:
    - docker exec icm sh -c "cd /icmdata/test && icm upgrade -image eduard93/icmdemo:$CI_COMMIT_REF_NAME"

Com o ICM, precisamos executar apenas um comando (icm upgrade) para fazer upgrade da implantação existente. Estamos chamando-a executando "docker exec icm sh -c ", que executa um comando especificado dentro do contêiner icm.  Primeiro, entramos no modo /icmdata/test, onde a definição da implantação do ICM é configurada para um servidor TEST. Depois disso, chamamos icm upgrade para substituir o contêiner existente por um novo contêiner.

Teste

Vamos fazer alguns testes.

test image:
  stage: test
  tags:
    - master
  script:
    - docker exec icm sh -c "cd /icmdata/test && icm session -namespace USER -command 'do \$classmethod(\"%UnitTest.Manager\",\"RunTest\",\"MyApp/Tests\",\"/nodelete\")' | tee /dev/stderr | grep 'All PASSED' && exit 0 || exit 1"

Novamente, estamos executando um comando dentro do nosso contêiner icm. A sessão icm executa um comando em um nó implantado. O comando executa testes de unidade. Depois disso, ele canaliza todos os resultados para a tela e também para o grep para encontrar os resultados dos testes de unidade e sair do processo com sucesso ou com um erro.

Implantar

A implantação em um servidor de produção é absolutamente igual à implantação em teste, exceto por outro diretório para a definição da implantação LIVE. Se os testes falhassem, essa etapa não seria executada.

deploy image:
  stage: deploy
  environment:
    name: $CI_COMMIT_REF_NAME
  tags:
    - master
  script:
    - docker exec icm sh -c "cd /icmdata/live && icm upgrade -image eduard93/icmdemo:$CI_COMMIT_REF_NAME"

Conclusão

O ICM oferece uma maneira simples e intuitiva de provisionar uma infraestrutura na nuvem e implantar serviços nela, ajudando você a entrar na nuvem<nobr>agora</nobr> sem grande desenvolvimento ou reorganização. Os benefícios da infraestrutura como código (IaC) e da implantação em contêiner facilitam a implantação de aplicativos baseados no InterSystems IRIS em plataformas de nuvem públicas, como Google, Amazon e Azure, ou na sua nuvem privada VMware vSphere. Defina o que você quer, emita alguns comandos e o ICM faz o resto.
Mesmo se você já estiver usando infraestrutura de nuvem, contêineres ou ambos, o ICM reduz drasticamente o tempo e o esforço necessários para provisionar e implantar seu aplicativo automatizando várias etapas manuais.
0
0 71
Artigo Danusa Calixto · Fev. 23, 2023 3m read

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:

  • Primeiro artigo
    • Conceitos básicos do Git, por que um entendimento de alto nível dos conceitos do Git é importante para o desenvolvimento de software moderno
    • Como o Git pode ser usado para desenvolver software (fluxos do Git)
  • Segundo artigo
    • Fluxo de trabalho do GitLab — um processo completo do ciclo de vida do software, desde a ideia até o feedback do usuário
    • Entrega Contínua — uma abordagem de engenharia de software em que as equipes produzem software em ciclos curtos, garantindo que o software possa ser lançado de forma confiável a qualquer momento. Seu objetivo é construir, testar e lançar software com mais rapidez e frequência
  • Terceiro artigo
    • Instalação e configuração do GitLab
    • Conexão dos seus ambientes ao GitLab
  • Quarto artigo
    • Configuração da entrega contínua
  • Quinto artigo
    • Contêineres e como (e por que) podem ser usados
  • Sexto artigo
    • Principais componentes para um pipeline de entrega contínua com contêineres
    • Como todos eles trabalham juntos
  • Sétimo artigo
    • Configuração da entrega contínua com contêineres
  • Oitavo artigo
    • Configuração da entrega contínua com o InterSystems Cloud Manager
  • Nono artigo
    • Arquitetura do contêiner
  • Décimo artigo
    • CI/CD para configuração e dados
  • Décimo primeiro artigo
    • Interoperabilidade e CI/CD

Nessa série de artigos, discuti abordagens gerais de entrega contínua. É um tema extremamente vasto e essa série de artigos precisa ser vista mais como uma coleção de receitas do que algo definitivo. Se você deseja automatizar o desenvolvimento, os testes e a entrega do seu aplicativo, a entrega contínua em geral e o GitLab em particular é o melhor caminho. A entrega contínua e os contêineres permitem que você personalize seu fluxo de trabalho conforme necessário.

0
0 175
Artigo Danusa Calixto · Fev. 23, 2023 11m read

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

No primeiro artigo, abordamos os fundamentos do Git, por que um entendimento de alto nível dos conceitos do Git é importante para o desenvolvimento de software moderno e como o Git pode ser usado para desenvolver software.

No segundo artigo, abordamos o fluxo de trabalho do GitLab: um processo inteiro do ciclo de vida do software e a entrega contínua.

No terceiro artigo, abordamos a instalação e configuração do GitLab e a conexão dos seus ambientes a ele

No quarto artigo, escrevemos uma configuração de CD.

No quinto artigo, falamos sobre contêineres e como (e por que) eles podem ser usados.

No sexto artigo, vamos discutir os principais componentes necessários para executar um pipeline de entrega contínua com contêineres e como eles trabalham juntos.

Neste artigo, criaremos a configuração de entrega contínua discutida nos artigos anteriores.

Fluxo de trabalho

Na nossa configuração de entrega contínua:

  • Enviamos código para o repositório do GitLab
  • Criamos a imagem docker
  • Testamos
  • Publicamos a imagem no nosso registro docker
  • Trocamos o contêiner antigo pela nova versão do registro

Ou em formato gráfico:

Vamos começar.

Criação

Primeiro, precisamos criar nossa imagem.

Nosso código seria, como sempre, armazenado no repositório, a configuração de CD em gitlab-ci.yml. No entanto, além disso (para aumentar a segurança), armazenaríamos vários arquivos específicos do servidor em um servidor de compilação.

GitLab.xml

Contém o código dos hooks de CD. Foi desenvolvido no artigo anterior e disponibilizado no GitHub. É uma pequena biblioteca para carregar código, executar vários hooks e testar código. Como alternativa preferencial, você pode usar submódulos git para incluir este projeto ou algo semelhante no seu repositório. Os submódulos são melhores porque é mais fácil mantê-los atualizados. Uma outra alternativa seria marcar as versões no GitLab e carregá-las com o comando ADD.

iris.key

Chave de licença. Como alternativa, ela pode ser baixada durante a compilação do contêiner em vez de armazenada em um servidor. É bastante arriscado armazenar no repositório.

pwd.txt

Arquivo contendo a senha padrão. Novamente, é bastante arriscado armazená-lo no repositório. Além disso, se você estiver hospedando um ambiente de produção em um servidor separado, ele poderá ter uma senha padrão diferente.

load_ci.script

O script inicial:

  • Ativa a autenticação do SO

  • Carrega GitLab.xml

  • Inicializa as configurações do utilitário GitLab

  • Carrega o código

    set sc = ##Class(Security.System).Get("SYSTEM",.Properties) write:('sc) $System.Status.GetErrorText(sc) set AutheEnabled = Properties("AutheEnabled") set AutheEnabled = $zb(+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

Observe que a primeira linha é deixada em branco de maneira intencional.

Como algumas configurações podem ser específicas do servidor, elas não são armazenadas no repositório, mas separadamente. Se o hook inicial for sempre o mesmo, você pode simplesmente armazená-lo no repositório.

gitlab-ci.yml

Agora, para a configuração da entrega contínua:

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 .

O que está acontecendo aqui?

Primeiro, como o docker build pode acessar apenas subdiretórios de um diretório de compilação base — na raiz do repositório do nosso caso, precisamos copiar nosso diretório "secreto" (aquele com GitLab.xmliris.key, pwd.txt e load_ci.script) no repositório clonado.

Em seguida, o primeiro acesso ao terminal requer um usuário/senha, então nós os adicionamos a load_ci.script (por isso a linha vazia no início de load_ci.script).

Por fim, criamos a imagem do docker e a marcamos adequadamente: docker.domain.com/test/docker:$CI_COMMIT_REF_NAME

onde $CI_COMMIT_REF_NAME é o nome de um branch atual. Observe que a primeira parte da tag de imagem deve ter o mesmo nome do nome do projeto no GitLab, para que possa ser vista na guia GitLab Registry (instruções sobre a marcação estão disponíveis na guia Registry).

Dockerfile

A criação da imagem docker é feita usando o Dockerfile:

FROM docker.intersystems.com/intersystems/iris:2018.1.1.611.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 &lt; $CI_DIR/load_ci.script \
 && iris stop $ISC_PACKAGE_INSTANCENAME quietly

Começamos a partir do contêiner básico iris.

Primeiro, copiamos nosso repositório (e diretório "secreto") dentro do contêiner.

Em seguida, copiamos a chave de licença e GitLab.xml para o diretório mgr.

Em seguida, alteramos a senha para o valor de pwd.txt. Observe que pwd.txt é excluído nessa operação.

Depois disso, a instância é iniciada e load_ci.script é executado.

Por fim, a instância iris é interrompida.

Veja o registro do job (parcial, os registros de carregamento/compilação foram ignorados):

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.611.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 &lt; $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

Estou usando o executor GitLab Shell, e não o executor Docker. O executor Docker é usado quando você precisa de algo de dentro da imagem, por exemplo, você está criando um aplicativo Android em um contêiner java e precisa apenas de um apk. No nosso caso, precisamos de um contêiner inteiro e, para isso, precisamos do executor Shell. Então, estamos executando comandos do Docker pelo executor GitLab Shell.

 

Executar

Temos nossa imagem, agora vamos executá-la.  No caso de ramificações de recursos, podemos simplesmente destruir o contêiner antigo e iniciar o novo. No caso do ambiente, podemos executar um container temporário e substituir o contêiner do ambiente caso os testes tenham êxito (isso fica como um exercício para o leitor).

Aqui está o script.

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

Esse script destrói o contêiner em execução no momento e é sempre bem-sucedido (por padrão, o docker falha se tentar parar/remover um contêiner inexistente).

Em seguida, iniciamos a nova imagem e a registramos como um ambiente. Contêiner Nginx faz proxy automático de solicitações usando a variável de ambiente VIRTUAL_HOST e a diretiva de exposição (para saber em qual porta fazer o proxy).

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

 

Testes

Vamos fazer alguns testes.

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

Publicar

Por fim, vamos publicar nossa imagem no registro

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

O usuário/código pode ser transmitido usando variáveis secretas do GitLab.

Agora, podemos ver a imagem no GitLab:

E outros desenvolvedores podem a extrair do registro. Na guia de ambientes, todos os ambientes estão disponíveis para a fácil navegação:

 

Conclusão

Nessa série de artigos, discuti abordagens gerais de entrega contínua. É um tema extremamente vasto e essa série de artigos precisa ser vista mais como uma coleção de receitas do que algo definitivo. Se você deseja automatizar o desenvolvimento, os testes e a entrega do seu aplicativo, a entrega contínua em geral e o GitLab em particular é o melhor caminho. A entrega contínua e os contêineres permitem que você personalize seu fluxo de trabalho conforme necessário.

Links

O que vem a seguir

É isso. Espero que eu tenha abordado os conceitos básicos da entrega contínua e dos contêineres.

Há vários tópicos sobre os quais não falei (talvez mais tarde), especialmente em relação a contêineres:

  • Os dados podem ser persistentes fora do contêiner. Veja a documentação relacionada.
  • Plataformas de orquestração como kubernetes
  • InterSystems Cloud Manager
  • Gerenciamento de ambiente - criando ambientes temporários para testes, removendo ambientes antigos após a mesclagem de ramificações de recursos
  • Docker compose para implantações de vários contêineres
  • Diminuindo o tamanho da imagem docker e os tempos de construção
  • ...
0
0 157
Artigo Danusa Calixto · Fev. 23, 2023 7m read

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
  • CI/CD do GitLab usando contêineres

No primeiro artigo, abordamos os fundamentos do Git, por que um entendimento de alto nível dos conceitos do Git é importante para o desenvolvimento de software moderno e como o Git pode ser usado para desenvolver software.

No segundo artigo, abordamos o fluxo de trabalho do GitLab: um processo inteiro do ciclo de vida do software e a entrega contínua.

No terceiro artigo, abordamos a instalação e configuração do GitLab e a conexão dos seus ambientes a ele

No quarto artigo, escrevemos uma configuração de CD.

No quinto artigo, falamos sobre contêineres e como (e por que) eles podem ser usados.

Neste artigo, vamos discutir os principais componentes necessários para executar um pipeline de entrega contínua com contêineres e como eles trabalham juntos.

A configuração deve ser assim:

Aqui podemos ver a separação de três etapas principais:

  • Criação
  • Envio
  • Execução

Criação

Nas partes anteriores, a criação era frequentemente incremental — calculamos a diferença entre o ambiente e a codebase atuais e modificamos nosso ambiente para corresponder à codebase. Com contêineres, cada build é completo. O resultado de um build é uma imagem que pode ser executada em qualquer lugar com dependências.

Envio

Depois que nossa imagem é criada e aprovada nos testes, ela é carregada no registro — servidor especializado para hospedar imagens docker. Então, é possível substituir a imagem anterior pela mesma tag. Por exemplo, devido ao novo commit para o master branch, nós construímos a nova imagem (project/version:master) e, se os testes funcionarem, podemos substituir a imagem no registro pela nova com a mesma tag, então todos que extraírem project/version:master obtêm uma nova versão.

Execução

Por fim, nossas imagens são implantadas. Uma solução de CI, como o GitLab, pode controlar isso ou um orquestrador especializado, mas o ponto é o mesmo: algumas imagens são executadas, verificadas periodicamente quanto à integridade e atualizadas se uma nova versão estiver disponível.

Confira o webinar docker explicando esses diferentes estágios.

Como alternativa, do ponto de vista do commit:

Na nossa configuração de entrega:

  • Enviamos código para o repositório do GitLab
  • Criamos a imagem docker
  • Testamos
  • Publicamos a imagem no nosso registro docker
  • Trocamos o contêiner antigo pela nova versão do registro

Para fazer isso, precisamos do seguinte:

  • Docker
  • Registro docker
  • Domínio registrado (opcional, mas recomendado)
  • Ferramentas de GUI (opcional)

 

Docker

Primeiro de tudo, precisamos executar o docker em algum lugar. Recomendo começar com um servidor mais convencional tipo o Linux, como Ubuntu, RHEL ou Suse. Não use distribuições voltadas para a nuvem, como CoreOS, RancherOS etc. — elas não são destinadas a iniciantes. Não se esqueça de trocar o driver de armazenamento para devicemapper

Em caso de grandes implantações, usar ferramentas de orquestração de contêineres, como Kubernetes, Rancher ou Swarm, pode automatizar a maioria das tarefas, mas não vamos discuti-las (pelo menos nesta parte).

 

Registro docker

Esse é o primeiro contêiner que precisamos executar e é um aplicativo do lado do servidor escalável e sem estado que armazena e permite distribuir imagens Docker.
Use o registro se quiser:

  •  controlar rigidamente onde as imagens estão sendo armazenadas
  •  possuir totalmente o pipeline de distribuição das imagens
  •  integrar o armazenamento e a distribuição de imagens firmemente no seu fluxo de trabalho de desenvolvimento interno

Veja a documentação do registro.

Conexão do registro e do GitLab

Observação: o GitLab inclui registro integrado. Você pode executá-lo em vez do registro externo. Leia os documentos do GitLab vinculados neste parágrafo.

Para conectar seu registro ao GitLab, você precisará executar seu registro com suporte HTTPS  — eu uso o Let's Encrypt para obter os certificados e segui este Gist para obter e transmitir os certificados a um contêiner. Depois de garantir a disponibilidade do registro em HTTPS (você pode verificar no navegador), siga estas instruções sobre como conectar o registro ao GitLab.  Essas instruções diferem com base no que você precisa e na sua instalação do GitLab. No meu caso, a configuração foi adicionar o certificado do registro e a chave (com o nome adequado e as permissões corretas) a /etc/gitlab/ssl e estas linhas a /etc/gitlab/gitlab.rb:

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

Depois de reconfigurar o GitLab, pude ver a nova guia do Registro, com informações sobre como marcar corretamente as imagens recém-criadas para que elas apareçam aqui.

 

Domínio

Na nossa configuração de Entrega Contínua, construímos automaticamente uma imagem por branch e, se a imagem passar nos testes, ela é publicada no registro e executada automaticamente. Para que nosso aplicativo fique disponível em todos os "estados" de maneira automática, por exemplo, podemos acessar:

  • Vários recursos de ramificações em <featureName>.docker.domain.com
  • Versão de teste em master.docker.domain.com
  • Versão pré-produção em preprod.docker.domain.com
  • Versão de produção em prod.docker.domain.com

Para isso, precisamos de um nome de domínio e adicionamos um registro DNS curinga que aponta *.docker.domain.com ao endereço IP de docker.domain.com. Outra opção seria usar portas diferentes.

Proxy Nginx

Como temos várias ramificações de recursos, precisamos redirecionar os subdomínios automaticamente para o contêiner correto. Para fazer isso, podemos usar o Nginx como proxy reverso. Veja aqui um guia.

Ferramentas de GUI

Para começar a trabalhar com contêineres, você pode usar a linha de comando ou uma das interfaces GUI. Há várias disponíveis, por exemplo:

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

Eles permitem que você crie contêineres e os gerencie a partir da GUI em vez da CLI. Veja como o Rancher aparenta:

 

Runner do GitLab

Como antes, para executar scripts em outros servidores, precisaremos instalar o runner do GitLab. Discuti isso no terceiro artigo.

Você precisará usar o executor Shell, e não o executor Docker. O executor Docker é usado quando você precisa de algo de dentro da imagem, por exemplo, você está criando um aplicativo Android em um contêiner java e precisa apenas de um apk. No nosso caso, precisamos de um contêiner inteiro e, para isso, precisamos do executor Shell.

 

Conclusão

É fácil começar a executar contêineres e há muitas ferramentas disponíveis.

A entrega contínua usando contêineres difere da configuração usual de várias maneiras:

  • As dependências são atendidas no momento da compilação e, após a criação da imagem, você não precisa pensar nas dependências.
  • Reprodutibilidade — é possível reproduzir facilmente qualquer ambiente existente ao executar o mesmo contêiner localmente.
  • Velocidade — como os contêineres não têm nada além do que você adicionou explicitamente, eles podem ser construídos com mais rapidez e, principalmente, eles são construídos uma vez e usados sempre que necessário.
  • Eficiência — como acima, os contêineres produzem menos sobrecarga do que, por exemplo, VMs.
  • Escalabilidade — com ferramentas de orquestração, você pode dimensionar automaticamente seu aplicativo para a carga de trabalho e consumir apenas os recursos necessários no momento.

O que vem a seguir

      <p>
        No próximo artigo, vamos falar sobre a criação da configuração de CD que usa o contêiner Docker do InterSystems IRIS.
      </p>
    </div>
  </div>
</div>
0
0 364
Artigo Danusa Calixto · Dez. 22, 2022 6m read

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?
  • CI/CD do GitLab usando contêineres

No primeiro artigo, abordamos os fundamentos do Git, por que um entendimento de alto nível dos conceitos do Git é importante para o desenvolvimento de software moderno e como o Git pode ser usado para desenvolver software.

No segundo artigo, abordamos o fluxo de trabalho do GitLab: um processo inteiro do ciclo de vida do software e a entrega contínua.

No terceiro artigo, abordamos a instalação e configuração do GitLab e a conexão dos seus ambientes a ele

No quarto artigo, escrevemos uma configuração de CD.

Neste artigo, falaremos sobre os contêineres e como (e por que) podem ser usados.

Este artigo presume a familiaridade com os conceitos de docker e contêiner. Confira estes artigos do @Luca Ravazzolo se quiser ler sobre contêineres e imagens.

Vantagens

Há muitas vantagens em usar contêineres:

  • Portabilidade
  • Eficiência
  • Isolamento
  • Leveza
  • Imutabilidade

Vamos falar sobre cada uma em detalhes.

Portabilidade

Um contêiner embrulha um aplicativo com tudo o que ele precisa para ser executado, como arquivos de configuração e dependências. Isso permite que você execute aplicativos de maneira fácil e confiável em diferentes ambientes, como seu desktop local, servidores físicos, servidores virtuais, testes, staging, ambientes de produção e nuvens públicas ou privadas.

Outro ponto da portabilidade é que, depois de criar sua imagem do Docker e verificar que ela é executada corretamente, ela pode ser executada em qualquer outro lugar que execute o docker, que atualmente são os servidores Windows, Linux e MacOS.

Eficiência

Você só precisa que o processo do aplicativo seja executado, e não todo o sistema, etc. E os contêineres oferecem exatamente isso: eles executam apenas os processos de que você precisa explicitamente e nada mais. Como os contêineres não exigem um sistema operacional separado, eles consomem menos recursos. Enquanto uma VM costuma ter vários gigabytes de tamanho, um contêiner geralmente tem apenas algumas centenas de megabytes, tornando possível executar muito mais contêineres do que VMs em um único servidor. Como os contêineres têm um nível de uso mais alto em relação ao hardware subjacente, você precisa de menos hardware, resultando em uma redução nos custos dos servidores bare metal, bem como dos centros de processamento de dados.

Isolamento

Os contêineres isolam seu aplicativo de todo o resto e, embora vários contêineres possam ser executados no mesmo servidor, eles podem ser completamente independentes uns dos outros. Qualquer interação entre contêineres deve ser explicitamente declarada como tal. Se um contêiner falhar, ele não afetará os outros e poderá ser reiniciado rapidamente. A segurança também se beneficia desse isolamento. Por exemplo, explorar a vulnerabilidade do servidor web em um servidor bare metal pode dar a um invasor acesso a todo o servidor, mas, no caso dos contêineres, o invasor só teria acesso ao contêiner do servidor web.

Leveza

Como os contêineres não exigem um sistema operacional separado, eles podem ser iniciados, interrompidos ou reinicializados em questão de segundos, o que acelera todos os pipelines de desenvolvimento relacionados e o tempo de produção. Você pode começar a trabalhar antes e não gastar nenhum tempo na configuração. 

Imutabilidade

A infraestrutura imutável é composta por componentes imutáveis que são substituídos a cada implantação, em vez de serem atualizados no local. Esses componentes são inicializados a partir de uma imagem comum que é criada uma vez por implantação e pode ser testada e validada. A imutabilidade reduz a inconsistência e permite a replicação e a movimentação entre diferentes estados do seu aplicativo com facilidade. Mais sobre a imutabilidade.

Novas possibilidades

Todas essas vantagens nos permitem gerenciar a infraestrutura e o fluxo de trabalho de maneiras totalmente novas.

Orquestração

Há um problema com ambientes bare metal ou VM, eles ganham individualidade, o que traz várias surpresas depois, geralmente desagradáveis. A resposta para isso é a infraestrutura como código, o gerenciamento da infraestrutura em um modelo descritivo, usando as mesmas versões que a equipe de DevOps usa para o código-fonte.

Com a infraestrutura como código, um comando de implantação sempre coloca o ambiente de destino na mesma configuração, não importa o estado inicial do ambiente. Isso é alcançado ao configurar automaticamente um destino existente ou descartar o destino existente e recriar um novo ambiente.

Assim, com a infraestrutura como código, as equipes fazem alterações na descrição do ambiente e na versão do modelo de configuração, que normalmente está em formatos de código bem documentados, como JSON. O pipeline de lançamento executa o modelo para configurar ambientes de destino. Se a equipe precisar fazer alterações, ela editará a fonte, e não o destino.

Tudo isso é possível e muito mais fácil de fazer com contêineres. Leva poucos segundos para desativar um contêiner e iniciar outro, enquanto o provisionamento de uma nova VM leva alguns minutos. E nem estou falando em reverter um servidor para um estado limpo.

Escalonamento

Do ponto anterior, você pode ter uma ideia de que a infraestrutura como código é estática por si só. Não é, pois as ferramentas de orquestração também podem fornecer escalonamento horizontal (provisionando mais do mesmo) com base na carga de trabalho atual. Você só deve executar o que é necessário no momento e escalonar seu aplicativo de acordo. Isso também pode reduzir custos.

Conclusão

Os contêineres podem otimizar seu pipeline de desenvolvimento. A eliminação de inconsistências entre ambientes permite testes e depurações mais fáceis. A orquestração permite que você crie aplicativos escalonáveis.  A implantação ou reversão para qualquer ponto do histórico imutável é possível e fácil.

As organizações querem trabalhar em um nível mais alto, onde todos os problemas listados acima já estejam resolvidos e onde encontramos agendadores e orquestradores lidando com mais coisas de maneira automatizada.

O que vem a seguir

      <p>
        No próximo artigo, vamos falar sobre o provisionamento com contêineres e a criação da configuração de CD que usa o contêiner Docker do InterSystems IRIS.
      </p>
    </div>
  </div>
</div>
0
0 88
Artigo Danusa Calixto · Dez. 22, 2022 10m read

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

No primeiro artigo, abordamos os fundamentos do Git, por que um entendimento de alto nível dos conceitos do Git é importante para o desenvolvimento de software moderno e como o Git pode ser usado para desenvolver software.

No segundo artigo, abordamos o fluxo de trabalho do GitLab: um processo inteiro do ciclo de vida do software e a entrega contínua.

No terceiro artigo, abordamos a instalação e configuração do GitLab e a conexão dos seus ambientes a ele

Neste artigo, finalmente, vamos escrever uma configuração de CD.

Plano

Ambientes

Em primeiro lugar, precisamos de vários ambientes e branches que correspondam a eles:

EnvironmentBranchDeliveryWho can commitWho can merge
TestmasterAutomaticDevelopers  OwnersDevelopers  Owners
PreprodpreprodAutomaticNo oneOwners
ProdprodSemiautomatic (press button to deliver)No one

Owners

Ciclo de desenvolvimento

E, como exemplo, desenvolveremos um novo recurso usando o fluxo do GitLab e o entregaremos usando a CD do GitLab.

  1. O recurso é desenvolvido em um branch de recursos.
  2. O branch de recurso é revisado e mesclado no master branch.
  3. Depois de um tempo (vários recursos mesclados), o master é mesclado com o preprod
  4. Depois de um tempo (teste do usuário, etc.), o preprod é mesclado com o prod

Veja como isso ficaria (marquei as partes que precisamos desenvolver para o CD em itálico):

  1. Desenvolvimento e teste
    • O desenvolvedor envia o código para o novo recurso em um branch de recursos separado
    • Depois que o recurso se torna estável, o desenvolvedor mescla nosso branch de recursos no master branch
    • O código do branch master é entregue ao ambiente de teste, onde é carregado e testado
  2. Entrega para o ambiente de pré-produção
    • O desenvolvedor cria a solicitação de mesclagem do branch master para o branch de pré-produção
    • Depois de algum tempo, o proprietário do repositório aprova a solicitação de mesclagem
    • O código do branch de pré-produção é entregue ao ambiente de pré-produção
  3. Entrega para o ambiente de produção
    • O desenvolvedor cria a solicitação de mesclagem do branch de pré-produção para o branch de produção
    • Depois de algum tempo, o proprietário do repositório aprova a solicitação de mesclagem
    • O proprietário do repositório aperta o botão "Implantar"
    • O código do branch de produção é entregue ao ambiente de produção

Ou o mesmo, mas em formato de gráfico:

Aplicativo

Nosso aplicativo consiste em duas partes:

  • API REST desenvolvida na plataforma InterSystems
  • Web application de JavaScript cliente

Estágios

Com o plano acima, podemos determinar as etapas que precisamos definir na nossa configuração de entrega contínua:

  • Carregamento — para importar o código do lado do servidor para o InterSystems IRIS
  • Teste — para testar o código do servidor e cliente
  • Pacote — para criar o código do cliente
  • Implantação — para "publicar" o código do cliente usando o servidor web

Veja como isso fica no arquivo de configuração gitlab-ci.yml:

stages:
  - load
  - test
  - package
  - deploy

Scripts

Carregamento

Em seguida, vamos definir os scripts. Documentos de scripts. Primeiro, vamos definir um script load server que carrega o código do lado do servidor:

load server:
  environment:
    name: test
    url: http://test.hostname.com
  only:
    - master
  tags:
    - test
  stage: load
  script: csession IRIS "##class(isc.git.GitLab).load()"

O que acontece aqui?

  • load server é o nome de um script
  • em seguida, descrevemos o ambiente em que esse script é executado
  • only: master — informa ao GitLab que esse script só deve ser executado quando houver um commit para o master branch
  • tags: test especifica que esse script só deve ser executado em um runner com a tag test
  • stage especifica o estágio para um script
  • script define o código para executar. No nosso caso, chamamos o classmethod load da classe isc.git.GitLab

Observação importante

Para InterSystems IRIS, troque csession por iris session.

Para Windows, use: irisdb -s ../mgr -U TEST "##class(isc.git.GitLab).load()

Agora, vamos escrever a classe isc.git.GitLab correspondente. Todos os pontos de entrada nessa classe ficam desta forma:

ClassMethod method()
{
    try {
        // code
        halt
    } catch ex {
        write !,$System.Status.GetErrorText(ex.AsStatus()),!
        do $system.Process.Terminate(, 1)
    }
}

Observe que esse método pode terminar de duas maneiras:

  • interrompendo o processo atual — que é registrado no GitLab como uma conclusão bem-sucedida
  • chamando $system.Process.Terminate — que termina o processo de maneira anormal e o GitLab registra isso como um erro

Dito isso, aqui está nosso código de carregamento:

/// Do a full load
/// do ##class(isc.git.GitLab).load()
ClassMethod load()
{
    try {
        set dir = ..getDir()
        do ..log("Importing dir " _ dir)
        do $system.OBJ.ImportDir(dir, ..getExtWildcard(), "c", .errors, 1)
        throw:$get(errors,0)'=0 ##class(%Exception.General).%New("Load error")

        halt
    } catch ex {
        write !,$System.Status.GetErrorText(ex.AsStatus()),!
        do $system.Process.Terminate(, 1)
    }
}

Dois métodos de utilitários são chamados:

  • getExtWildcard — para obter uma lista das extensões de arquivo relevantes
  • getDir — para obter o diretório do repositório

Como podemos obter o diretório?

Quando o GitLab executa um script, primeiro, ele especifica várias variáveis de ambiente. Uma delas é a CI_PROJECT_DIR — o caminho completo onde o repositório é clonado e onde o job é executado. Ele pode ser obtido facilmente no nosso método getDir :

ClassMethod getDir() [ CodeMode = expression ]
{
##class(%File).NormalizeDirectory($system.Util.GetEnviron("CI_PROJECT_DIR"))
}

####Testes

Aqui está o script de teste:

load test:
  environment:
    name: test
    url: http://test.hostname.com
  only:
    - master
  tags:
    - test
  stage: test
  script: csession IRIS "##class(isc.git.GitLab).test()"
  artifacts:
    paths:
      - tests.html

O que mudou? O nome e o código do script, é claro, mas o artefato também foi adicionado. Um artefato é uma lista de arquivos e diretórios que são anexados a um job depois que ele é concluído com sucesso. No nosso caso, depois que os testes forem concluídos, podemos gerar a página HTML redirecionando para os resultados dos testes e disponibilizá-la a partir do GitLab. 

Observe que há bastante copiar e colar do estágio de carregamento — o ambiente é o mesmo, partes do script, como ambientes, podem ser rotuladas separadamente e anexadas a um script. Vamos definir o ambiente de teste:

.env_test: &env_test
  environment:
    name: test
    url: http://test.hostname.com
  only:
    - master
  tags:
    - test

Agora, nosso script de teste fica assim:

load test:
  <<: *env_test
  script: csession IRIS "##class(isc.git.GitLab).test()"
  artifacts:
    paths:
      - tests.html

Em seguida, vamos executar os testes usando o framework UnitTest.

/// do ##class(isc.git.GitLab).test()
ClassMethod test()
{
    try {
        set tests = ##class(isc.git.Settings).getSetting("tests")
        if (tests'="") {
            set dir = ..getDir()
            set ^UnitTestRoot = dir

            $$$TOE(sc, ##class(%UnitTest.Manager).RunTest(tests, "/nodelete"))
            $$$TOE(sc, ..writeTestHTML())
            throw:'..isLastTestOk() ##class(%Exception.General).%New("Tests error")
        }
        halt
    } catch ex {
        do ..logException(ex)
        do $system.Process.Terminate(, 1)
    }
}

A definição do teste, nesse caso, é um caminho relativo à raiz do repositório onde os testes de unidade são armazenados. Se estiver vazio, pulamos testes. O método writeTestHTML é usado para gerar o html com um redirecionamento para os resultados dos testes:

ClassMethod writeTestHTML()
{
    set text = ##class(%Dictionary.XDataDefinition).IDKEYOpen($classname(), "html").Data.Read()
    set text = $replace(text, "!!!", ..getURL())
    
    set file = ##class(%Stream.FileCharacter).%New()
    set name = ..getDir() _  "tests.html"
    do file.LinkToFile(name)
    do file.Write(text)
    quit file.%Save()
}

ClassMethod getURL()
{
    set url = ##class(isc.git.Settings).getSetting("url")
    set url = url _ $system.CSP.GetDefaultApp("%SYS")
    set url = url_"/%25UnitTest.Portal.Indices.cls?Index="_ $g(^UnitTest.Result, 1) _ "&$NAMESPACE=" _ $zconvert($namespace,"O","URL")
    quit url
}

ClassMethod isLastTestOk() As %Boolean
{
    set in = ##class(%UnitTest.Result.TestInstance).%OpenId(^UnitTest.Result)
    for i=1:1:in.TestSuites.Count() {
        #dim suite As %UnitTest.Result.TestSuite
        set suite = in.TestSuites.GetAt(i)
        return:suite.Status=0 $$$NO
    }
    quit $$$YES
}

XData html
{
<html lang="en-US">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="refresh" content="0; url=!!!"/>
<script type="text/javascript">
window.location.href = "!!!"
</script>
</head>
<body>
If you are not redirected automatically, follow this <a href='!!!'>link to tests</a>.
</body>
</html>
}

Pacote

Nosso cliente é uma página HTML simples:

<html>
<head>
<script type="text/javascript">
function initializePage() {
  var xhr = new XMLHttpRequest();
  var url = "${CI_ENVIRONMENT_URL}:57772/MyApp/version";
  xhr.open("GET", url, true);
  xhr.send();
  xhr.onloadend = function (data) {
    document.getElementById("version").innerHTML = "Version: " + this.response;
  };
  
  var xhr = new XMLHttpRequest();
  var url = "${CI_ENVIRONMENT_URL}:57772/MyApp/author";
  xhr.open("GET", url, true);
  xhr.send();
  xhr.onloadend = function (data) {
    document.getElementById("author").innerHTML = "Author: " + this.response;
  };
}
</script>
</head>
<body  onload="initializePage()">
<div id = "version"></div>
<div id = "author"></div>
</body>
</html>

E, para criá-la, precisamos substituir ${CI_ENVIRONMENT_URL} pelo seu valor. Claro, um aplicativo real provavelmente exigiria npm, mas esse é apenas um exemplo. Aqui está o script:

package client:
  <<: *env_test
  stage: package
  script: envsubst < client/index.html > index.html
  artifacts:
    paths:
      - index.html

Implantação

Por fim, implantamos nosso cliente ao copiar index.html para o diretório raiz do servidor web.

deploy client:
  <<: *env_test
  stage: deploy
  script: cp -f index.html /var/www/html/index.html

É isso!

Vários ambientes

O que fazer se você precisar executar o mesmo script (semelhante) em vários ambientes? Partes do script também podem ser rótulos, então aqui está uma configuração de exemplo que carrega o código em ambientes de teste e pré-produção:

stages:
  - load
  - test

.env_test: &env_test
  environment:
    name: test
    url: http://test.hostname.com
  only:
    - master
  tags:
    - test
    
.env_preprod: &env_preprod
  environment:
    name: preprod
    url: http://preprod.hostname.com
  only:
    - preprod
  tags:
    - preprod

.script_load: &script_load
  stage: load
  script: csession IRIS "##class(isc.git.GitLab).loadDiff()"

load test:
  <<: *env_test
  <<: *script_load

load preprod:
  <<: *env_preprod
  <<: *script_load

Assim, podemos fugir de copiar e colar o código.

Veja a configuração de CD completa aqui. Ela segue o plano original de mover código entre os ambientes de teste, pré-produção e produção.

Conclusão

A entrega contínua pode ser configurada para automatizar qualquer fluxo de trabalho de desenvolvimento necessário.

Links

O que vem a seguir

No próximo artigo, vamos criar a configuração de CD que usa o contêiner Docker do InterSystems IRIS.

0
0 101
Artigo Danusa Calixto · Dez. 15, 2022 5m read

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

No primeiro artigo, abordamos os fundamentos do Git, por que um entendimento de alto nível dos conceitos do Git é importante para o desenvolvimento de software moderno e como o Git pode ser usado para desenvolver software.

No segundo artigo, abordamos o fluxo de trabalho do GitLab: um processo inteiro do ciclo de vida do software e a entrega contínua.

Neste artigo, vamos discutir:

  • Instalação e configuração do GitLab
  • Conexão dos seus ambientes ao GitLab

Instalação do GitLab

Vamos instalar o GitLab no local. Há várias maneiras de instalar o GitLab — da fonte, pacote, em um contêiner. Não descreverei todos os passos aqui, há um guia para isso. Ainda assim, algumas observações.

Pré-requisitos:

  • Servidor separado — como é um web application e um recurso bastante intensivo, é melhor executar em um servidor separado
  • Linux
  • (Opcional, mas altamente recomendável) Domínio — necessário para executar páginas e proteger a configuração inteira

Configuração

Primeiro de tudo, você provavelmente precisa enviar e-mails com notificações.

Em seguida, recomendo instalar Páginas. Como discutido no artigo anterior — artefatos do script podem ser enviados para o GitLab. O usuário pode fazer o download deles, mas é útil poder abri-los diretamente no navegador e, para isso, precisamos de páginas.

Por que você precisa de páginas:

Como as páginas html podem ter um redirecionamento onload, elas podem ser usadas para enviar o usuário para onde precisamos. Por exemplo, veja este código que gera uma página html que envia um usuário para o último teste de unidade executado (no momento da geração do html):

ClassMethod writeTestHTML()
{
  set text = ##class(%Dictionary.XDataDefinition).IDKEYOpen($classname(), "html").Data.Read()
  set text = $replace(text, "!!!", ..getURL())
  
  set file = ##class(%Stream.FileCharacter).%New()
  set name = "tests.html"
  do file.LinkToFile(name)
  do file.Write(text)
  quit file.%Save()
}

ClassMethod getURL()
{
  set url = "http://host:57772"
  set url = url _ $system.CSP.GetDefaultApp("%SYS")
  set url = url_"/%25UnitTest.Portal.Indices.cls?Index="_ $g(^UnitTest.Result, 1) _ "&$NAMESPACE=" _ $zconvert($namespace,"O","URL")
  quit url
}

XData html
{

  
  
    If you are not redirected automatically, follow this link to tests.
  

}

Encontrei um bug usando as páginas (erro 502 ao procurar artefatos), veja aqui a correção.

 

Conexão dos seus ambientes ao GitLab

Para executar scripts de CD, você precisa de ambientes, servidores configurados para executar seu aplicativo. Presumindo que você tem um servidor Linux com o produto InterSystems instalado (digamos InterSystems IRIS, mas funciona também com o Caché e Ensemble), estas etapas conectam o ambiente ao GitLab:

  1. Instalar o runner do GitLab
  2. Registrar o runner com o GitLab
  3. Permitir que o runner chame o InterSystems IRIS

Observação importante sobre a instalação do runner GitLab, NÃO clone servidores após instalar o runner do GitLab.  Os resultados são imprevisíveis e muito indesejados.

Registrar o runner com o GitLab

Após executar o inicial:

sudo gitlab-runner register

você verá vários prompts e, embora a maioria das etapas seja bastante direta, várias não são:

Insira o token gitlab-ci para este runner

Há vários tokens disponíveis:

  • Um para o sistema inteiro (disponível nas configurações de administração)
  • Um para cada projeto (disponível nas configurações do projeto)

Conforme você conecta um runner para executar a CD para um projeto específico, você precisa especificar um token para este projeto.

Insira as tags gitlab-ci para este runner (separadas por vírgulas):

Na configuração de CD, você pode filtrar quais scripts vão ser executados em quais tags. Então, no caso mais simples, especifique uma tag, que seria o nome do ambiente.

Insira o executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell:
docker

Se você estiver usando o servidor habitual sem docker, escolha shell.  O Docker será discutido nas partes posteriores.

Permitir que o runner chame o InterSystems IRIS

Depois de conectar o runner ao GitLab, precisamos permitir que ele interaja com o InterSystems IRIS, para isso:

  1. O usuário gitlab-runner precisa conseguir chamar csession. Para fazer isso, adicione-o ao grupo cacheusr: 
    • usermod -a -G cacheusr gitlab-runner
  2. Crie o usuário gitlab-runner no InterSystems IRIS e dê a ele funções para realizar tarefas de CD (escreva para DB, etc.)
  3. Permitir a autenticação no nível do SO

Para 2 e 3, outras abordagens podem ser usadas, como a transmissão de usuário/código, mas acho que a autenticação de SO é preferível. 

Conclusão

Nesta parte:

  • GitLab instalado
  • Ambientes conectados ao GitLab

O que vem a seguir

Na próxima parte, escrevemos nossa configuração de entrega contínua.

0
0 156
Artigo Danusa Calixto · Nov. 9, 2022 10m read

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

No artigo anterior, abordamos os fundamentos do Git, por que um entendimento de alto nível dos conceitos do Git é importante para o desenvolvimento de software moderno e como o Git pode ser usado para desenvolver software. Ainda assim, nosso foco foi na parte da implementação do desenvolvimento de software, mas esta parte apresenta:

  • Fluxo de trabalho do GitLab — um processo completo do ciclo de vida do software, desde a ideia até o feedback do usuário
  • Entrega Contínua — uma abordagem de engenharia de software em que as equipes produzem software em ciclos curtos, garantindo que o software possa ser lançado de forma confiável a qualquer momento. Seu objetivo é construir, testar e lançar software com mais rapidez e frequência.

Fluxo de trabalho do GitLab

O fluxo de trabalho do GitLab é uma sequência lógica de possíveis ações a serem tomadas durante todo o ciclo de vida do processo de desenvolvimento de software.

O fluxo de trabalho do GitLab leva em consideração o fluxo do GitLab, que discutimos em um artigo anterior. Veja como funciona:

  1. Ideia: todas as novas propostas começam com uma ideia.
  2. Problema: a maneira mais eficaz de discutir uma ideia é criar um problema para ela. Sua equipe e seus colaboradores podem ajudar você a aprimorar e melhorar a ideia no rastreador de problemas.
  3. Plano: quando a discussão chega a um acordo, é hora de programar. Porém, primeiro, precisamos priorizar e organizar nosso fluxo de trabalho ao atribuir problemas a marcos e quadro de problemas.
  4. Código: agora estamos prontos para escrever nosso código, já que está tudo organizado.
  5. Commit: depois de satisfeitos com o rascunho, podemos enviar nosso código para um feature-branch com controle de versão. O fluxo do GitLab foi explicado em detalhes no artigo anterior.
  6. Teste: executamos nossos scripts usando o CI GitLab, para construir e testar nosso aplicativo.
  7. Revisão: assim que nosso script funcionar e nossos testes e compilações forem bem-sucedidos, estamos prontos para que nosso código seja revisado e aprovado.
  8. Staging: agora é hora de implantar nosso código em um ambiente de staging para verificar se tudo funciona como esperado ou se ainda precisamos de ajustes.
  9. Produção: quando tudo estiver funcionando como deve, é hora de implantar no nosso ambiente de produção!
  10. Feedback: agora é hora de olhar para trás e verificar qual etapa do nosso trabalho precisa ser melhorada.

Novamente, o processo em si não é novo (ou exclusivo do GitLab) e pode ser alcançado com outras ferramentas da sua escolha.

Vamos discutir várias dessas etapas e o que elas implicam. Também há documentação disponível.

Problema e plano

As etapas iniciais do fluxo de trabalho do GitLab são centradas em um problema: um recurso, bug ou outro tipo de trabalho semanticamente separado.

O problema tem várias finalidades, como:

  • Gerenciamento: um problema tem data de vencimento, pessoa designada, tempo gasto e estimativas, etc. para ajudar a monitorar a resolução do problema.
  • Administrativo: um problema faz parte de um marco, quadro kanban, que nos permite rastrear nosso software à medida que ele avança de versão para versão.
  • Desenvolvimento: um problema tem uma discussão e commits associados a ele.

A etapa de planejamento nos permite agrupar os problemas por prioridade, marco, quadro kanban e ter uma visão geral disso.

O desenvolvimento foi discutido na parte anterior, basta seguir qualquer fluxo git que quiser. Depois que desenvolvemos nosso novo recurso e o mesclamos no master: o que vem depois?

Entrega contínua

A entrega contínua é uma abordagem de engenharia de software em que as equipes produzem software em ciclos curtos, garantindo que o software possa ser lançado de forma confiável a qualquer momento. Seu objetivo é construir, testar e lançar software com mais rapidez e frequência. A abordagem ajuda a reduzir o custo, o tempo e o risco da entrega de alterações, permitindo mais atualizações incrementais para aplicativos em produção. Um processo de implantação simples e repetível é importante para a entrega contínua.

Entrega contínua no GitLab

No GitLab, a configuração da entrega contínua é definida por repositório como um arquivo de configuração YAML.

  • A configuração de entrega contínua é uma série de estágios consecutivos.
  • Cada estágio tem um ou vários scripts que são executados em paralelo.

O script define uma ação e quais condições devem ser atendidas para executá-la:

  • O que fazer (executar o comando do SO, executar um contêiner)?
  • Quando executar o script:
    • Quais são os gatilhos (commit de um branch específico)?
    • Nós o executamos se os estágios anteriores falharam?
  • Executar manualmente ou automaticamente?
  • Em que ambiente executar o script?
  • Quais artefatos salvar após a execução dos scripts (eles são carregados do ambiente para o GitLab para facilitar o acesso)?

Ambiente - é um servidor ou contêiner configurado no qual você pode executar seus scripts.

Runners executam scripts em ambientes específicos. Eles são conectados ao GitLab e executam scripts conforme necessário.

O runner pode ser implantado em um servidor, contêiner ou até mesmo na sua máquina local.

Como acontece a entrega contínua?

  1. O novo commit é enviado para o repositório.
  2. O GitLab verifica a configuração de entrega contínua.
  3. A configuração de entrega contínua contém todos os scripts possíveis para todos os casos, para que sejam filtrados para um conjunto de scripts que devem ser executados para esse commit específico (por exemplo, um commit para o branch master aciona apenas ações relacionadas a um branch master). Esse conjunto é chamado de pipeline.
  4. O pipeline é executado em um ambiente de destino e os resultados da execução são salvos e exibidos no GitLab.

Por exemplo, aqui está um pipeline executado após um commit em um branch master:

Ele consiste em quatro etapas, executadas consecutivamente

  1. O estágio de carregamento carrega o código em um servidor
  2. O estágio de teste executa testes de unidade
  3. O estágio de pacote consiste em dois scripts executados em paralelo:
    • Compilação cliente
    • Código de exportação do servidor (principalmente para fins informativos)
  4. O estágio de implantação move o cliente criado para o diretório do servidor web.

Como podemos ver, todos os scripts foram executados com sucesso. Se um dos scripts falhar, por padrão, os scripts posteriores não são executados (mas podemos alterar esse comportamento):

Se abrirmos o script, podemos ver o log e determinar por que ele falhou:

Running with gitlab-runner 10.4.0 (857480b6)
 on test runner (ab34a8c5)
Using Shell executor...
Running on gitlab-test...
&lt;span class="term-fg-l-green term-bold">Fetching changes...&lt;/span>
Removing diff.xml
Removing full.xml
Removing index.html
Removing tests.html
HEAD is now at a5bf3e8 Merge branch '4-versiya-1-0' into 'master'
From http://gitlab.eduard.win/test/testProject
 * [new branch] 5-versiya-1-1 -> origin/5-versiya-1-1
 a5bf3e8..442a4db master -> origin/master
 d28295a..42a10aa preprod -> origin/preprod
 3ac4b21..7edf7f4 prod -> origin/prod
&lt;span class="term-fg-l-green term-bold">Checking out 442a4db1 as master...&lt;/span>
&lt;span class="term-fg-l-green term-bold">Skipping Git submodules setup&lt;/span>
&lt;span class="term-fg-l-green term-bold">$ csession ensemble "##class(isc.git.GitLab).loadDiff()"&lt;/span>

[2018-03-06 13:58:19.188] Importing dir /home/gitlab-runner/builds/ab34a8c5/0/test/testProject/

[2018-03-06 13:58:19.188] Loading diff between a5bf3e8596d842c5cc3da7819409ed81e62c31e3 and 442a4db170aa58f2129e5889a4bb79261aa0cad0

[2018-03-06 13:58:19.192] Variable modified
var=$lb("MyApp/Info.cls")

Load started on 03/06/2018 13:58:19
Loading file /home/gitlab-runner/builds/ab34a8c5/0/test/testProject/MyApp/Info.cls as udl
Load finished successfully.

[2018-03-06 13:58:19.241] Variable items
var="MyApp.Info.cls"
var("MyApp.Info.cls")=""

Compilation started on 03/06/2018 13:58:19 with qualifiers 'cuk /checkuptodate=expandedonly'
Compiling class MyApp.Info
Compiling routine MyApp.Info.1
ERROR: MyApp.Info.cls(version+2) #1003: Expected space : '}' : Offset:14 [zversion+1^MyApp.Info.1]
 TEXT:  quit, "1.0" }
Detected 1 errors during compilation in 0.010s.

[2018-03-06 13:58:19.252] ERROR #5475: Error compiling routine: MyApp.Info.1. Errors: ERROR: MyApp.Info.cls(version+2) #1003: Expected space : '}' : Offset:14 [zversion+1^MyApp.Info.1]
 > ERROR #5030: An error occurred while compiling class 'MyApp.Info'
&lt;span class="term-fg-l-red term-bold">ERROR: Job failed: exit status 1
&lt;/span>

O erro de compilação causou a falha do nosso script.

Conclusão

  • O GitLab é compatível com todos os principais estágios de desenvolvimento de software.
  • A entrega contínua pode ajudar você a automatizar tarefas de construção, teste e implantação do seu software.

O que vem a seguir?

No próximo artigo, vamos:

  • Instalar o GitLab.
  • Conectá-lo a diversos ambientes com os produtos InterSystems instalados.
  • Escrever uma configuração de entrega contínua.

Vamos discutir como a entrega contínua deve funcionar.

Em primeiro lugar, precisamos de vários ambientes e branches que correspondam a eles. O código entra nesse branch e é entregue ao ambiente de destino:

AmbienteBranchEntregaQuem pode fazer enviosQuem pode mesclar
TestemasterAutomáticoDesenvolvedores  ProprietáriosDesenvolvedores  Proprietários
PreprodpreprodAutomáticoNinguémProprietários
ProdprodSemiautomático (pressionar botão para entregar)NinguémProprietários

E, como exemplo, desenvolveremos um novo recurso usando o fluxo do GitLab e o entregaremos usando a CD do GitLab.

  1. O recurso é desenvolvido em um branch de recursos.
  2. O branch de recurso é revisado e mesclado no master branch.
  3. Depois de um tempo (vários recursos mesclados), o master é mesclado com o preprod
  4. Depois de um tempo (teste do usuário, etc.), o preprod é mesclado com o prod

Veja como ficaria:

  1. Desenvolvimento e teste
    • O desenvolvedor envia o código para o novo recurso em um branch de recursos separado
    • Depois que o recurso se torna estável, o desenvolvedor mescla nosso branch de recursos no master branch
    • O código do branch master é entregue ao ambiente de teste, onde é carregado e testado
  2. Entrega para o ambiente de pré-produção
    • O desenvolvedor cria a solicitação de mesclagem do branch master para o branch de pré-produção
    • Depois de algum tempo, o proprietário do repositório aprova a solicitação de mesclagem
    • O código do branch de pré-produção é entregue ao ambiente de pré-produção
  3. Entrega para o ambiente de produção
    • O desenvolvedor cria a solicitação de mesclagem do branch de pré-produção para o branch de produção
    • Depois de algum tempo, o proprietário do repositório aprova a solicitação de mesclagem
    • O proprietário do repositório aperta o botão "Implantar"
    • O código do branch de produção é entregue ao ambiente de produção

Ou o mesmo, mas em formato gráfico:

 

0
0 302
Artigo Danusa Calixto · Out. 10, 2022 8m read

No vasto e variado mercado de banco de dados SQL, o InterSystems IRIS se destaca como uma plataforma que vai muito além do SQL, oferecendo uma experiência multimodelo otimizada e a compatibilidade com um rico conjunto de paradigmas de desenvolvimento. Em especial, o mecanismo Object-Relational avançado ajudou as organizações a usar a abordagem de desenvolvimento mais adequada para cada faceta das cargas de trabalho com muitos dados, por exemplo, fazendo a ingestão de dados por objetos e consultando-os simultaneamente por SQL. As Classes Persistentes correspondem às tabelas SQL, suas propriedades às colunas da tabela, e a lógica de negócios é facilmente acessada usando as Funções Definidas pelo Usuário ou os Procedimentos Armazenados. Neste artigo, focaremos um pouco na mágica logo abaixo da superfície e discutiremos como isso pode afetar suas práticas de desenvolvimento e implantação. Essa é uma área do produto em que temos planos de evoluir e melhorar, portanto, não hesite em compartilhar suas opiniões e experiências usando a seção de comentários abaixo.

Salvando a definição de armazenamento

Escrever uma nova lógica de negócios é fácil e, supondo que você tenha APIs e especificações bem definidas, adaptá-la ou ampliá-la também costuma ser. No entanto, quando não é apenas lógica de negócios, mas também envolve dados persistentes, qualquer coisa que você alterar na versão inicial precisará ser capaz de lidar com os dados que foram ingeridos por essa versão anterior.

No InterSystems IRIS, os dados e código coexistem em um único mecanismo de alto desempenho, sem a meia dúzia de camadas de abstração que você vê em outras estruturas de programação 3GL ou 4GL. Isso significa que há apenas um mapeamento muito fino e transparente para traduzir as propriedades da sua classe para posições $list em um nó global por linha de dados ao usar o armazenamento padrão. Se você adicionar ou remover propriedades, não quer que os dados de uma propriedade removida apareçam em uma nova propriedade. É desse mapeamento das propriedades da sua classe que a Definição de Armazenamento cuida, um bloco de XML um pouco enigmático que você deve ter percebido na parte inferior da definição da sua classe. Na primeira vez que você compila uma classe, uma nova Definição de Armazenamento é gerada com base nas propriedades e nos parâmetros da classe. Quando você faz alterações na definição da classe, no momento da recompilação, essas alterações são reconciliadas com a Definição de Armazenamento existente e alteradas para manter a compatibilidade com os dados existentes. Assim, enquanto você se esforça para refatorar as classes, a Definição de Armazenamento considera cuidadosamente sua criatividade anterior e garante que os dados antigos e novos permaneçam acessíveis. Chamamos isso de evolução de esquema.

Na maioria dos outros bancos de dados SQL, o armazenamento físico das tabelas é muito mais opaco, se visível, e as alterações só podem ser feitas por declarações ALTER TABLE. Esses são comandos de DDL (linguagem de definição de dados) padrão, mas normalmente são muito menos expressivos do que é possível alcançar ao modificar uma definição de classe e um código de procedimento diretamente no IRIS. 

Na InterSystems, nos esforçamos para oferecer aos desenvolvedores do IRIS a capacidade de separar de forma limpa o código e os dados, pois isso é crucial para garantir o empacotamento e a implantação suave dos aplicativos. A Definição de Armazenamento desempenha uma função única nisso, pois captura como um mapeia para o outro. Por isso, vale a pena examinar mais a fundo o contexto de práticas gerais de desenvolvimento e pipelines de CI/CD em particular.

Exportando para UDL

No século atual, o gerenciamento de código-fonte é baseado em arquivos, então vamos primeiro analisar o formato principal de exportação de arquivos do IRIS. A Linguagem de Descrição Universal (Universal Description Language ou UDL, na sigla em inglês) pretende, como o nome sugere, ser um formato de arquivo universal para todo e qualquer código que você escrever no InterSystems IRIS. É o formato de exportação padrão ao trabalhar com o plug-in VS Code ObjectScript e leva a arquivos fáceis de ler que parecem quase iguais ao que você veria em um IDE, com um arquivo .cls individual para cada classe (tabela) no seu aplicativo. Você pode usar $SYSTEM.OBJ.Export() para criar arquivos UDL explicitamente ou apenas aproveitar a integração do VS Code.

Da época do Studio, talvez você se lembre de um formato XML que capturava as mesmas informações do UDL e permitia agrupar várias classes em uma única exportação. Embora essa última parte seja conveniente em alguns cenários, é muito menos prático ler e rastrear diferenças entre versões, então vamos ignorá-la por enquanto.

Como a UDL é destinada a capturar tudo o que o IRIS pode expressar sobre uma classe, ela incluirá todos os elementos de uma definição de classe, incluindo a Definição de Armazenamento completa. Ao importar uma definição de classe que já inclui uma Definição de Armazenamento, o IRIS verificará se essa Definição de Armazenamento abrange todas as propriedades e índices da classe e, se for o caso, usará no estado em que está e substituirá a Definição anterior para essa classe. Isso torna a UDL um formato prático para o gerenciamento de versões das classes e a Definição de Armazenamento, pois preserva essa compatibilidade para dados ingeridos por versões anteriores da classe, onde quer que você implante. 

Se você é um desenvolvedor hardcore, talvez se pergunte se essas Definições de Armazenamento continuam crescendo e se essa "bagagem" precisa ser transportada indefinidamente. O objetivo das Definições de Armazenamento é preservar a compatibilidade com dados pré-existentes, portanto, se você sabe que não há nada disso e quiser se livrar de uma genealogia longa, pode "redefinir" a Definição de Armazenamento ao removê-la da definição da classe e gerar outra com o compilador da classe. Por exemplo, você pode usar isso para aproveitar novas práticas recomendadas, como o uso de Conjuntos de Extensão, que implementam nomes globais com hash e separam cada índice em um próprio global, melhorando as eficiências de baixo nível. Para a compatibilidade com versões anteriores nos aplicativos dos clientes, não podemos mudar universalmente esses padrões na superclasse %Persistent (embora os aplicaremos ao criar uma tabela do zero usando o comando DDL CREATE TABLE). Portanto, uma revisão periódica das classes e do armazenamento vale a pena. Também é possível editar o XML de Definição de Armazenamento diretamente, mas os usuários precisam ter muito cuidado, pois isso pode tornar os dados existentes inacessíveis.

Até aqui, tudo bem. As Definições de Armazenamento oferecem um mapeamento inteligente entre suas classes e se adaptam automaticamente com a evolução do esquema. O que mais tem lá?

Estático x Estatísticas?

Como você provavelmente sabe, o mecanismo SQL do InterSystems IRIS faz o uso avançado de estatísticas de tabela para identificar o plano de consulta ideal para qualquer declaração executada pelo usuário. As estatísticas de tabela incluem métricas sobre o tamanho de uma tabela, como os valores são distribuídos em uma coluna e muito mais. Essas informações ajudam o otimizador de SQL do IRIS a decidir qual índice é mais vantajoso, em que ordem unir as tabelas, etc. Portanto, intuitivamente, quanto mais atualizadas as estatísticas estiverem, maiores serão as chances de planos de consulta ideais. Infelizmente, até a introdução da amostragem de bloco rápida no IRIS 2021.2, coletar estatísticas de tabela precisas costumava ser uma operação computacionalmente cara. Portanto, quando os clientes implantavam o mesmo aplicativo em vários ambientes com padrões de dados basicamente iguais, fazia sentido considerar as estatísticas de tabela como parte do código do aplicativo e incluí-las nas definições da tabela.

Por isso, no IRIS hoje você encontra as estatísticas de tabela incorporadas à Definição de Armazenamento. Ao coletar estatísticas de tabela por uma chamada manual para TUNE TABLE ou de maneira implícita pela consulta (veja abaixo), as novas estatísticas são gravadas na Definição de Armazenamento e os planos de consulta existentes para essa tabela são invalidados, para que possam aproveitar as novas estatísticas durante a próxima execução. Por serem parte da Definição de Armazenamento, essas estatísticas farão parte das exportações de classe UDL e, portanto, podem acabar no seu repositório de código-fonte. No caso de estatísticas cuidadosamente verificadas para um aplicativo empacotado, isso é desejado, pois você quer que essas estatísticas específicas levem à geração do plano de consulta para todas as implantações do aplicativo.

A partir de 2021.2, o IRIS coletará automaticamente as estatísticas de tabela no início do planejamento de consulta ao consultar uma tabela que não possui nenhuma estatística e está qualificada para a amostragem de bloco rápida. Nos nossos testes, os benefícios de trabalhar com estatísticas atualizadas em vez de nenhuma estatística superaram claramente o custo da coleta de estatísticas em tempo real. Para alguns clientes, no entanto, isso teve o lamentável efeito colateral das estatísticas coletadas automaticamente na instância do desenvolvedor terminarem na Definição de Armazenamento no sistema de controle de fonte e, por fim, no aplicativo empacotado. Obviamente, os dados nesse ambiente de desenvolvedor e, portanto, as estatísticas nele talvez não sejam representativos para uma implantação real do cliente e levem a planos de consulta abaixo do ideal.

É fácil evitar essa situação. As estatísticas de tabela podem ser excluídas da exportação da definição de classe usando o qualificador /exportselectivity=0 ao chamar $SYSTEM.OBJ.Export(). O padrão do sistema para essa sinalização pode ser configurado usando $SYSTEM.OBJ.SetQualifiers("/exportselectivity=0"). Depois, deixe para a coleta automática na eventual implantação coletar estatísticas representativas, tornar a coleta de estatísticas explícitas parte do processo de implantação, o que substituirá qualquer coisa que possa ter sido empacotada com o aplicativo, ou gerenciar suas estatísticas de tabela separadamente pelas próprias funções de importação/exportação: $SYSTEM.SQL.Stats.Table.Export() e Import().  

A longo prazo, pretendemos mover as estatísticas de tabela para ficar com os dados, em vez de fazer parte do código, e diferenciar mais claramente entre quaisquer estatísticas configuradas explicitamente por um desenvolvedor e as coletadas de dados reais. Além disso, estamos planejando mais automação em relação à atualização periódica dessas estatísticas, com base em quanto os dados da tabela mudam ao longo do tempo. 

Conclusão

Neste artigo, descrevemos a função de uma Definição de Armazenamento no mecanismo ObjectRelational do IRIS, como ela é compatível com a evolução do esquema e o que significa incluí-la no seu sistema de controle de fonte. Também descrevemos por que as estatísticas de tabela são atualmente armazenadas nessa Definição de Armazenamento e sugerimos práticas de desenvolvimento para garantir que as implantações de aplicativos acabem com estatísticas representativas dos dados reais do cliente. Conforme mencionado anteriormente, planejamos aprimorar ainda mais esses recursos. Portanto, aguardamos seu feedback sobre a funcionalidade atual e planejada para refinar nosso design conforme apropriado.

0
0 88
Artigo Eduard Lebedyuk · Nov. 22, 2021 8m read

Todo mundo tem um ambiente de teste.

Algumas pessoas têm a sorte de ter um ambiente totalmente separado para executar a produção.

-- Desconhecido

.

Nesta série de artigos, gostaria de apresentar e discutir várias abordagens possíveis para o desenvolvimento de software com as tecnologias InterSystems e GitLab. Vou cobrir tópicos como:

  • Git Básico
  • Fluxo Git (processo de desenvolvimento)
  • Instalação do GitLab
  • Fluxo de Trabalho do GitLab
  • GitLab CI/CD
  • CI/CD com contêineres

Esta primeira parte trata do pilar do desenvolvimento de software moderno - sistema de controle de versão Git e vários fluxos Git.

Git Básico

Embora o tópico principal que iremos discutir seja o desenvolvimento de software em geral e como o GitLab pode nos capacitar nesse esforço, o Git, ou melhor, os vários conceitos de alto nível subjacentes no design do Git, são importantes para o melhor entendimento de conceitos posteriores.

Dito isso, o Git é um sistema de controle de versão, baseado nessas ideias (existem muitas outras, essas são as mais importantes):

  • Desenvolvimento não linear significa que enquanto nosso software é lançado consequentemente da versão 1 para a 2 para a 3, sob a mesa a mudança da versão 1 para a 2 é feita em paralelo - vários desenvolvedores desenvolvem uma série de recursos/correções de bugs simultaneamente.
  • Desenvolvimento distribuído significa que o desenvolvedor é independente de um servidor central ou de outros desenvolvedores e pode desenvolver facilmente em seu próprio ambiente.
  • Fusão - as duas ideias anteriores nos levam à situação em que muitas versões diferentes da verdade existem simultaneamente e precisamos uni-las de volta em um estado completo.

Agora, não estou dizendo que Git inventou esses conceitos. Não. Em vez disso, o Git os tornou fáceis e populares e isso, juntamente com várias inovações relacionadas, ou seja,  infraestrutura como código/conteinerização mudou o desenvolvimento de software.

Termos básicos do Git

Repositório é um projeto que armazena dados e metainformações sobre os dados.

  • O repositório "físico" é um diretório em um disco.
  • O repositório armazena arquivos e diretórios.
  • O repositório também armazena um histórico completo de alterações para cada arquivo.

O repositório pode ser armazenado:

  • Localmente, em seu próprio computador
  • Remotamente em um servidor remoto

Mas não há nenhuma diferença particular entre repositórios locais e remotos do ponto de vista do git.

Commit é um estado fixo do repositório. Obviamente, se cada commit armazenasse o estado completo do repositório, nosso repositório cresceria muito rapidamente. É por isso que um commit armazena um diff que é uma diferença entre o commit atual e seu commit pai.

Commits diferentes podem ter um número diferente de pais:

  • 0 - o primeiro commit no repositório não tem pais.
  • 1 - conforme o habitual - nosso commit mudou algo no repositório como era durante o commit pai
  • 2 - quando temos dois estados diferentes do repositório, podemos uni-los em um novo estado. E esse estado e esse commit teriam 2 pais.
  • 2 - pode acontecer quando unimos mais de 2 estados diferentes do repositório em um novo estado. Não seria particularmente relevante para nossa discussão, mas existe.

Agora, para um pai, cada commit diferente é chamado de commit filho. Cada commit pai pode ter qualquer número de commits filhos.

Branch é uma referência (ou ponteiro) para um commit.  Veja como funciona:

Nesta imagem, podemos ver o repositório com dois commits (círculos cinza), o segundo é o head do branch master. Depois de adicionar mais commits, nosso repositório começa a ficar assim:

Esse é o caso mais simples. Um desenvolvedor trabalha em uma mudança de cada vez. No entanto, normalmente, existem muitos desenvolvedores trabalhando simultaneamente em diferentes recursos e precisamos de uma árvore de commit para mostrar o que está acontecendo em nosso repositório.

Árvore de commit

Vamos começar do mesmo ponto de partida. Aqui está o repositório com dois commits:

Mas agora, dois desenvolvedores estão trabalhando ao mesmo tempo e para não interferir um no outro, eles trabalham em branches separados:

Depois de um tempo, eles precisam unir as alterações feitas e para isso eles criam uma solicitação de mesclagem (merge) (também chamada de pull request) - que é exatamente o que parece - é uma solicitação para unir dois estados diferentes do repositório (no nosso caso, queremos mesclar o develop branch no master branch) em um novo estado. Depois de ser devidamente revisado e aprovado, nosso repositório fica assim:

E o desenvolvimento continua:

Resumo - Git Básico

Conceitos principais:

  • Git é um sistema de controle de versão distribuído não linear.
  • Repositório armazena dados e metainformações sobre os dados.
  • Commit é um estado fixo do repositório.
  • Branch é uma referência para um commit. 
  • Solicitação de mesclagem (também chamada de pull request) - é uma solicitação para unir dois estados diferentes do repositório em um novo estado.

Se você quiser ler mais sobre o Git, existem livros disponíveis.

Fluxos Git

Agora que o leitor está familiarizado com os termos e conceitos básicos do Git, vamos falar sobre como a parte do desenvolvimento do ciclo de vida do software pode ser gerenciada usando o Git.  Existem várias práticas (chamadas  de fluxos) que descrevem o processo de desenvolvimento usando Git, mas vamos falar sobre duas delas:

  • Fluxo do GitHub
  • Fluxo do GitLab

Fluxo do GitHub

O fluxo do GitHub é tão fácil quanto parece. Aqui está:

  1. Crie um branch (ramificação) do repositório.
  2. Commit suas alterações para seu novo branch
  3. Envie um pull request do seu branch com as alterações propostas para iniciar uma discussão.
  4. Commit mais alterações em seu branch conforme necessário. Seu pull request será atualizado automaticamente.
  5. Mescle o pull request assim que o branch estiver pronto para ser mesclado.

E existem várias regras que devemos seguir:

  • master branch é sempre implantável (e funcionando!)

  • Não há desenvolvimento indo diretamente para o master branch

  • O desenvolvimento está acontecendo nos branches de recursos

  • master == ambiente** de produção*

  • Você precisa implantar na produção o mais rápido possível

    • Não confunda com "Produções Ensemble", aqui "Produção" significa SISTEMA EM PRODUÇÃO.

** Ambiente é um local configurado onde seu código é executado - pode ser um servidor, uma VM, até mesmo um contêiner.

Veja como funciona:

Você pode ler mais sobre o fluxo do GitHub aqui. Também há um guia ilustrado.

O fluxo do GitHub é bom para pequenos projetos e para testes se você está começando com os fluxos do Git. No entanto, o GitHub o usa, portanto, também pode ser viável em projetos grandes.

Fluxo do GitLab

Se você não estiver pronto para implantar na produção imediatamente, o fluxo do GitLab oferece um fluxo do GitHub + ambientes. É assim que funciona - você desenvolve em branches de recursos, como acima, mescla (merge) no master, como acima, mas aqui está uma diferença: o master é igual apenas no ambiente de teste. Além disso, você tem "Branches de ambiente" que estão vinculados a vários outros ambientes que você possa ter.

Normalmente, existem três ambientes (você pode criar mais se precisar):

  • Ambiente de teste == master branch
  • Ambiente de pré-produção == preprod branch
  • Ambiente de produção == prod branch

O código que chega em um dos branches do ambiente deve ser movido para o ambiente correspondente imediatamente, isso pode ser feito:

  • Automaticamente (cobriremos isso nas partes 2 e 3)
  • Parcialmente automático (igual ao automaticamente, exceto que um botão que autoriza a implantação deve ser pressionado)
  • Manualmente

Todo o processo é assim:

  1. O recurso é desenvolvido no branch de recursos.
  2. O branch de recurso é revisado e mesclado no master branch.
  3. Depois de um tempo (vários recursos mesclados), o master é mesclado com o preprod
  4. Depois de um tempo (teste do usuário, etc.), o preprod é mesclado com o prod  
  5. Enquanto estávamos mesclando e testando, vários novos recursos foram desenvolvidos e mesclados no master, então vá para parte 3.

Veja como funciona:

Você pode ler mais sobre o fluxo do GitLab aqui.

Conclusão

  • Git ****é um sistema de controle de versão distribuído não linear.
  • O fluxo Git pode ser usado como uma diretriz para o ciclo de desenvolvimento de software; existem vários que você pode escolher.

Links

Questões para discussão

  • Você usa um fluxo git? Qual?
  • Quantos ambientes você tem para um projeto padrão?

O que vem a seguir

Na próxima parte, iremos:

  • Instalar o GitLab.
  • Falar sobre alguns ajustes recomendados.
  • Discutir o fluxo de trabalho do GitLab (não deve ser confundido com o fluxo do GitLab).

Fique ligado.

0
0 311
Artigo Vinicius Maranhao Ribeiro de Castro · Jul. 6, 2021 11m read

Introdução

Suponha que você desenvolveu uma nova aplicação utilizando a parte de Interoperabilidade do InterSystems IRIS e você tem certeza de que será um sucesso! No entanto, você ainda não tem um número concreto de quantas pessoas irão utilizá-la. Além disso, pode haver dias específicos em que há mais pessoas utilizando sua aplicação e dias em que quase ninguém irá acessar. Deste modo, você necessita de que sua aplicação seja escalável!

0
0 139
Job Rogerio de Oliveira · Jun. 24, 2021

Pessoal,

Procuro perfil de analista de integração / Ensemble (freelance). Interessados, por favor enviar mensagem de WhatsApp (61) 98405-2981.

Local de trabalho: 100% Remoto

Habilidades:  Cache DB, Object Script, InterSystems, Ensemble

Conhecimentos Necessários:

0
0 125
InterSystems Oficial Steven LeBlanc · Maio 20, 2021

Estou muito grato em anunciar o lançamento do InterSystems Container Registry. Este lançamento disponibiliza um novo canal de distribuição para que clientes possam acessar lançamentos é prévias de lançamentos baseadas em contêineres. Todas as imagens Community Edition estão disponíveis em um repositório público sem necessidade de login. Todas as imagens de produto completos (IRIS, IRIS for Health, Health Connect, System Alerting and Monitoring, InterSystems Cloud Manager) e imagens utilitárias (como o árbitro, Web Gateway e PasswordHash) necessitam de token de login, gerado a partir das credenciais de sua conta do WRC.

0
0 91
Artigo Vinicius Maranhao Ribeiro de Castro · Maio 11, 2021 7m read

Introdução

Suponha que você desenvolveu uma nova aplicação utilizando a parte de Interoperabilidade do InterSystems IRIS e você tem certeza de que será um sucesso! No entanto, você ainda não tem um número concreto de quantas pessoas irão utilizá-la. Além disso, pode haver dias específicos em que há mais pessoas utilizando sua aplicação e dias em que quase ninguém irá acessar. Deste modo, você necessita de que sua aplicação seja escalável!

0
2 139
Artigo Vinicius Maranhao Ribeiro de Castro · Mar. 9, 2021 12m read

Introdução

Com a transformação digital no mundo dos negócios, novos recursos ou funcionalidades nos softwares oferecidos por uma empresa, podem significar vantagem competitiva. No entanto, se o time de TI não estiver preparado com a cultura, metodologia, práticas e ferramentas corretas, pode ser muito difícil garantir a entrega dessas novas funcionalidades a tempo hábil.

0
0 859