Como construír un desenvolvemento interno completo usando a experiencia DevOps - VTB

As prácticas de DevOps funcionan. Nós mesmos estabamos convencidos diso cando reducimos 10 veces o tempo de instalación da versión. No sistema FIS Profile, que usamos en VTB, a instalación leva agora 90 minutos en lugar de 10. O tempo de compilación do lanzamento diminuíu de dúas semanas a dous días. O número de defectos de implementación persistentes baixou case ao mínimo. Para fuxir do "traballo manual" e eliminar a dependencia do vendedor, tivemos que traballar con muletas e atopar solucións inesperadas. Debaixo do corte hai unha historia detallada sobre como creamos un desenvolvemento interno completo.

Como construír un desenvolvemento interno completo usando a experiencia DevOps - VTB
 

Prólogo: DevOps é unha filosofía

Durante o ano pasado, fixemos moito traballo para organizar o desenvolvemento interno e a implementación das prácticas de DevOps en VTB:

  • Creamos procesos de desenvolvemento interno para 12 sistemas;
  • Puxemos en marcha 15 oleodutos, catro dos cales foron postos en produción;
  • 1445 escenarios de proba automatizados;
  • Implementamos con éxito unha serie de versións preparadas por equipos internos.

Un dos máis difíciles de organizar o desenvolvemento interno e a implementación das prácticas DevSecOps resultou ser o sistema de perfil FIS, un procesador de produtos de venda polo miúdo nun DBMS non relacional. Non obstante, puidemos construír o desenvolvemento, lanzar o pipeline, instalar paquetes individuais sen lanzamento no produto e aprendemos a montar versións. A tarefa non foi fácil, pero interesante e sen restricións obvias na implementación: aquí está o sistema: cómpre construír un desenvolvemento interno. A única condición é utilizar o CD antes que un ambiente produtivo.

Ao principio, o algoritmo de implementación parecía sinxelo e claro:

  • Desenvolvemos coñecementos de desenvolvemento inicial e alcanzamos un nivel aceptable de calidade do equipo de código sen defectos graves;
  • Integramos nos procesos existentes na medida do posible;
  • Para transferir código entre etapas obvias, cortamos unha canalización e empuxamos un dos seus extremos na continuación.

Durante este tempo, o equipo de desenvolvemento do tamaño necesario debe desenvolver habilidades e aumentar a participación da súa contribución aos lanzamentos a un nivel aceptable. E xa está, podemos considerar a tarefa rematada.

Parece que este é un camiño completamente eficiente enerxéticamente cara ao resultado esixido: aquí está DevOps, aquí están as métricas de rendemento do equipo, aquí está a experiencia acumulada... Pero na práctica, recibimos outra confirmación de que DevOps segue sendo filosofía. , e non "anexado ao proceso gitlab, ansible, nexus e máis abaixo na lista".

Despois de analizar de novo o plan de acción, decatámonos de que estábamos construíndo unha especie de provedor externo dentro de nós. Polo tanto, ao algoritmo descrito anteriormente engadiuse a reenxeñaría de procesos, así como o desenvolvemento da experiencia ao longo de toda a ruta de desenvolvemento para acadar un papel protagonista neste proceso. Non é a opción máis doada, pero este é o camiño do desenvolvemento ideoloxicamente correcto.
 

Onde comeza o desenvolvemento interno? 

Non era o sistema máis amigable co que traballar. Arquitectónicamente, era un gran DBMS non relacional, constaba de moitos obxectos executables separados (scripts, procedementos, lotes, etc.), que eran chamados segundo era necesario e funcionaba co principio dunha caixa negra: recibe unha solicitude e emite problemas. unha resposta. Outras dificultades a destacar son:

  • Linguaxe exótica (MUMPS);
  • Interface de consola;
  • Falta de integración con ferramentas e marcos de automatización populares;
  • Volume de datos en decenas de terabytes;
  • Carga de máis de 2 millóns de operacións por hora;
  • Importancia: crítica empresarial.

Ao mesmo tempo, non había un repositorio de código fonte do noso lado. En todo. Había documentación, pero todos os coñecementos e competencias clave estaban do lado dunha organización externa.
Comezamos a dominar o desenvolvemento do sistema case desde cero, tendo en conta as súas características e a baixa distribución. Comezou en outubro de 2018:

  • Estudou a documentación e os fundamentos da xeración de código;
  • Estudamos o curso curto sobre desenvolvemento recibido do vendedor;
  • Dominar as habilidades iniciais de desenvolvemento;
  • Elaboramos un manual de formación para novos membros do equipo;
  • Acordamos incluír o equipo en modo "combate";
  • Resolveuse o problema co control de calidade do código;
  • Organizamos un stand para o desenvolvemento.

Pasamos tres meses desenvolvendo coñecementos e mergullándonos no sistema, e desde principios de 2019, o desenvolvemento interno comezou o seu movemento cara a un futuro brillante, ás veces con dificultade, pero con confianza e propósito.

Migración do repositorio e autotests

A primeira tarefa de DevOps é o repositorio. Axiña acordamos proporcionar acceso, pero foi necesario migrar desde o SVN actual cunha rama troncal ao noso destino Git coa transición a un modelo de varias ramas e desenvolvemento de Git Flow. Tamén temos 2 equipos con infraestrutura propia, ademais de parte do equipo do vendedor no estranxeiro. Tiven que vivir con dous Gits e garantir a sincronización. En tal situación, era o menor dos dous males.

A migración do repositorio aprazouse repetidamente; só se completou en abril, coa axuda de compañeiros da primeira liña. Con Git Flow, decidimos manter as cousas sinxelas para comezar e decidimos establecer o esquema clásico con hotfix, desenvolvemento e lanzamento. Decidiron abandonar o mestre (tamén coñecido como prod). A continuación explicaremos por que esta opción resultou ser a óptima para nós. Utilizouse como traballador un repositorio externo pertencente ao vendedor, común para dous equipos. Sincronizouse co repositorio interno segundo unha programación. Agora con Git e Gitlab era posible automatizar procesos.

O problema das probas automáticas resolveuse con sorprendente facilidade: proporcionáronnos un marco preparado. Tendo en conta as peculiaridades do sistema, chamar a unha operación separada era unha parte comprensible do proceso empresarial e, ao mesmo tempo, servía de proba unitaria. Só restaba preparar os datos da proba e establecer a orde desexada de chamar aos guións e avaliar os resultados. A medida que se cubriu a lista de escenarios, formada en base a estatísticas de operación, a criticidade dos procesos e a metodoloxía de regresión existente, comezaron a aparecer probas automáticas. Agora poderíamos comezar a construír o gasoduto.

Como foi: o modelo antes da automatización

O modelo existente do proceso de implementación é unha historia separada. Cada modificación foi transferida manualmente como un paquete de instalación incremental separado. A continuación veu o rexistro manual en Jira e a instalación manual en ambientes. Para os paquetes individuais, todo parecía claro, pero coa preparación do lanzamento, as cousas foron máis complicadas.

A montaxe realizouse a nivel de entregas individuais, que eran obxectos independentes. Calquera cambio é unha nova entrega. Entre outras cousas, engadíronse 60-70 versións técnicas aos 10-15 paquetes da composición principal do lanzamento: versións obtidas ao engadir ou excluír algo do lanzamento e que reflicten os cambios nas vendas fóra dos lanzamentos.

Os obxectos dentro das entregas superponíanse entre si, especialmente no código executable, que era menos da metade único. Había moitas dependencias tanto do código xa instalado como daquel cuxa instalación se acababa de planificar. 

Para obter a versión requirida do código, foi necesario seguir estrictamente a orde de instalación, durante a cal os obxectos foron fisicamente reescritos moitas veces, unhas 10-12 veces.

Despois de instalar un lote de paquetes, tiven que seguir manualmente as instrucións para inicializar a configuración. A versión foi montada e instalada polo vendedor. A composición do lanzamento aclarouse case antes do momento da implantación, o que supuxo a creación de paquetes de "desacoplamento". Como resultado, unha parte importante dos suministros pasou de lanzamento a lanzamento coa súa propia cola de "desacoplamentos".

Agora está claro que con este enfoque -ensamblar o puzzle de lanzamento a nivel de paquete- unha única rama mestra non tiña significado práctico. A instalación en produción levou entre unha e media e dúas horas de traballo manual. É bo que polo menos a nivel de instalador se especificase a orde de procesamento de obxectos: introducíronse campos e estruturas antes dos datos para eles e procedementos. Non obstante, isto só funcionou nun paquete separado.

O resultado lóxico deste enfoque foron os defectos de instalación obrigatorios en forma de versións tortas de obxectos, código innecesario, instrucións que faltan e influencias mutuas non contabilizadas dos obxectos, que foron eliminados febrilmente despois do lanzamento. 

Primeiras actualizacións: commit montaxe e entrega

A automatización comezou transmitindo código a través dunha tubería ao longo desta ruta:

  • Recolle a entrega acabada do almacén;
  • Instalalo nun ambiente dedicado;
  • Executar autotests;
  • Avaliar o resultado da instalación;
  • Chame á seguinte canalización ao lado do comando de proba.

A seguinte canalización debe rexistrar a tarefa en Jira e esperar a que os comandos sexan distribuídos nos bucles de proba seleccionados, que dependen do momento da implementación da tarefa. Trigger - unha carta sobre a preparación para a entrega a un determinado enderezo. Esta, por suposto, era unha muleta obvia, pero tiven que comezar por algún lado. En maio de 2019, a transferencia de código comezou coas comprobacións dos nosos contornos. O proceso comezou, só queda poñelo en forma decente:

  • Cada modificación realízase nunha rama separada, que corresponde ao paquete de instalación e fusiona coa rama mestra de destino;
  • O disparador do lanzamento do pipeline é a aparición dunha nova confirmación na rama mestra mediante unha solicitude de combinación, que pechan os mantedores do equipo interno;
  • Os repositorios sincronízanse unha vez cada cinco minutos;
  • Iníciase a montaxe do paquete de instalación utilizando o ensamblador recibido do vendedor.

Despois disto, xa existían pasos para comprobar e transferir o código, para lanzar a tubería e montar do noso lado.

Esta opción lanzouse en xullo. As dificultades da transición provocaron certa insatisfacción entre o vendedor e a primeira liña, pero durante o mes seguinte conseguimos eliminar todas as asperezas e establecer un proceso entre os equipos. Agora temos montaxe por compromiso e entrega.
En agosto, conseguimos completar a primeira instalación dun paquete separado en produción usando o noso pipeline, e desde setembro, sen excepción, todas as instalacións de paquetes individuais non liberados realizáronse a través da nosa ferramenta de CD. Ademais, conseguimos conseguir unha parte das tarefas internas nun 40 % da composición do lanzamento cun equipo máis pequeno que o provedor; este é un éxito definitivo. A tarefa máis seria quedou: montar e instalar a versión.

A solución final: paquetes de instalación acumulativos 

Entendemos perfectamente que escribir as instrucións do fornecedor era unha automatización tan así; tivemos que repensar o proceso en si. A solución era obvia: recoller unha subministración acumulada da rama de lanzamento con todos os obxectos das versións requiridas.

Comezamos coa proba de concepto: montamos a man o paquete de lanzamento segundo o contido da implementación pasada e instalámolo nos nosos ambientes. Todo funcionou, o concepto resultou viable. A continuación, resolvemos o problema de escribir a configuración de inicialización e incluílos na confirmación. Preparamos un novo paquete e probámolo en ambientes de proba como parte da actualización do contorno. A instalación foi exitosa, aínda que con unha ampla gama de comentarios do equipo de implementación. Pero o principal é que nos deron o visto e prace para entrar en produción na versión de novembro coa nosa montaxe.

Cando quedaba pouco máis dun mes, o material escollido a dedo deixaba entrever claramente que o tempo se esgotaba. Decidiron facer a compilación desde a rama de lanzamento, pero por que debería separarse? Non temos un Prod e as sucursais existentes non son boas: hai moito código innecesario. Necesitamos cortar con urxencia os produtos, e isto é máis de tres mil compromisos. Montar a man non é unha opción en absoluto. Esbozamos un script que se executa no rexistro de instalación do produto e recolle commits para a rama. A terceira vez funcionou correctamente, e despois de "acabar cun ficheiro" a rama estaba lista. 

Escribimos o noso propio constructor para o paquete de instalación e rematamos nunha semana. Despois tivemos que modificar o instalador desde a funcionalidade principal do sistema, xa que é de código aberto. Despois dunha serie de comprobacións e modificacións, o resultado foi considerado exitoso. Mentres tanto, tomaba forma a composición do lanzamento, para a correcta instalación da cal era necesario aliñar o circuíto de proba co de produción, e para iso escribiuse un guión separado.

Por suposto, houbo moitos comentarios sobre a primeira instalación, pero en xeral o código funcionou. E despois da terceira instalación, todo comezou a ter un bo aspecto. O control de composición e o control de versións dos obxectos monitorizáronse por separado en modo manual, o que nesta fase estaba bastante xustificado.

Un reto adicional foi a gran cantidade de non lanzamentos que había que ter en conta. Pero coa rama tipo Prod e Rebase, a tarefa fíxose transparente.

Primeira vez, rápido e sen erros

Achegámonos á estrea cunha actitude optimista e máis dunha ducia de instalacións exitosas en diferentes circuítos. Pero, literalmente, un día antes do prazo, resultou que o vendedor non concluíu o traballo para preparar a versión para a instalación da forma aceptada. Se por algún motivo a nosa compilación non funciona, a versión interromperase. Ademais, a través dos nosos esforzos, que é especialmente desagradable. Non tiñamos xeito de retirarnos. Por iso, pensamos en opcións alternativas, elaboramos plans de acción e comezamos a instalación.

Sorprendentemente, todo o lanzamento, composto por máis de 800 obxectos, comezou correctamente, a primeira vez e en só 10 minutos. Pasamos unha hora comprobando os rexistros buscando erros, pero non atopamos ningún.

Todo o día seguinte houbo silencio no chat de lanzamento: sen problemas de implementación, versións tortas ou código "inapropiado". Mesmo foi dalgún xeito incómodo. Máis tarde xurdiron algúns comentarios, pero en comparación con outros sistemas e experiencias anteriores, o seu número e prioridade foron notablemente inferiores.

Un efecto adicional do efecto acumulado foi un aumento da calidade da montaxe e das probas. Debido ás múltiples instalacións da versión completa, identificáronse de forma oportuna os defectos de compilación e os erros de implantación. As probas en configuracións de versión completa permitiron identificar adicionalmente defectos na influencia mutua dos obxectos que non aparecían durante as instalacións incrementais. Definitivamente foi un éxito, especialmente tendo en conta a nosa contribución do 57% ao lanzamento.

Resultados e conclusións

En menos dun ano conseguimos:

  • Construír un desenvolvemento interno completo utilizando un sistema exótico;
  • Elimina a dependencia crítica dos provedores;
  • Lanza CI/CD para un legado moi antipático;
  • Elevar os procesos de implementación a un novo nivel técnico;
  • Reducir significativamente o tempo de implantación;
  • Reducir significativamente o número de erros de implementación;
  • Declárase con confianza como un experto en desenvolvemento líder.

Por suposto, gran parte do que se describe parece unha merda, pero estas son as características do sistema e as limitacións do proceso que existen nel. Polo momento, os cambios afectaron aos produtos e servizos do perfil do IS (contas mestres, tarxetas plásticas, contas de aforro, depósito en garantía, préstamos en efectivo), pero potencialmente o enfoque pode aplicarse a calquera SI para o que se estableza a tarefa de implementar prácticas DevOps. O modelo acumulativo pódese replicar con seguridade para implementacións posteriores (incluídas as que non sexan de lanzamento) de moitas entregas.

Fonte: www.habr.com

Engadir un comentario