Receitas TeamCity. Relatório Yandex.Taxi

Meu nome é Eduard Matsukov, estou criando o Taximeter - um aplicativo para drivers Yandex.Taxi. Estou envolvido em infraestrutura e tudo relacionado a ela. Há algum tempo, fiz um relatório - falei sobre a experiência da amizade do TeamCity com nosso projeto e com os desenvolvedores em geral. Uma parte separada do relatório é dedicada ao que Kotlin tem a ver com isso.


- Quase todos os dias eles vêm a mim pessoalmente e a nossos desenvolvedores com perguntas. E onde conseguir a montagem? E onde conseguir esse ramo? Por que algo caiu? Onde está o problema no meu código? Por que algo não está funcionando corretamente? Para fazer isso, temos muita infraestrutura auto-escrita no projeto, plugins, vários hacks e truques que usamos. Por um lado, tornar a vida mais fácil para o desenvolvedor, por outro lado, implementar tarefas de negócios específicas.





E, em algum momento, é claro, também usamos o CI e o TeamCity. Ficamos confusos - ensinamos o TeamCity a ser amigo de Kotlin e elevamos, podemos dizer, todo o IC e toda a assembléia a um nível totalmente novo.

Mas primeiro, um pouco de história - para entender como chegamos a isso e por que esse nível eu chamo de cânone separado. O TeamCity existe no Yandex há muitos anos. Tivemos que morar nesse servidor compartilhado, onde todo o back-end, todo o front-end e, mais recentemente, todos os aplicativos móveis estão hospedados. Cerca de dois anos atrás, todos nós nos reunimos. E cada desenvolvedor configura cada projeto nem mesmo como ele quer, mas como ele pode ou até onde ele entende o quanto ele quer entender o sistema. E não há uma pessoa que saiba tudo e saiba como. Poucas pessoas querem se incomodar, estudar modelos separadamente, o TeamCity Wilds. Portanto, todo mundo está vendo, quem é o quanto.

Moramos nesse servidor único e, no ano passado, tivemos um acidente no TeamCity. Cerca de uma semana foi um tempo de inatividade completo. As assembléias não foram coletadas, os testes estavam constantemente reclamando. Alguém inventou, coletou localmente.



Isso se deve ao fato de que nosso servidor TeamCity era, grosso modo, uma solução até o joelho que de repente se transformou em um ótimo serviço. É usado por milhares de desenvolvedores no Yandex. Obviamente, havia algum tipo de tolerância a falhas, mas também recusava. Na próxima vez em que o TeamCity foi atualizado após a reinicialização, vários discos rígidos simplesmente entraram em colapso e não pudemos subir novamente. Eu tive que sair.

Precisamos tirar conclusões de tudo o que aconteceu. E, é claro, tiramos essas conclusões: analisamos por que isso aconteceu e como garantir que isso não aconteça novamente.

Antes de tudo, é importante que subamos por muito tempo e restauremos nosso serviço. Por serviço, entendo um processo técnico e parcialmente um processo comercial para a entrega banal de liberações, para a montagem de solicitações de pool. Perdemos muitos artefatos, incluindo compilações de versão, perdemos muito tempo em solicitações de pool, no fato de que o teste não podia fazer seu trabalho corretamente. E, é claro, passamos bastante tempo restaurando o projeto do zero, reconfigurando toda a estrutura, todo o sistema de compilação. E então percebemos que era hora de mudar alguma coisa e configurar nosso próprio servidor.

Fomos a isso por um longo tempo. Para não dizer que apenas um acidente levou a essa conclusão. Em geral, decidimos que era hora de ir para a montanha, fazer tudo isso sozinhos. Iniciamos um lançamento de serviço. Isso é feito com extrema rapidez: alguns dias e pronto. Quando você implanta tudo isso sozinho e pode se aprofundar no assunto, administrar um pouco, então os recursos interessantes são impressionantes. Um deles - o novo TeamCity permite configurar o controle de versão.



O controle de versão é muito primitivo, mas ao mesmo tempo muito confiável, bonito e legal. Tudo o que é armazenado no TeamCity em relação ao seu ou a qualquer outro projeto pode ser carregado com segurança no Git, e você pode viver feliz com ele. Mas existem alguns problemas.

O primeiro problema é que todas as pessoas estão acostumadas a trabalhar com o TeamCity exclusivamente por meio da interface, e esse hábito é difícil de erradicar. Há um pequeno truque aqui: você pode simplesmente proibir qualquer alteração na interface e forçar todas as pessoas a reaprender. Nossa equipe tem 2.000 desenvolvedores. Não é um bom caminho, é?

De fato, os contras terminam aí. O menos importante é que as pessoas precisam reaprender para algo novo. Portanto, eles precisam ser fundamentados para tirar uma conclusão pessoal sobre por que isso é necessário. E é necessário, então, que o TeamCity, graças ao controle de versão, não permita aplicar alterações que de alguma forma quebrem o sistema. O TeamCity em si recorre à mais recente revisão estável.



No TeamCity, você pode iniciar cada projeto para esse controle de versão e configurá-lo de maneira bastante flexível.



Um pouco de programa educacional. Todos os projetos no TeamCity são organizados em uma árvore. Existe algum tipo de raiz comum e, mais adiante, vem uma estrutura tão simples. Cada projeto é o topo deste gráfico. Ele pode atuar como um determinado conjunto de configurações que constroem algo e como pai de outros projetos.



No Git, você pode enviar tudo de uma vez ou uma peça específica. Por exemplo, se colegas do back-end com o front-end não desejam usar versionamento, não é possível contar com eles e simplesmente proteger seu projeto pessoal.



Você pode configurar um sistema hierárquico bastante complexo, ao qual nossa equipe chegou finalmente. Temos uma raiz grande comum e algumas raízes pequenas. Back-end, desenvolvimento móvel, front-end, Yandex.Food - todos eles vivem cada um em seu próprio repositório separado. Ao mesmo tempo, as informações sobre todos esses projetos são armazenadas em um grande repositório compartilhado - na raiz.

Depois que você finalmente conectar esse controle de versão, instale-o com todos os seus colegas, onde quem e como viverá e quem estará envolvido no suporte - depois de tudo isso, é necessário fazer uma escolha difícil.



O TeamCity suporta apenas dois formatos de configurações. Com XML, suspeito que ninguém queira trabalhar, por isso escolhemos o segundo formato. Ele permite que você faça essas configurações em um script Kotlin.



A TeamCity cria um projeto de preparação, uma aparência de qualquer projeto comum. Você pode fazer uma de duas coisas: fazer upload no seu projeto (Android, back-end, isso não importa) ou deixá-lo como um projeto independente. Então você terá um repositório independente com um projeto independente.



Qual é a vantagem dessa abordagem? Pessoalmente, eu e aqueles caras que lidamos com nossa infraestrutura no backend e no frontend fomos imediatamente subornados por algo. E mesmo aqueles que não conhecem Kotlin, que ouviram falar pela primeira vez, foram e começaram a ensiná-lo.



Essas duas linhas criam o projeto inteiro. Este é o dialeto da API do TeamCity. A API altera todas as versões principais. Existem 2018-2, 2018-1, 2017, etc. Em breve, esperamos que o 2019 seja lançado.

A segunda linha simplesmente declara o projeto.



Aqui está o próprio projeto. Este é um código absolutamente real. É assim que o nosso repositório raiz se parece agora. Nada extra, nada complicado. O único trabalho manual necessário aqui é criar manualmente o UUID. O TeamCity exige que cada objeto, cada projeto tenha seu próprio identificador exclusivo. Você pode escrever qualquer coisa lá. Eu apenas uso o apelido padrão da equipe uuidgen.

Aqui começa a aventura no Kotlin DSL. Eu acho que essa é uma linguagem completamente simples para dominar. Ao fazer o upload para o IDEA, Eclipse ou qualquer outro IDE, você pode obter toda a documentação, destaque, preenchimento automático, dicas. De fato, muitos deles estão ausentes na interface. Portanto, minha experiência pessoal diz que trabalhar com o código é muito mais conveniente, mais simples e mais intuitivo. Ainda somos desenvolvedores.



Algo assim parece uma configuração real, agora funcionando ao mesmo tempo, suportando as configurações do TeamCity. Ou seja, o TeamCity cria suas próprias configurações em seu próprio ambiente. Se tudo estiver bem e tudo der errado, ele calmamente o envia na memória e replica as alterações no PostgreSQL. A base já está conectada ao próprio serviço. E aqui será pecado não usar todos os recursos do Kotlin.



Nesse caso, diferentemente do XML, essas configurações podem ser descritas usando polimorfismo, herança - todos os recursos da linguagem Kotlin são permitidos. O único ponto importante é que tudo isso pode se transformar em caos antes de introduzirmos a versão das configurações no script Kotlin.



Mas, curiosamente, esse caos se tornou muito menor. Porque antes não era muito óbvio como fazer o que eu quero, como conseguir esse ou aquele recurso? Pelo código, na minha prática, é muito mais fácil entender como implementar qualquer recurso.

As aventuras mais interessantes começam aqui: como implementamos algumas coisas e como, em princípio, facilita a interação do projeto com o TeamCity?

Todos os presentes aqui, de uma forma ou de outra, estão preparando uma liberação, participando de sua assembléia, na publicação. Publicamos nossos lançamentos em vários canais no Google Play.





Temos beta, existem experimentos, é estável. Usamos um plug-in especial com um robô que publica comentários com um relatório sobre a compilação do release no ticket de lançamento. E tudo isso é configurado com uma janela tão bonita. Aparece assim que você tenta criar um release. Essas perguntas não podem ser evitadas.



Na interface do TeamCity, é algo parecido com isto. Para entender imediatamente o que, onde, onde e como, você precisa ler cada parâmetro, precisa experimentar. A partir da documentação, além do que é visível na tela, nada mais pode ser obtido.



No código, fica assim. Pelo menos até agora, por meio ano, ninguém chegou e perguntou: como faço para criar algum recurso? Na maioria das vezes, a partir do código, tudo é intuitivamente claro.



Ao mesmo tempo, algumas coisas são feitas de maneira bastante simples, mas ocultas por trás de várias camadas da interface. Temos que andar, ir e voltar.



Aqui está um exemplo de como a segurança é implementada no TeamCity. Na minha prática, para a maioria das pessoas, o TeamCity parece ser um sistema frio bastante simples que pronto para uso não suporta integração, por exemplo, com serviços de segurança. Portanto, todos os tokens, todas as chaves, todas as credenciais conosco geralmente ficam em aberto. Porque não

De fato, o TeamCity está seguro. Ele sabe como criar seu próprio arquivo especial em seu servidor, chamado credential json, como mostrado. E ele cria uma chave para cada token, para cada credencial, que geramos especialmente por meio da interface. Você já pode inseri-lo no código e garantir que essa credencial nunca apareça nos logs do TeamCity ou na interface do TeamCity. O sistema pode cortar essas chaves literalmente de qualquer lugar. Toda a interface é, grosso modo, um tipo de decoração.



Ok, configuramos alguns de nossos parâmetros, fizemos o encaminhamento dos parâmetros necessários, por exemplo, para compilar o release. Mas e se quisermos ir mais longe? E nós queríamos ir mais longe. Durante a montagem, várias etapas diferentes são iniciadas. Nós executamos várias bibliotecas aninhadas que são construídas a partir de repositórios completamente diferentes. E só queríamos fazer novas mudanças. Tudo isso é agora. Não se preocupe - por exemplo, não colete uma biblioteca auxiliar para solicitações de pool, não faça o upload para o repositório maven, não inclua gestos adicionais na solicitação de pool.



Acabamos de montar o conjunto da corrente. Mostrarei até o final como é óbvio e inconveniente fazer isso a partir da interface, na minha opinião pessoal. E já julgue por si mesmo.

É assim que o conjunto da cadeia na interface se parece.



Parece algo assim no código. Simplesmente indicamos exatamente qual configuração depende e o que fazer se alguma das configurações não funcionou ou foi cancelada pelo usuário externamente. Nesse caso, não quero que a montagem comece. Porque qual é o sentido disso se não coletamos todas as bibliotecas dependentes?

Com o mesmo espírito, todas as outras coisas estão sendo feitas. E todo o projeto no TeamCity leva literalmente 500 linhas de código.



Acontece que você pode encaminhar algum parâmetro interessante por todas as dependências. Eu mostrei o encadeamento por uma razão. Cadeias é conveniente, mas difícil de preparar na interface. E o TeamCity não documenta um recurso tão importante como o encaminhamento através de parâmetros. Para que é isso? Suponha que, em nossa compilação em Gradle ou em outro lugar, queremos ficar vinculados a algum campo específico, encaminhar o mesmo endereço para o ticket de lançamento. E queremos fazer isso uma vez, e não para cada montagem aninhada.



O TeamCity possui um parâmetro não tão óbvio e completamente não documentado - reverse.dep (dependência reversa). Ele lança todos os parâmetros que vêm após o asterisco em todas as construções aninhadas.


Na saída, temos uma estrutura tão simples. Você pode complicar e tornar o ninho tão profundo quanto sua imaginação ou necessidades. E para ter certeza de que em todas essas dependências, em todas essas configurações, todos os nossos parâmetros que esperamos em cada etapa da montagem serão encaminhados. Pronto para responder às suas perguntas. Obrigado a todos!

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


All Articles