Actualización del proceso de CI / CD: preparación y planificación

imagen

En 2020, probablemente sea bastante difícil encontrar un proyecto en una descripción de pila que no tenga una de las siguientes palabras: IaC, microservicios, kubernetes, docker, aws / azure / gcloud, blockchain, ML, VR, etc. ¡Y eso es genial! El progreso no se detiene. Estamos creciendo, nuestros proyectos están creciendo con nosotros, aparecen herramientas más convenientes y funcionales que resuelven problemas modernos.

Hola. Entonces quería comenzar este artículo. Pero luego revisé algunas cosas, hablé con mis colegas y me di cuenta de que estaría equivocado. Todavía hay proyectos que ya tienen más de 15 años, con gerentes y participantes que son viejos creyentes, y en consecuencia estos proyectos tienen una pila de tecnología antigua que es bastante difícil de mantener en un zoológico existente. Y por alguna razón, este proyecto no se puede actualizar a nivel mundial (el cliente está estancado, no hay actualización, el proyecto es muy grande y la migración se retrasa, o todos están contentos con todo), y hay que apoyarlo. Aún más desagradable cuando un proyecto similar todavía se está desarrollando activamente. Es como una bola de nieve. El cliente y el público requieren características, el código requiere entrega, los servidores requieren atención y cuidado ... Pero el bitpack, por lo tanto, en general, dejó de admitir mercurio. Se propone tal caso para su consideración.

Lo que se considerará: convertir mercurial-git, mover CI de CruiseControl.NET a TeamCity, de git-implementación a Octopus con una pequeña descripción de todo el proceso.

El texto resultó mucho, por lo que se dividirá en partes separadas para facilitar la percepción. Habrá una tabla de contenidos.
Parte 1: qué es, por qué no es así, planificar, una pequeña fiesta. Yo llamaría a esta parte casi técnica.
Parte 2: teamcity.
Parte 3: despliegue de pulpo.
Parte 4: detrás de escena. Momentos desagradables, planes para el futuro, posiblemente preguntas frecuentes. Lo más probable es que también se le pueda llamar casi técnico.

No llamaría a esto una guía para la repetición por muchas razones: inmersión insuficiente en los procesos del proyecto debido a la falta de tiempo, práctica insuficiente de tales cosas, un enorme monolito en el que todos los subproyectos están estrechamente entrelazados y un montón de otros matices que te hacen arder, preguntarte, soportarlos. , pero en ningún caso no por favor. Y también, debido a las características del proyecto (es bastante único), algunos pasos se adaptarán exclusivamente para este caso.

Introducción clásica


Teníamos un repositorio mercurial, más de 300 (¡abiertos!) Brunches, ccnet, otro ccnet + git (para implementaciones) y una gran cantidad de módulos de proyecto con nuestras propias configuraciones y clientes individuales, cuatro entornos y una gran cantidad de grupos en IIS, así como cmd scripts, SQL, más de quinientos dominios, dos docenas de compilaciones y desarrollo activo además. No es que todo esto fuera necesario, pero funcionó, y fue inconveniente y largo. Lo único que me preocupaba era la presencia de otros proyectos que requerían mi atención. Nada en el proceso de trabajar con tareas de esta magnitud es más peligroso que la falta de concentración e interrupción.

Sabía que tarde o temprano tendría que prestar atención a otras tareas, y es por eso que pasé una gran cantidad de tiempo estudiando la infraestructura existente para que al menos no hubiera problemas sin resolver.

Desafortunadamente, no puedo dar una descripción completa del proyecto, debido a la NDA, por lo que se considerarán los puntos técnicos generales. Todos los nombres relacionados con el proyecto también serán pintados. Pido disculpas por la mancha negra en las capturas de pantalla.

Una de las características clave del proyecto es que tiene una serie de módulos que tienen un núcleo, pero difieren en sus configuraciones. También hay módulos con un enfoque "especial", diseñados para revendedores y especialmente para grandes clientes. Un módulo puede servir a más de un cliente. Un cliente debe entenderse como una organización separada o grupo de personas que obtienen acceso a un módulo específico. Cada cliente obtiene acceso en su propio dominio, tiene su propio diseño y su propia configuración predeterminada única. El cliente se identifica por el dominio que utiliza.

El esquema general de esta parte del proyecto se puede representar de la siguiente manera:


Como puede ver, el núcleo se usa igual en todas partes, y esto se puede usar.

Razones por las cuales surgió la tarea de revisar y actualizar los procesos de CI / CD:

  1. CruiseControl.NET se utilizó como sistema de compilación. Trabajar con él es un dudoso placer en principio. Configuraciones XML en múltiples pantallas, un montón de dependencias y configuraciones de enlace entre sí, falta de soluciones modernas a problemas modernos.
  2. Algunos desarrolladores (principalmente clientes potenciales) en el proyecto deben tener acceso a los servidores de compilación, y a veces les gusta cambiar las configuraciones de ccnet que no deben cambiarse. Adivina qué pasa después. Debe tener una administración de derechos simple y conveniente en el sistema de CI, sin quitar el acceso de los desarrolladores al servidor. En pocas palabras, no hay configuración de texto: no hay ningún lugar para escalar con manos juguetonas.
  3. - … CCNET, git. (. ).
  4. , . , . 
  5. - , — ( ) .
  6. . ? ? ? .
  7. Uso subóptimo de recursos y un proceso desactualizado de construcción y entrega de código.

Figura del párrafo 3:


En la etapa de planificación, se decidió utilizar Teamcity como sistema de compilación y Octopus como sistema de implementación. La infraestructura "de hierro" del cliente se ha mantenido sin cambios: servidores dedicados separados para desarrollo, prueba, preparación y producción, así como servidores revendedores (principalmente entornos de producción).

El cliente recibió una Prueba de concepto en el ejemplo de uno de los módulos, se escribió un plan de acción, se llevaron a cabo trabajos preparatorios (instalación, configuración, etc.). Probablemente no tenga sentido describir esto. Cómo instalar Team City se puede leer en el sitio web oficial. Me detendré por separado en algunos requisitos formulados para el nuevo sistema:

  1. Fácil mantenimiento con todas las consecuencias (copias de seguridad, actualizaciones, resolución de problemas, si las hay).
  2. Universalidad Idealmente, desarrolle un esquema general según el cual todos los módulos se ensamblen y entreguen, y úselo como plantilla.
  3. Minimice el tiempo para agregar nuevas configuraciones de compilación y mantenimiento. Los clientes se agregan / eliminan. A veces se hace necesario hacer nuevas configuraciones. Es necesario que al crear un nuevo módulo no haya demoras en la configuración de su entrega.

Aproximadamente en este punto, recordamos la interrupción del soporte para repositorios mercuriales con un bitbucket, y se agregó el requisito de transferir el repositorio a git mientras se preservaban las ramas y el historial de confirmaciones.

Preparación: conversión de repositorio


Parece que alguien claramente resolvió este problema antes que nosotros y en lugar de nosotros. Solo necesita encontrar una solución de trabajo preparada. La exportación rápida resultó no ser tan rápida. Además, no funcionó. Desafortunadamente, no quedan registros ni capturas de pantalla. El hecho es que no pudo. Bitbucket no proporciona su propio convertidor (pero podría). Un par de métodos más buscados en Google, y también por. Decidí escribir mis propios scripts, de todos modos este no es el único repositorio mercurial, será útil en el futuro. Aquí se presentarán los primeros desarrollos (porque aún permanecen en la misma forma). La lógica del trabajo se parece a esto:

  1. Tomamos la extensión mercurial hggit como base. 
  2. Obtenemos una lista de todas las ramas del repositorio mercurial. 
  3. Convertimos los nombres de las ramas (gracias a mercurial y a los desarrolladores por los espacios en los nombres de las ramas, gracias especiales por las diéresis y otros caracteres que agregan alegría a la vida).
  4. Haga marcadores (marcador de hg) e inserte en el repositorio intermedio. ¿Para qué? Porque bitbucket, y porque no puede crear un marcador con el mismo nombre que el nombre de la rama (por ejemplo, puesta en escena). 
  5. En el nuevo repositorio (ya git), elimine el postfix del nombre de la rama y migre hgignore a gitignore. 
  6. Empuje al repositorio principal.

Listado de comandos según puntos:

  1. $ cd /path/to/hg/repo
    $ cat << EOF >> ./.hg/hgrc
    [extensions]
    hggit=
    EOF
    
  2. $ hg branches > ../branches
    
  3. #!/usr/bin/env bash
    hgBranchList="./branches"
    sed -i 's/:.*//g' ${hgBranchList}
    symbolsToDelete=$(awk '{print $NF}' FS=" " ${hgBranchList} > sym_to_del.tmp)
     
    i=0
    while read hgBranch; do
      hgBranches[$i]=${hgBranch}
      i=$((i+1))
    done <${hgBranchList}
     
    i=0
    while read str; do
      strToDel[$i]=${str}
      i=$((i+1))
    done < ./sym_to_del.tmp
     
    for i in ${!strToDel[@]}
    do
      echo ${hgBranches[$i]} | sed "s/${strToDel[$i]}//" >> result.tmp
    done
     
    sed -i 's/[ \t]*$//' result.tmp
    sed 's/^/"/g' result.tmp > branches_hg
    sed -i 's/$/"/g' branches_hg
    sed 's/ /-/g' result.tmp > branches_git
    sed -i 's/-\/-/\//g' branches_git
    sed -i 's/-\//\//g' branches_git
    sed -i 's/\/-/\//g' branches_git
    sed -i 's/---/-/g' branches_git
    sed -i 's/--/-/g' branches_git
    rm sym_to_del.tmp
    rm result.tmp
    
  4. #!/usr/bin/env bash
    gitBranchList="./branches_git"
    hgBranchList="./branches_hg"
    hgRepo="/repos/reponame"
     
    i=0
    while read hgBranch; do
      hgBranches[$i]=${hgBranch}
      i=$((i+1))
    done <${hgBranchList}
     
    i=0
    while read gitBranch; do
      gitBranches[$i]=${gitBranch}
      i=$((i+1))
    done <${gitBranchList}
     
    cd ${hgRepo}
    for i in ${!gitBranches[@]}
    do
      hg bookmark -r "${hgBranches[$i]}" "${gitBranches[$i]}-cnv"
    done
     
    hg push git+ssh://git@bitbucket.org:username/reponame-temp.git
    echo "Done."
    
  5. #!/bin/bash
    # clone repo, run git branch -a, delete remotes/origin words to leave only branch names, delete -cnv postfix, delete default branch string because we can't delete it
    repo="/repos/repo"
    gitBranchList="./branches_git"
    defaultBranch="default-cnv"
    while read gitBranch; do   gitBranches[$i]=${gitBranch};   i=$((i+1)); done < $gitBranchList
    cd $repo
    for i in ${!gitBranches[@]}; do git checkout ${gitBranches[$i]}-cnv; done
    git checkout $defaultBranch
    for i in ${!gitBranches[@]}; do
        git branch -m ${gitBranches[$i]}-cnv ${gitBranches[$i]}
        git push origin :${gitBranches[$i]}-cnv ${gitBranches[$i]}
        git push origin -u ${gitBranches[$i]}
    done
    
  6. #!/bin/bash
    # clone repo, run git branch -a, delete remotes/origin words to leave only branch names, delete -cnv postfix, delete default branch string because we can't delete it
    repo="/repos/repo"
    gitBranchList="./branches_git"
    defaultBranch="default"
    while read gitBranch; do   gitBranches[$i]=${gitBranch};   i=$((i+1)); done < $gitBranchList
    cd $repo
    for i in ${!gitBranches[@]}; do
        git checkout ${gitBranches[$i]}
        sed -i '1d' .hgignore
        mv .hgignore .gitignore
        git add .
        git commit -m "Migrated ignore file"
    done
    

Trataré de explicar el significado de algunas acciones, a saber, el uso de un repositorio intermedio. Inicialmente, en el repositorio después de la conversión, los nombres de las ramas contienen el postfix "-cnv". Esto se debe a la función de marcador hg. Debe eliminar este postfix y también crear archivos gitignore en lugar de hgignore. Todo esto agrega historia y, por lo tanto, aumenta el tamaño del repositorio (e irrazonablemente). Como otro ejemplo, puedo citar lo siguiente: intente crear un repositorio y presione el primer commit a 300M con el código. Luego agréguelo a gitignore y empújelo sin él. Permanecerá en la historia. Ahora intenta eliminarlo del historial (git filter-branch). Con un cierto número de confirmaciones, el tamaño del repositorio resultante no disminuirá, sino que aumentará. Esto se resuelve mediante la optimización, pero no se puede iniciar en bitbucket.Se lleva a cabo solo al importar el repositorio. Por lo tanto, todas las operaciones aproximadas se llevan a cabo con un intermedio, y luego se realiza la importación a una nueva. El tamaño del repositorio intermedio en la final fue de 1.15G, y el tamaño de los 350M resultantes. 

Conclusión


Todo el proceso de migración se dividió en varias etapas, a saber:

  • preparación (demostración al cliente utilizando un ejemplo de una compilación, instalación de software, conversión de repositorio, actualización de configuraciones ccnet existentes);
  • Configuración de CI / CD para el entorno de desarrollo y sus pruebas (el sistema antiguo sigue funcionando en paralelo);
  • Configuraciones de CI / CD para los entornos restantes (en paralelo con el "bueno" existente) y pruebas;
  • desarrollo de migración, puesta en escena y prueba;
  • Migración de producción y transferencia de dominios de instancias IIS antiguas a nuevas.

La descripción de la fase preparatoria completada con éxito se está completando actualmente. Aquí no se logró un éxito grandioso, excepto que el sistema existente no se descompuso y se migró el repositorio mercurial en git. Sin embargo, sin una descripción de estos procesos, no habrá contexto para más partes técnicas. La siguiente parte describirá el proceso de configuración de un sistema de CI basado en teamcity.

All Articles