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 :
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.
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.
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
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: []
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: