Entrega contínua de sua solução InterSystems usando GitLab – Parte VIII: CD usando ICM
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()
haltObserve 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:
- Cria o namespace do aplicativo.
- Cria o banco de dados de código do aplicativo (os dados seriam armazenados no banco de dados USER).
- carrega o código no banco de dados de código do aplicativo.
- Mapeia o pacote MyApp para o namespace USER.
- 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.key, pwd.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_NAMEObserve 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"