Migramos do GitHub para o GitLab

Os bastidores da decisão e o que aprendemos com essa mudança

Caio Andrade
mercos-engineering

--

Also available in English

Aqui na Mercos, já tínhamos feito no passado uma migração de hospedagem de código fonte: em 2015 saímos do Beanstalk e fomos para o GitHub. Éramos um time de aproximadamente 7 pessoas e a migração foi bem tranquila. O motivo era basicamente termos mais recursos: Pull Requests, integrações com outros serviços, etc.

O status quo

Conforme os anos foram passando, adicionamos algumas ferramentas ao nosso workflow: integração contínua, medição de cobertura de testes, análise estática de código, atualização automática de dependências… Mas o GitHub continuava o mesmo, parado no tempo. Começamos a olhar para o GitLab por ele oferecer vários destes recursos nativamente, coisas que o GitHub só oferecia por meio de integrações que incorriam em custos adicionais por serem outros produtos.

Então a Microsoft comprou o GitHub e alguns anúncios de avanços técnicos começaram a ser feitos. Resolvemos aguardar mais um pouco para ver se algum novo recurso poderia valer mais a pena. O Dependabot era algo que já usávamos há muito tempo, e o anúncio de que ele se tornaria gratuito foi muito bem recebido. O GitHub Actions foi a última cartada que faltava para nos convencer de que talvez valeria mais a pena ficar no GitHub.

A decepção

Mas a teoria na prática nem sempre é a mesma. Testamos o GitHub Actions e nos decepcionamos. Ele é uma ótima alternativa para projetos OpenSource, por ser completamente gratuito, mas para a Mercos ele se tornaria rapidamente muito caro.

Fizemos o teste usando a infraestrutura do próprio GitHub, que cobra por minutos. Cada time pagante tem 10.000 minutos inclusos no plano. Esgotamos esses minutos em poucos dias, e fazendo a conta em dólares, ficaria absurdamente caro manter todos os minutos que iríamos precisar. Não faz sentido para nós um modelo de cobrança de CI que encoraja os desenvolvedores a testarem menos.

Passamos então para o segundo teste: Construir uma infraestrutura própria na AWS com agentes do GitHub Actions. Não foi fácil: Não existe imagem disponível dos agentes do GitHub Actions, e a mais similar tem vários GB de tamanho. Além disso, o processo de registro e desregistro dos agentes é moroso, através da API do GitHub, que deve ser consumida manualmente. O custo das máquinas até que seria baixo na AWS, mas o custo de manutenção quando algo desse errado seria um risco muito alto.

Porque agora?

O que acelerou a nossa mudança foi o impacto econômico gerado pelos acontecimentos de 2020. Precisávamos fazer um grande corte de custos. Avaliamos novamente os recursos do GitLab e decidimos por fazer a migração. Seguem os pontos principais que nos fizeram migrar e o que aprendemos com eles.

Os bastidores da decisão

Preço

O GitHub estava nos cobrando $8 por usuário por mês, enquanto o GitLab cobraria $4. Acabamos optando pelo plano gratuito do GitLab, o que deu uma vantagem quase injusta frente ao GitHub. Logo após a nossa migração, o GitHub anunciou uma mudança nos preços que fez com que ficassem muito similares aos preços do GitLab. Porém, a conta gratuita do GitHub não conta com recursos muito básicos como Wiki e mesmo com preços parecidos a oferta gratuita do GitLab é muito mais vantajosa.

Além do custo do GitHub, a migração para o GitLab nos fez economizar outros custos como ferramenta de CI dedicada, ferramenta de análise estática (Linter),

Estabilidade

O GitLab ficou famoso certo tempo atrás por ter apagado acidentalmente os dados de seus bancos de dados, e demorou cerca de 24h para recuperar, parcialmente, os dados dos clientes. O que nos surpreendeu foi a seriedade com que lidaram com a situação: Fizeram várias transmissões ao vivo mostrando os passos que estavam dando para solucionar o problema, e publicaram um extenso post-mortem com as medidas que adotaram para que não aconteça de novo.

O GitHub não teve um incidente tão grave, mas também teve ao longo dos anos vários momentos onde o famigerado unicórnio rosa apareceu para muitos, impossibilitando acesso à interface.

Na eventualidade de alguma indisponibilidade, tanto do GitLab quanto do GitHub, o código fica em backup na máquina de todos os desenvolvedores, que podem continuar o trabalho localmente sem problemas. Em relação às Issues e Boards, temos uma forte cultura de comunicação que poderia se adaptar por mensagem ou email ao invés de usar as Issues caso o serviço ficasse indisponível por várias horas. E sobre o deploy, tomamos o cuidado de conseguir executar os scripts de deploy manualmente nas máquinas dos SREs caso o nosso CI esteja fora do ar. Isso nos dá segurança de que não ficaremos completamente refém da hospedagem de código fonte que escolhemos.

Migrador

O GitLab possui um migrador incrível. Ele importa não somente o código, mas todas as branches, Issues, páginas da Wiki, Pull Requests (transforma em Merge Request), e etc. É só clicar e esperar.

Dica: Use a ferramenta de Archive Repository no GitHub para garantir que ninguém vai alterar nada enquanto a migração acontecer.

Dica 2: Adicione todos os usuários no GitLab primeiro, pois assim o importador já vai manter o mesmo usuário nos commits, Issues e Merge Requests.

CI

O GitLab CI é mais amigável ao nosso workflow que é baseado principalmente em Docker. Criar nossa própria infraestrutura de máquinas para o GitHub Actions foi bem traumático e nada simples, cheio de gambiarras. Já o GitLab CI tem um Helm Chart pronto, em minutos tínhamos a infraestrutura rodando na AWS.

Dica: Não use comandos docker ou docker-compose no GitLab CI. Ao invés de docker build, use o Kaniko com cache no registry, funciona muito bem. Ao invés de docker run ou docker-compose run, use a imagem que você fez build com o Kaniko como aimage do próximo step no CI.

Dica 2: Por padrão os Runners só aceitam Jobs que estiverem com tags específicas, o que não faz muito sentido. Para que eles aceitem todos os Jobs, adicione na configuração do Helm Chart:

runners:
runUntagged: true

Dica 3: A documentação do GitLab sobre rodar e escalar os Runners no Kubernetes não é muito boa. Ao invés de simplesmente subir mais Pods, você deve aumentar uma configuração no Helm Chart chamada concurrent, deixar que o GitLab Kubernetes Executor crie dinamicamente os Pods conforme a demanda, e então o cluster-autoscaler (que já deve estar funcionando previamente no cluster) faz sua mágica subindo mais nós no cluster.

Issues e Boards

Como escolhemos o plano gratuito do GitLab, não podemos criar múltiplos Boards a nível de Group (Organization). Então tivemos que nos adaptar e usar mais os Boards nos repositórios.

Uma outra questão também é que o GitLab exibe no Board sempre todos os cards, não há a opção de adicionar ou remover algum card do board. Cada estágio no Board é identificado por uma Label, então toda vez que arrastamos os cards no Board, efetivamente estamos trocando Labels neles.

Essas limitações e amarrações acabaram nos forçando a ser mais organizados com os cards, o que é algo bom, pois antes no GitHub muitas Issues acabavam caindo no limbo do esquecimento (e até tínhamos configurado um stale-bot para tentar ajudar a resolver esse problema).

Atualizador de dependências

Como mencionei no começo do artigo, usávamos o Dependabot como atualizador de dependências no GitHub. Ao migrar para o GitLab, descobrimos o RenovateBot, que é ainda mais inteligente (e funciona com o GitHub também).

Ele identifica automaticamente todas as dependências de múltiplas plataformas (por exemplo: Python, Docker, GitLab-CI) e se alguma não estiver fixa (pinned), ele primeiro abre uma MR para fixar todas e depois outras para as atualizações.

O RenovateBot identifica quando um conjunto de dependências é de um mesmo monorepo e atualiza elas juntas na mesma MR, o que é muito bom para dependências Javascript, como por exemplo babel. Na documentação tem muitas outras configurações que podem ser feitas pelo renovate.json.

Dica: Para ver os logs de execução do RenovateBot, você deve entrar no Dashboard. É um link bem escondido, mas para a gente ajudou bastante para poder ativar/desativar repositórios e também descobrir qual o motivo de alguma dependência não estar sendo identificada.

Análise estática de código (Linter)

O GitLab oferece embutido um analisador de código bem flexível, baseado na tecnologia do CodeClimate. Além de ser gratuito, é bem fácil de configurar e definir as regras de estilo de código. Recentemente o GitHub lançou o SuperLinter, mas para executar ele custa minutos de GitHub Actions, o que se tornaria caro também.

Dica: Deixe as regras de nomenclatura e estilo todas em arquivos de configuração das ferramentas (por exemplo: .eslintrc, .pylintrc, etc), inclusive as regras que configuram quais arquivos devem ser ignorados na análise. Deixe no .codeclimate.yml somente a configuração de qual engine está ativa ou não. A análise vai ser mais rápida e você vai ter menos dor de cabeça ao tentar debugar alguma inconsistência.

Últimos comentários e detalhes

A interface do GitLab não atualiza automaticamente (Hot Reload) quando alguma interação nova acontece em uma Issue ou Merge Request. Ter que atualizar a página manualmente para ver novos comentários e etc tem incomodado um pouco.

Definir Code Review como algo obrigatório nas Merge Requests também é um recurso somente dos planos pagos. Como temos uma cultura forte na Mercos, não precisamos da obrigatoriedade, todos já conhecem o processo e valorizam essa prática.

Todos os nossos repositórios OpenSource continuam no GitHub, pois as limitações que encontramos no GitHub não existem para repositórios OpenSource, que tem acesso gratuito a todos os recursos.

Próximos passos

Ainda precisamos explorar melhor os benefícios da integração do GitLab com Kubernetes. Os recursos que parecem mais promissores são Review Apps e Deploy Boards.

Review Apps é um recurso do GitLab-CI que cria, para cada branch, um ambiente onde o código daquela branch é publicado e fica disponível para testes manuais. Configuramos por quanto tempo aquele ambiente deve continuar disponível e depois desse período ele apaga o ambiente. Parece muito interessante para o pessoal de produto testar alguma feature pequena ou correção antes do deploy, e também para atualizações de dependências de Front que precisem de testes manuais.

Deploy Boards é um recurso do GitLab-CI que mostra dentro do GitLab um Deployment do Kubernetes sendo aplicado, Pod por Pod, para que qualquer desenvolvedor possa acompanhar seu deploy sem precisar acessar outra ferramenta. Junto com esse recurso vem de brinde monitoramento de Logs da aplicação e, se tiver um Prometheus instalado no cluster, também vem gráficos de monitoramento da aplicação automaticamente.

Conclusão

A migração do GitHub para o GitLab foi bem tranquila para a Mercos. Aprendemos que migrar a hospedagem de código fonte não é um bicho de sete cabeças como poderia parecer. Recomendamos o GitLab para empresas que precisarem cortar custos ou que buscam por mais recursos nativos na hospedagem de código-fonte.

Conseguimos manter todos os principais recursos do nosso workflow, que antes eram produtos separados, em recursos nativos do GitLab. Tivemos que nos adaptar em relação à gestão de Issues e Boards, mas é uma limitação que nos força a ser mais organizados.

Em termos de inovações, o GiLab tem recursos muito interessantes quando integrado com clusters Kubernetes, que pode ser muito útil para quem já começou a abraçar esse mundo.

Para repositórios OpenSource, concluímos que a melhor alternativa ainda é o GitHub pois fica totalmente gratuito e a grande maioria dos projetos OpenSource já está lá, o que facilita contribuições da comunidade.

--

--