En la industria DevOps actual nos esforzamos para cumplir ciertas prácticas ejemplares que no solamente hacen nuestro trabajo más fácil, sino que también hacen nuestros sistemas y aplicaciones más fiables. Dos de esas prácticas son automatizar tanto como sea posible y documentar lo que hacemos. Y a veces, podemos mezclar esas dos prácticas y automatizar la generación de documentación. Aquí os presentamos un ejemplo que mejoró nuestras vidas ayudándonos a simplificar la generación de documentación de manera automatizada.
Documentación
La documentación es uno de los recursos clave en un equipo de ingeniería de sistemas o de desarrollo. Hay dos aspectos en los que básicamente todo el mundo está de acuerdo: es muy importante tener buena documentación que sea útil; y es muy difícil mantenerla actualizada y con cierta lógica. Las variables que influyen en estos son muchas y generan muchas alternativas:
- Herramientas: hay un montón de sistemas para guardar documentación, y la mayoría de equipos han pasado por numerosas fases con varias de estas herramientas, probándolas hasta encontrar alguna que les funcionara relativamente bien. Algunos ejemplos de esos sistemas son: documentos en carpetas compartidas, sitios web, wikis, tickets, herramientas específicas… etc.
- Formato: existen también muchos formatos en los que puedes escribir documentación: en texto simple, en texto WYSIWYG, en HTML (desde wiki, markdown, markup, a reStructured Text, latex…). La usabilidad y legibilidad aquí se contradicen: escribir documentos de texto sin formato es más fácil, aunque tedioso de leer y de seguir; y las páginas web con buen aspecto son fáciles de seguir y acceder, pero suelen tomar más tiempo a la hora de generarlas.
- Organización de equipo: cada persona piensa de manera diferente y organiza ideas en su cabeza de manera diferente, y eso se demuestra a la hora de poner esas ideas en palabras. Por ejemplo, alguien pondría el procedimiento de crear un volcado de base de dentro de la categoría “MySQL”, mientras que otra persona lo ubicaría en la categoría de “copias de seguridad”. En algunos equipos esto se administra determinando un “editor”, es decir, una persona que toma los bits de documentación generados por sus compañeros y los organiza de una manera concreta. Sin embargo, esto genera un paso adicional o una demora, lo que hace que sea más difícil mantener la documentación actualizada.
CAPSiDE es uno de esos equipos que ha probado varios métodos. Hemos usado y usamos más de un procedimiento, pues no toda la documentación es igual y la tecnología sigue evolucionando. Aquí está la historia de cómo automatizamos la generación de documentación HTML desde texto en reStructured con Git, Gitlab, integración continua/distribución continua y Docker.
La situación
Clouddeploy es una herramienta de código abierto desarrollada en CAPSiDE que nos ayuda a crear y mantener la infraestructura en AWS a través de código. Para la documentación de esta herramienta empezamos a usar una wiki, pero a medida que esta fue creciendo también creció la idea de usar otro sistema. Mientras mirábamos diferentes alternativas, nos encontramos con Sphinx que transforma texto en reStructured Text (RST) en varios formatos, como HTML o epub.
Todo en CAPSiDE está bajo un control de versiones, así que los archivos RST se tuvieron que gestionar con Git. También tenemos una cuenta de Gitlab donde viven nuestros repositorios. Así que, en la primera versión de esta documentación, cada miembro del equipo hizo lo siguiente para contribuir:
- Configurar un virtualenv en su área de trabajo e instalar Sphinx y Read the Docs.
- Extraer el repositorio de documentación desde el servidor Gitlab de la empresa.
- Crear una rama y empezar a trabajar en la documentación.
- Una vez satisfecho con el trabajo realizado, generar el HTML con el comando make html de Sphinx y asegurarse que todo tiene el aspecto deseado.
- Accionar la opción commit y extraer hacia el servidor.
- Copiar la HTML generada a un servidor web.
Este proceso inicial fue engorroso en comparación con solo editar una wiki, por lo que necesitaba perfeccionarse un poco. Y dado que la automatización es el núcleo de la ingeniería de sistemas, buscamos formas de hacerlo.
La integración continua al rescate
Gitlab es un repositorio muy completo que proporciona herramientas de integración continua/distribución continua. TEs una herramienta muy poderosa y fácil de configurar, y su documentación es clara y completa. Es tan simple como esto:
Si agregas un archivo .gitlab-ci.yml al directorio raíz de tu repositorio y configuras tu proyecto GitLab para usar un runner, cada acción commit o push activa tu pipeline de integración continua.
En el flujo de trabajo anterior hubo varias oportunidades para reducir la carga de trabajo del equipo:
- Evitando que todo el mundo configurara el entorno
- Compilando el código en html y asegurándose de que queda bien
- Publicando el HTML generado al servidor web
Esto se podría hacer en Gitlab en dos tareas:
- Una para generar el html y proporcionarlo al usuario para que lo comprobara
- Otra para publicarla
Gitlab ofrece diferentes maneras de ejecutar las tareas de integración continua/distribución continua. Para un trabajo como este en el que era necesario configurar el entorno, decidimos usar Docker.
Gitlab Runners y Docker
La imagen de Docker en este runner solamente necesitaba configurar el entorno para que pudiéramos compilar el código. Un simple Dockerfile como este fue suficiente para ello:
Con este, obtuvimos la imagen oficial en Python 2.7 y usamos pip para instalar Sphinx y el tema en RTD. El siguiente paso es crear la imagen que el runner utilizará en el servidor de Gitlab:
Ahora podemos crear el runner de Gitlab. Para ello, necesitas tener privilegios sudo en el servidor de Gitlab y ser administrador en Gitlab para obtener el token:
Responde a las preguntas que te solicita (más información aquí). Parte de la configuración que se establezca respondiendo estas preguntas se puede cambiar más adelante. La última pregunta es sobre cómo elegir el tipo de ejecución:
En este caso escogemos docker, que nos lleva a la última pregunta en la que usaremos la imagen de Docker que creamos anteriormente:
Ahora tenemos el runner configurado. El siguiente paso es configurar la pipeline para que este runner se use cuando hagamos la acción de push en el repositorio.
Creando la pipeline
Ahora necesitamos crear el archivo .gitlab-ci.yml en nuestro repositorio, para que todo se ponga en marcha. La pipeline tendrá dos tareas:
- Tarea 1: crear el html
- Tarea 2: publicar
Aquí está el gitlab-ci.yml que hemos generado:
Esta es la visión general de lo que todo esto significa:
- Indicamos qué imagen de Docker usaremos para esta pipeline (la que creamos antes y con la que hemos configurado un runner)
- Indicamos las etapas de la pipeline. En este caso, tenemos dos: construir y desplegar.
- Definimos las tareas: construir y publicar
- En la tarea de construcción indicamos qué queremos ejecutar (make html) y con qué artefactos necesitaremos quedarnos de esta ejecución. El artefacto estará disponible una vez la tarea haya terminado, cualquier usuario podrá descargárselo desde la página de Gitlab y echar un vistazo a los archivos generados para asegurarse que tienen el aspecto deseado.
- En la tarea de publicación copiamos el artefacto generado al servidor de documentación en remoto. Algunos detalles sobre esto:
- La línea de only: master indica que esta tarea solamente se ejecutará si la acción push se hizo a la rama maestra. Por lo tanto, todo el mundo puede crear ramas con nueva documentación y cuando hagan push en la pipeline solamente se ejecutará la tarea build , permitiéndoles generar el código HTML y verlo sin tener que desplegarlo en producción.
- La sección before_script configura el entorno necesario para copiar el artefacto a un servidor remoto a través de SSH desde el contenedor. Es importante señalar la variable $SSH_PRIVATE_KEY. Esta variable se configura en la interfaz de Gitlab del proyecto en Settings -> CI/CD -> Secret variables, donde adjudicamos un nombre y un valor a la variable y decidimos si está protegida o no (es decir, si esta variable es disponible en tareas activadas desde todas las ramas o solo desde las protegidas).
- Finalmente, la sección script copia el artefacto y activa la ejecución de un script que, por ende, despliega el código en el servidor remoto.
La situación final
Al principio de este documento hablamos sobre los distintos pasos que alguien del equipo necesitaba seguir para actualizar documentación. Ahora la situación ha cambiado y tiene este aspecto:
- Extrae el repositorio de documentación del servidor Gitlab de la empresa.
- Crea una rama y empieza a trabajar en la documentación.
- Una vez satisfecho con el trabajo realizado, lleva una acción push con la rama hacia Gitlab. Esto activará la pipeline y ejecutará la tarea build, que proporcionará un artefacto: el código HTML en un archivo zip que el miembro del equipo puede descargarse para asegurar de que todo tiene el aspecto que se esperaba. El estado del trabajo, su salida y los artefactos se pueden ver en la página del proyecto en Gitlab, en la sección “integración continua/distribución continua” (CI/CD).
- Si estás satisfecho, lanza una solicitud de extracción a la rama maestra.
- Cuando esta esté aceptada, la pipeline se activará de nuevo, generando el código y copiándolo en el servidor web.
Así hemos eliminado la necesidad de configurar el entorno para cada miembro del equipo, compilar el código y copiarlo manualmente al servidor una vez se apruebe. Esto hace que la actualización de la documentación sea más fácil que antes, lo cual es clave para mantenerla al día.
TAGS: automation, ci pipeline, docker, documentation, documentation generation, gitlab
Comentarios