Manejo de múltiples sucursales en integración continua

85

He estado lidiando con el problema de escalar CI en mi empresa y al mismo tiempo tratando de averiguar qué enfoque tomar cuando se trata de CI y múltiples sucursales. Hay una pregunta similar en stackoverflow, Varias ramas de funciones e integración continua . Comencé uno nuevo porque me gustaría tener más discusión y proporcionar un análisis en la pregunta.

Hasta ahora, he descubierto que hay 2 enfoques principales que puedo tomar (¿o tal vez algunos otros?)

Entonces, parece que si quiero proporcionar a los desarrolladores CI para sus propias ramas personalizadas, necesito herramientas especiales para Jenkins (¿API o shellscripts o algo así?) Y manejar el escalado. O puedo decirles que se fusionen más a menudo con DEV y vivan sin CI en ramas personalizadas. ¿Cuál tomarías o hay otras opciones?

toomasr
fuente

Respuestas:

69

Cuando habla de escalar CI, realmente está hablando de escalar el uso de su servidor CI para manejar todas sus ramas de funciones junto con su línea principal. Inicialmente, esto parece un buen enfoque ya que los desarrolladores de una sucursal obtienen todas las ventajas de las pruebas automatizadas que incluyen los trabajos de CI. Sin embargo, tiene problemas para administrar los trabajos del servidor de CI (como ha descubierto) y, lo que es más importante, en realidad no está haciendo CI. Sí, está utilizando un servidor CI, pero no está integrando continuamente el código de todos sus desarrolladores.

Realizar CI real significa que todos sus desarrolladores se comprometen regularmente con la línea principal. Es fácil de decir, pero lo difícil es hacerlo sin romper tu aplicación. Le recomiendo encarecidamente que consulte la Entrega continua , especialmente la sección Mantener su aplicación liberable en el Capítulo 13: Administración de componentes y dependencias . Los puntos principales son:

  • Oculte la nueva funcionalidad hasta que esté terminada (también conocido como Alternar funciones ).
  • Realice todos los cambios de forma incremental como una serie de pequeños cambios, cada uno de los cuales es liberable.
  • Utilice la rama por abstracción para realizar cambios a gran escala en la base de código.
  • Utilice componentes para desacoplar partes de su aplicación que cambian a diferentes velocidades.

Se explican por sí mismos, excepto que se ramifican por abstracción. Este es solo un término elegante para:

  1. Cree una abstracción sobre la parte del sistema que necesita cambiar.
  2. Refactorice el resto del sistema para usar la capa de abstracción.
  3. Cree una nueva implementación, que no forma parte de la ruta del código de producción hasta que se completa.
  4. Actualice su capa de abstracción para delegar a su nueva implementación.
  5. Elimina la implementación anterior.
  6. Elimine la capa de abstracción si ya no es apropiada.

El siguiente párrafo de la sección Sucursales, corrientes e integración continua en el Capítulo 14: Control de versiones avanzado resume los impactos.

El enfoque incremental ciertamente requiere más disciplina y cuidado, y de hecho más creatividad, que crear una sucursal y sumergirse en la reestructuración y el desarrollo de nuevas funcionalidades. Pero reduce significativamente el riesgo de que sus cambios interrumpan la aplicación, y le ahorrará a usted y a su equipo una gran cantidad de tiempo al fusionarse, arreglar roturas y hacer que su aplicación esté en un estado de implementación.

Se necesita un gran cambio de mentalidad para renunciar a las ramas de funciones y siempre obtendrá resistencia. En mi experiencia, esta resistencia se basa en que los desarrolladores no se sienten seguros al cometer el código en la línea principal y esta es una preocupación razonable. Esto, a su vez, generalmente se debe a la falta de conocimiento, confianza o experiencia con las técnicas enumeradas anteriormente y posiblemente a la falta de confianza con sus pruebas automatizadas. El primero se puede resolver con capacitación y soporte para desarrolladores. Este último es un problema mucho más difícil de abordar, sin embargo, la ramificación no proporciona ninguna seguridad real adicional, solo pospone el problema hasta que los desarrolladores se sientan lo suficientemente seguros con su código.

Tom Howard
fuente
4
Tom, esto solo funciona bien si 1) tanto el lanzamiento como la actualización son relativamente fáciles 2) la mayoría de los cambios están bien aislados. Esto es cierto para los desarrolladores web, pero si está realizando lanzamientos de productos en caja, las versiones estables deben permanecer estables a toda costa, ya que las revisiones son realmente caras o incluso imposibles en un gran entorno corporativo.
Jevgeni Kabanov
13
CI real no se trata solo de la integración, también se trata de la retroalimentación
Anton Arhipov
3
Elegí esto como la respuesta (al menos di la recompensa, por favor avíseme si de alguna manera todavía necesito marcarlo como correcto) pero creo que esta no es una solución para mi problema. Escribí
toomasr
1
@Jevgeni Kabanov y @toomasr Parece que ambos asumen que hacer CI verdadera significa renunciar a la calidad y funciona solo para desarrolladores web, porque es muy fácil implementar correcciones. Supongo que lo que te preocupa es un compromiso poco fiable justo antes de un lanzamiento. Sí, esto puede resultar en una mala versión que puede ser costosa de arreglar. Sin embargo, una confirmación poco fiable en una rama de función justo antes de su lanzamiento es igualmente mala. Si cree que hay una diferencia, comparta su razonamiento. Una forma de combatir esto (si la confirmación fue en la línea principal o en una rama de función) es usar el enfoque de Entrega continua.
Tom Howard
1
Ah, y por cierto, durante los últimos 4 años mi principal experiencia de desarrollo ha sido en instituciones financieras. El imperativo de tener lanzamientos estables y el costo de hacerlo mal (sin mencionar el proceso de control de cambios por el que debe pasar para implementar una revisión) no es mucho mayor que eso. Un producto en caja sería un cambio relajante para mí.
Tom Howard
4

Establecería trabajos separados para cada rama. He hecho esto antes y no es difícil de administrar y configurar si ha configurado Hudson / Jenkins correctamente. Una forma rápida de crear varios trabajos es copiar de un trabajo existente que tenga requisitos similares y modificarlos según sea necesario. No estoy seguro de si desea permitir que cada desarrollador configure sus propios trabajos para sus propias sucursales, pero no es mucho trabajo para una persona (es decir, un administrador de compilación) administrar. Una vez que las ramas personalizadas se han fusionado en ramas estables, los trabajos correspondientes se pueden eliminar cuando ya no sean necesarios.

Si le preocupa la carga en el servidor de CI, puede configurar instancias separadas del CI o incluso esclavos separados para ayudar a equilibrar la carga en varios servidores. Asegúrese de que el servidor en el que está ejecutando Hudson / Jenkins sea adecuado. He usado Apache Tomcat y solo tenía que asegurarme de que tuviera suficiente memoria y poder de procesamiento para procesar la cola de compilación.

Es importante tener claro lo que desea lograr con la IC y luego encontrar una manera de implementarlo sin mucho esfuerzo manual o duplicación. No hay nada de malo en utilizar otras herramientas o scripts externos que ejecute su servidor de CI que ayuden a simplificar el proceso general de gestión de la compilación.

Bernardo
fuente
Creo que esta falta de herramientas significa que hay espacio para algunos complementos / productos en este departamento. No querría escribir el mío.
toomasr
1
Hay una utilidad para Jenkins que crea la configuración de compilación para cada rama automáticamente: entagen.github.com/jenkins-build-per-branch
kolen
3

Elegiría dev + ramas estables. Y si todavía quieres ramas personalizadas y temes la carga, entonces ¿por qué no trasladar estas personalizadas a la nube y dejar que los desarrolladores las administren ellos mismos? Por ejemplo, http://cloudbees.com/dev.cb Esta es la empresa donde Kohsuke está ahora . También hay herramientas Eclipse, por lo que si está en Eclipse, lo tendrá estrechamente integrado directamente en dev env.

Anton Safonov
fuente
¿Cambiaré la falta de herramientas para administrar múltiples sucursales por tener el mismo problema pero en la nube? Quiero decir, podré administrar la carga ahora, pero ¿aún no las ramas?
toomasr
Me refería a olvidar las herramientas y distribuir la gestión entre los desarrolladores: "si quieres una compilación personal personalizada, aquí tienes tu cuenta CB". Sin afectar el rendimiento de la compilación del servidor principal. Aunque su API es bastante simple, la creación de utilidades de administración probablemente sería cuestión de una o dos semanas, y luego haces allí lo que quieras. Como es habitual en la vida, si quieres algo especial, es mejor que lo hagas tú mismo. Al mismo tiempo, están creciendo rápidamente y escuchando a la comunidad, así que complete una solicitud de función y puede que aparezca pronto.
Anton Safonov
Oh, entendido. Dígale al propietario de la sucursal que elige los trabajos que le interesan y que los configure para su sucursal personalizada como quiera. Me gusta esta idea.
toomasr
1

En realidad, lo que es realmente problemático es crear aislamiento con ramas de funciones. En nuestra empresa tenemos un conjunto de proyectos maven separados que forman parte de una distribución más amplia. Estos proyectos son mantenidos por diferentes equipos, pero para cada distribución es necesario publicar todos los proyectos. Una rama de características ahora puede superponerse de un proyecto a otro y ahí es cuando el aislamiento de la construcción se vuelve doloroso. Hay varias soluciones que hemos probado:

  • crear repositorios de instantáneas independientes en nexus para cada rama de función
  • compartir repositorios locales en esclavos dedicados
  • use el complemento de servidor de repositorio con repositorios ascendentes
  • construir todo dentro de un trabajo con un repositorio privado

De hecho, la última solución es la más prometedora. Todas las demás soluciones carecen de una u otra forma. Junto con el complemento job-dsl, es fácil configurar una nueva rama de funciones. simplemente copie y pegue el guión maravilloso, adapte las ramas y deje que el trabajo inicial cree los nuevos trabajos. Asegúrese de que el trabajo de inicialización elimine los trabajos no administrados. Luego, puede escalar fácilmente con ramas de funciones en diferentes proyectos de Maven.

Pero como Tom dijo anteriormente, sería mejor superar la necesidad de ramas de funciones y enseñar a los desarrolladores a integrarse limpiamente, pero ese es un proceso más largo y el resultado no está claro con muchas partes del sistema heredado que ya no tocará.

mis 2 centavos

prosailor
fuente