GitLab CI: 6 recursos dos últimos lançamentos que esperávamos



Na era do CI / CD onipresente, somos confrontados com uma ampla gama de ferramentas relacionadas, incluindo sistemas de CI. No entanto, foi o GitLab que se tornou o mais próximo de nós, verdadeiramente “nativo”. Ele ganhou notável popularidade na indústria como um todo *. Os desenvolvedores do produto não ficaram para trás do crescente interesse em seu uso, deliciando regularmente a comunidade de desenvolvedores e engenheiros de DevOps com novas versões.


Mês do repositório GitLab e agregação de tags

GitLab é o caso quando o desenvolvimento ativo traz muitos recursos novos e interessantes. Se, para usuários em potencial, esse é apenas um dos fatores de escolha de uma ferramenta, para os existentes, a situação é a seguinte: se você não atualizou sua instalação do GitLab no mês passado, com grande probabilidade de perder algo interessante. Incluindo atualizações de segurança emergentes regularmente.

Sobre os mais significativos - ou seja, exigido pelos nossos engenheiros e clientes do DevOps - inovações nas versões mais recentes da edição do GitLab para comunidade, e este artigo será discutido.

* 5 , «GitLab», : «, GitHub?». — , Google Trends 5- «gitlab» . «» , . , , «» .

№1: needs


  • job'.
  • GitLab: 12.2.
  • .

Pensamento dependencies- é disso que você precisa? Provavelmente, não fomos os únicos que cometeram o erro de atribuir essa diretiva ... É necessário listar os trabalhos anteriores, cujos artefatos serão necessários. São artefatos, e não dependência do desempenho da tarefa anterior.

Suponha que aconteceu que em um estágio existam trabalhos que não são necessários para serem executados, mas, por alguma razão, não há possibilidade ou apenas desejo de levá-los para um estágio separado (a preguiça é o motor do progresso, mas não se deixa levar).

Situação:



Como você pode ver, o estágio Deploy contém botões para implementar a produção e o estágio e os testes de selênio do trabalhopor algum motivo não é executado. É simples: ele espera até que todos os trabalhos do estágio anterior sejam concluídos com êxito. No entanto, na estrutura do mesmo pipeline, não precisamos implantar o estágio agora para executar os testes (ele foi bombeado anteriormente, não dentro da tag). O que fazer? Então venha para as necessidades de resgate !

Listamos apenas os trabalhos anteriores necessários para executar nossos testes:

  needs:
    - To production (Cluster 1)
    - To production (Cluster 2)

... e obtemos um trabalho, que é chamado automaticamente depois que apenas os trabalhos listados são executados:



Convenientemente, certo? Mas uma vez eu esperava que a diretiva funcionasse dessa maneira dependencies...

No. 2: estende



Cansado de ler rolos .gitlab-ci.yaml? Falta o princípio de reutilização de código? Então você já tentou e provavelmente trouxe o seu .gitlab-ci.yamlpara um estado como este:

.base_deploy: &base_deploy
  stage: deploy
  script:
    - my_deploy_command.sh
  variables:
    CLUSTER: "default-cluster"
    MY_VAR: "10"

Deploy Test:
  <<: *base_deploy
  environment:
    url: test.example.com
    name: test

Deploy Production:
  <<: *base_deploy
  environment:
    url: production.example.com
    name: production
  variables:
    CLUSTER: "prod-cluster"
    MY_VAR: "10"

Parece bom? No entanto, se você olhar de perto, algo chama sua atenção ... Por que mudamos a produção não apenas variables.CLUSTER, mas também prescrevemos uma segunda vez variables.MY_VAR=10? Essa variável deve ser retirada base_deploy? Acontece que não deveria: o YAML funciona para que, redefinindo o que é recebido da âncora, não expanda o conteúdo dos campos correspondentes, mas o substitua . Portanto, somos forçados a listar as variáveis ​​já conhecidas por nós no parágrafo correspondente.

Sim, “expande” é a palavra certa: é exatamente assim que o recurso em questão é chamado. ExtendsEles nos permitem não apenas reescrever o campo, como acontece com a âncora, mas realizar uma fusão inteligente para ele:

.base_deploy: 
  stage: deploy
  script:
    - my_deploy_command.sh
  variables:
    CLUSTER: "default-cluster"
    MY_VAR: "10"

Deploy Production:
  extends: .base_deploy
  environment:
    url: production.example.com
    name: production
  variables:
    CLUSTER: "prod-cluster"

Aqui no trabalho final, Implantar produção, haverá uma variável MY_VARcom um valor padrão e uma substituída CLUSTER.

Parece que isso é um pouco, mas imagine: você tem um base_deploye 20 circuitos implantados de maneira semelhante. Eles precisam ser transmitidos a outras pessoas cluster, environment.namepreservando um certo conjunto de variáveis ​​ou outros campos correspondentes ... Essa pequena satisfação nos permitiu reduzir a descrição da implantação de muitos circuitos de desenvolvimento em 2-3 vezes.

No. 3: inclua



.gitlab-ci.yamlainda parece uma instrução dobrável para um aspirador de pó em 20 idiomas (dos quais você entende apenas o seu nativo), é difícil quando você precisa lidar com uma de suas seções sem mudar a aparência de trabalhos desconhecidos encontrados no caminho?

Um amigo de longa data da programação ajudará include:

stages:
  - test
  - build
  - deploy

variables:
  VAR_FOR_ALL: 42

include:
  - local: .gitlab/ci/test.yml
  - local: .gitlab/ci/build.yml
  - local: .gitlab/ci/deploy-base.yml
  - local: .gitlab/ci/deploy-production.yml

Essa. Agora, estamos editando com ousadia a implantação na produção, enquanto os testadores estão ocupados modificando seu arquivo, que nem sequer podemos ver. Além disso, isso ajuda a evitar conflitos de mesclagem: nem sempre é divertido entender o código de outra pessoa.

Mas e se conhecermos o pipeline de nossos 20 projetos, podemos explicar a lógica de cada trabalho a partir dele? Como isso nos ajudará? Para aqueles que alcançaram a iluminação na reutilização de código e para todos os que têm muitos projetos semelhantes, você pode:


Uma dúzia do mesmo tipo de projetos com código diferente, mas implantados da mesma maneira - com facilidade e sem manter o IC atualizado em todos os repositórios!

Um exemplo de uso prático includetambém foi dado neste artigo .

No. 4: somente / exceto refs


  • Condições abrangentes, incluindo variáveis ​​e alterações de arquivo.
  • Como essa é uma família inteira de funções, algumas partes começaram a aparecer no GitLab 10.0, enquanto outras (por exemplo changes) começaram a aparecer na 11.4.
  • docs.gitlab.com/ce/ci/yaml/#onlyexcept-advanced

Às vezes, parece-me que este não é um canal que nos escuta, mas nós ele. Uma excelente ferramenta de gerenciamento está only/ except- agora integrada. O que isto significa?

No caso mais simples (e talvez o mais agradável), pular etapas:

Tests:
  only:
    - master
  except:
    refs:
    - schedules
    - triggers
    variables:
    - $CI_COMMIT_MESSAGE =~ /skip tests/

No trabalho de exemplo, ele é executado apenas na ramificação principal, mas não pode ser acionado por um agendamento ou acionamento (o GitLab compartilha chamadas e acionadores de API, embora essa seja essencialmente a mesma API). O trabalho não será executado se houver uma senha de ignorar testes na mensagem de confirmação . Por exemplo, um erro de digitação no README.mdprojeto ou na documentação foi corrigido - por que esperar pelos resultados do teste?

"Ei, 2020 está lá fora!" Por que devo explicar sempre à caixa de ferro que não é necessário executar testes ao alterar a documentação? ” E realmente: only:changespermite executar testes ao alterar arquivos apenas em determinados diretórios. Por exemplo:

  only:
    refs:
      - master
      - merge_requests
    changes:
      - "front/**/*"
      - "jest.config.js"
      - "package.json"

E para a ação inversa - ou seja, não corra - sim except:changes.

No. 5: regras



Esta diretiva é muito semelhante à anterior only:*, mas com uma diferença importante: permite controlar o parâmetro when. Por exemplo, se você não deseja remover completamente a possibilidade de iniciar um trabalho. Você pode simplesmente deixar o botão, que, se desejado, será chamado de forma independente, sem iniciar um novo pipeline ou sem confirmar.

# 6: ambiente: auto_stop_in



Aprendemos sobre essa oportunidade logo antes da publicação do artigo e ainda não tivemos tempo suficiente para experimentá-lo na prática, mas essa é definitivamente “a mesma coisa” que era tão esperada em vários projetos.

Você pode especificar um parâmetro nos ambientes GitLab on_stop- é muito útil quando você deseja criar e excluir ambientes dinamicamente, por exemplo, para cada filial. O trabalho marcado com k on_stopé executado, por exemplo, quando a mesclagem do MR está na ramificação mestre ou quando o MR é fechado (ou apenas clicando no botão), devido ao qual o ambiente desnecessário é excluído automaticamente.

Tudo é conveniente, lógico, funciona ... se não for pelo fator humano. Muitos desenvolvedores mesclam MRs não clicando em um botão no GitLab, mas localmente via git merge. Você pode entendê-los: é conveniente! Mas neste caso, a lógicaon_stopnão funciona, acumulamos um ambiente esquecido ... É aqui que os tão esperados vêm a calhar auto_stop_in.

Bônus: cabanas temporárias quando não há oportunidades suficientes


Apesar de todas essas (e muitas outras) funções novas e exigidas do GitLab, infelizmente, às vezes as condições para a realização de um trabalho são simplesmente impossíveis de serem descritas dentro da estrutura dos recursos disponíveis no momento.

O GitLab não é perfeito, mas fornece as ferramentas básicas para construir um pipeline de sonhos ... se você estiver pronto para ir além do modesto DSL, mergulhando no mundo dos scripts. Aqui estão algumas soluções de nossa experiência, que de forma alguma pretendem ser ideologicamente corretas ou recomendadas, mas são apresentadas mais para demonstrar diferentes possibilidades com a falta de funcionalidade de API integrada.

Solução alternativa nº 1: inicie dois trabalhos com um botão


script:
  - > 
    export CI_PROD_CL1_JOB_ID=`curl -s -H "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \ 
      "https://gitlab.domain/api/v4/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/jobs" | \
      jq '[.[] | select(.name == "Deploy (Cluster 1)")][0] | .id'`
  - > 
    export CI_PROD_CL2_JOB_ID=`curl -s -H "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \ 
      "https://gitlab.domain/api/v4/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/jobs" | \
      jq '[.[] | select(.name == "Deploy (Cluster 2)")][0] | .id'`
  - > 
    curl -s --request POST -H "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \ 
      "https://gitlab.domain/api/v4/projects/${CI_PROJECT_ID}/jobs/$CI_PROD_CL1_JOB_ID/play"
  - > 
    curl -s --request POST -H "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \ 
      "https://gitlab.domain/api/v4/projects/${CI_PROJECT_ID}/jobs/$CI_PROD_CL2_JOB_ID/play"

E por que não, se você realmente quer?

Solução alternativa 2: transferência alterada nos arquivos MR rb para rubocop dentro da imagem


Rubocop:
  stage: test
  allow_failure: false
  script:
    ...
    - export VARFILE=$(mktemp)
    - export MASTERCOMMIT=$(git merge-base origin/master HEAD)
    - echo -ne 'CHANGED_FILES=' > ${VARFILE}
    - if [ $(git --no-pager diff --name-only ${MASTERCOMMIT} | grep '.rb$' | wc -w |awk '{print $1}') -gt 0 ]; then
        git --no-pager diff --name-only ${MASTERCOMMIT} | grep '.rb$' |tr '\n' ' ' >> ${VARFILE} ;
      fi
    - if [ $(wc -w ${VARFILE} | awk '{print $1}') -gt 1 ]; then
        werf --stages-storage :local run rails-dev --docker-options="--rm --user app --env-file=${VARFILE}" -- bash -c /scripts/rubocop.sh ;
      fi
    - rm ${VARFILE}

Não há imagem dentro .git, então tive que sair para verificar apenas os arquivos alterados.

Nota: Essa não é uma situação muito padrão e uma tentativa desesperada de cumprir muitas condições do problema, cuja descrição não está incluída no escopo deste artigo.

Solução nº 3: gatilho para iniciar trabalhos de outros repositórios ao implantar


  before_script:
    - |
      echo '### Trigger review: infra'
      curl -s -X POST \
        -F "token=$REVIEW_TOKEN_INFRA" \
        -F "ref=master" \
        -F "variables[REVIEW_NS]=$CI_ENVIRONMENT_SLUG" \
        -F "variables[ACTION]=auto_review_start" \
        https://gitlab.example.com/api/v4/projects/${INFRA_PROJECT_ID}/trigger/pipeline

Parece que uma coisa tão simples e necessária (no mundo dos microsserviços) está lançando outro microsserviço em um circuito recém-criado como uma dependência. Mas, portanto, não é necessária uma chamada de API e um recurso já familiar (descrito acima):

  only:
    refs:
    - triggers
    variables:
    - $ACTION == "auto_review_start"

Notas:

  • O trabalho no acionador foi projetado para ser vinculado à passagem de uma variável para a API, da mesma forma que no exemplo 1. É mais lógico implementar isso na API com o nome do trabalho passado.
  • Sim, a função está na versão comercial (EE) do GitLab, mas não a consideramos.

Conclusão


O GitLab tenta acompanhar as tendências, implementando gradualmente recursos agradáveis ​​e procurados pela comunidade DevOps. Eles são bastante fáceis de usar e, quando os recursos básicos não são suficientes, eles sempre podem ser expandidos com scripts. E se percebermos que o suporte não é tão elegante e conveniente ... resta aguardar novos lançamentos do GitLab - ou ajudar o projeto com sua contribuição .

PS


Leia também no nosso blog:


All Articles