Dicas para criar fluxos de trabalho personalizados no GitLab CI

Nota perev. : O artigo original foi escrito por Miłosz Smółka, um dos fundadores da pequena empresa polonesa Three Dots Labs , especializada em "soluções avançadas de back-end". O autor baseia-se em sua experiência no uso ativo do GitLab CI e compartilha as dicas acumuladas para outros usuários deste produto Open Source. Depois de lê-los, percebemos o quão perto os problemas descritos por ele estão perto de nós, por isso decidimos compartilhar as soluções propostas com um público mais amplo.



Desta vez, abordarei tópicos mais avançados no GitLab CI. Uma tarefa comum aqui é implementar recursos não padrão no pipeline. A maioria das dicas é específica para o GitLab, embora algumas possam ser aplicadas a outros sistemas de IC.

Executar testes de integração


Como regra, a verificação de código usando testes de unidade é fácil de conectar a qualquer sistema de IC. Normalmente, isso não é mais complicado do que executar um dos comandos embutidos no conjunto padrão de utilitários em uma linguagem de programação. Nesses testes, você provavelmente usará vários moki e stubs para ocultar os detalhes da implementação e focar no teste de lógica específica. Por exemplo, você pode usar o banco de dados na memória como stubs de armazenamento ou gravação para clientes HTTP que sempre retornarão respostas já preparadas.

No entanto, mais cedo ou mais tarde você precisará de testes de integração para cobrir situações mais incomuns com os testes. Não vou entrar em discussão sobre todos os tipos possíveis de teste e apenas digo que por integração quero dizer testes que usam algum tipo de recursos externos. Pode ser um servidor de banco de dados real, serviço HTTP, armazenamento conectado etc.

No GitLab, é fácil executar recursos conectáveis ​​como contêineres do Docker associados ao contêiner em que os scripts estão em execução. Essas dependências podem ser definidas usando services . Eles estão disponíveis pelo nome da imagem ou pelo nome de sua escolha, se você a especificar no campo de alias .

Aqui está um exemplo simples de uso de um contêiner conectável com o MySQL:

 integration_tests: stage: tests services: - name: mysql:8 alias: db script: - ./run_tests.sh db:3306 

Nesse caso, nos scripts de teste, você precisará se conectar ao host db . Usar um alias geralmente é uma boa ideia, pois permite substituir imagens sem a necessidade de modificar o código de teste. Por exemplo, você pode substituir a imagem do mysql por mariadb , e o script ainda funcionará corretamente.

À espera de contêineres


Como os contêineres de plug-in demoram para carregar, pode ser necessário aguardar antes de enviar qualquer solicitação. Uma maneira simples é o script wait-for-it.sh com um tempo limite definido.

Usando o Docker Compose


Na maioria dos casos, os services devem ser suficientes. No entanto, às vezes a interação com serviços externos pode ser necessária. Por exemplo, no caso de iniciar o Kafka e o ZooKeeper em dois contêineres separados (é assim que as imagens oficiais são coletadas). Outro exemplo é a execução de testes com um número dinâmico de nós, como o Selenium. A melhor solução para executar esses serviços seria o Docker Compose :

 version: '3' services: zookeeper: image: confluentinc/cp-zookeeper environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: image: confluentinc/cp-kafka environment: KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 ports: - 9092:9092 

Se você usar sua instalação com os corredores do GitLab em servidores confiáveis, poderá executar o Docker Composer através do executor do Shell . Outra opção possível é o Docker no dind Docker ( dind ). Mas, neste caso, leia este artigo primeiro.

Uma maneira de usar o Compose é configurar seu ambiente, executar testes e destruir tudo. Um script bash simples ficaria assim:

 docker-compose up -d ./run_tests.sh localhost:9092 docker-compose down 

Contanto que você execute testes em um ambiente mínimo, tudo ficará bem. Embora possa surgir uma situação na qual você precisa instalar algumas dependências ... Há outra maneira de executar testes no Docker Compose - ele permite criar sua própria imagem do Docker com um ambiente de teste. Em um dos contêineres, você executa testes e sai com o código de retorno correspondente:

 version: '3' services: zookeeper: image: confluentinc/cp-zookeeper environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: image: confluentinc/cp-kafka environment: KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 tests: image: registry.example.com/some-image command: ./run_tests.sh kafka:9092 

Observe que eliminamos a necessidade de mapear portas. Neste exemplo, os testes podem interagir com todos os serviços diretamente.

E seu lançamento é realizado por um comando:

 docker-compose up --exit-code-from tests 

A opção --exit-code-from implica --abort-on-container-exit , o que significa: todo o ambiente iniciado pela docker-compose up será interrompido após a conclusão de um dos contêineres. O código de conclusão para este comando será equivalente ao código de saída do serviço selecionado (ou seja, esses são os tests no exemplo acima). Se o comando que inicia os testes for concluído com código diferente de zero, o docker-compose up inteiro será encerrado.

Usando rótulos como tags de IC


Aviso : essa é uma idéia bastante incomum, mas me pareceu muito útil e flexível.

Como você deve saber, o GitLab tem um recurso de Etiquetas disponível no nível do projeto e do grupo. Os rótulos podem ser definidos nos tickets e nas solicitações de mesclagem. No entanto, eles não têm relação com os pipelines.



Um pouco de refinamento permitirá acessar os rótulos da solicitação de mesclagem nos scripts de trabalho. No GitLab 11.6, tudo se tornou ainda mais fácil, porque a variável de ambiente CI_MERGE_REQUEST_IID apareceu (sim, é com o IID , não o ID ) se o pipeline usar only: merge_requests .

Se only: merge_requests não only: merge_requests usado ou você estiver trabalhando com uma versão mais antiga do GitLab, o MR ainda poderá ser obtido - usando a chamada da API:

 curl "$CI_API_V4_URL/projects/$CI_PROJECT_ID/repository/commits/$CI_COMMIT_SHA/merge_requests?private_token=$GITLAB_TOKEN" 

O campo que precisamos é iid . No entanto, lembre-se de que muitos MRs podem retornar para um determinado commit.

Quando o MR IID é recebido, resta apenas recorrer à API de solicitações de mesclagem e usar o campo de labels da resposta:

 curl "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID?private_token=$GITLAB_TOKEN" 

Entrar


Infelizmente, no momento não é possível usar $CI_JOB_TOKEN para acessar a API do projeto (pelo menos se o projeto não for público). Se o projeto tiver acesso limitado (interno ou privado), para autorização na API do GitLab, você precisará gerar um token de API pessoal.



No entanto, essa não é a solução mais segura, portanto, tenha cuidado. Se o token cair em mãos ruins, o acesso de gravação a todos os seus projetos poderá aparecer com ele. Uma maneira de reduzir riscos é criar uma conta separada com o direito de ler o repositório e gerar um token pessoal para essa conta.

Quão seguras são suas variáveis?


Algumas versões atrás, a seção Variáveis era chamada Variáveis ​​Secretas , que parece que elas foram criadas para armazenar credenciais e outras informações críticas de maneira confiável. De fato, as variáveis ​​são simplesmente ocultas dos usuários que não têm privilégios de Mantenedor. Eles não são criptografados no disco e seu vazamento pode ocorrer facilmente através de variáveis ​​de ambiente em scripts.

Lembre-se disso ao adicionar variáveis ​​e considere manter segredos em soluções mais seguras (por exemplo, o Vault da HashiCorp ).

Casos de uso


O que fazer com as listas de etiquetas depende de você. Aqui estão algumas idéias:

  • Use-os para segmentar testes.
  • Use a semântica de valor-chave com dois pontos como separador (por exemplo, rótulos como tests:auth , tests:user )
  • Inclua determinados recursos para trabalhos.
  • Permitir a depuração de trabalhos específicos se o rótulo existir.

Chamando APIs externas


Embora o GitLab possua vários recursos já disponíveis, é muito provável que você deseje usar outros utilitários que possam ser integrados aos pipelines. A maneira mais simples de implementá-lo é, obviamente, chamar o bom e velho curl .

Se você criar suas próprias ferramentas, poderá ensiná-las a ouvir os Webhooks do GitLab (consulte a guia Integrações nas configurações do projeto). No entanto, se você pretende usá-los com qualquer sistema crítico, verifique se eles atendem aos requisitos de alta disponibilidade.

Exemplo: anotações Grafana


Se você trabalha com o Grafana , as anotações são uma ótima maneira de marcar eventos que ocorreram ao longo do tempo nos gráficos. Eles podem ser adicionados não apenas manualmente clicando na GUI, mas também chamando a API REST do Grafana :



Para acessar a API, você precisará gerar uma chave de API. Considere criar um usuário separado com acesso limitado:



Defina duas variáveis ​​nas configurações do projeto:

  • GRAFANA_URL - URL da instalação do Grafana (por exemplo, https://grafana.example.com );
  • GRAFANA_APIKEY - chave gerada para a API.

Para poder reutilizá-lo, coloque o script no repositório com scripts comuns :

 #!/bin/bash set -e if [ $# -lt 2 ]; then echo "Usage: $0 <text> <tag>" exit 1 fi readonly text="$1" readonly tag="$2" readonly time="$(date +%s)000" cat >./payload.json <<EOF { "text": "$text", "tags": ["$tag"], "time": $time, "timeEnd": $time } EOF curl -X POST "$GRAFANA_URL/api/annotations" \ -H "Authorization: Bearer $GRAFANA_APIKEY" \ -H "content-type: application/json" \ -d @./payload.json 

Agora você pode adicionar sua chamada à configuração do IC com os parâmetros necessários:

 deploy: stage: deploy script: - $SCRIPTS_DIR/deploy.sh production - $SCRIPTS_DIR/grafana-annotation.sh "$VERSION deployed to production" deploy-production 

Essas chamadas podem ser feitas no script deploy.sh para simplificar a configuração do IC.

Bônus: dicas rápidas


O GitLab possui excelente documentação sobre todas as palavras-chave possíveis que podem ser usadas para configurar o IC. Não quero duplicar seu conteúdo aqui, mas vou apontar alguns casos úteis. Clique nos títulos para ver a documentação relacionada.

Uso avançado de somente / exceto


Ao definir padrões para variáveis ​​de IC, é possível definir montagens personalizadas para algumas ramificações. Isso pode ajudar, por exemplo, a identificar correções push para correções urgentes, mas não abuse:

 only: refs: - branches variables: - $CI_COMMIT_REF_NAME =~ /^hotfix/ 

O GitLab tem muitas variáveis ​​predefinidas em cada trabalho de IC - use-as.

Âncoras Yaml


Use-os para evitar duplicação.

Na versão 11.3, você também pode usar a palavra - chave extends :

 .common_before_script: &common_before_script before_script: - ... - ... deploy: <<: *common_before_script 

Exclusão de artefato


Por padrão, todos os artefatos coletados no pipeline serão transferidos para todos os trabalhos subseqüentes. Se você listar explicitamente os artefatos dos quais os trabalhos dependem, poderá economizar tempo e espaço em disco:

 dependencies: - build 

Ou, pelo contrário, pule completamente tudo se nenhum deles for necessário:

 dependencies: [] 

Estratégia Git


Ignore a clonagem de repositório se o trabalho não usar esses arquivos:

 variables: GIT_STRATEGY: none 

É isso aí!

Obrigado pela leitura! Para comentários e perguntas, entre em contato comigo no Twitter ou Reddit .

Mais dicas sobre o GitLab podem ser encontradas em posts anteriores:


PS do tradutor


Leia também em nosso blog:

Source: https://habr.com/ru/post/pt436910/


All Articles