Drone: Monta tu propio sistema de integración continua

Más ligero que Jenkins, y sin las limitaciones de Gitlab o Github, Drone nos permite tener nuestro propio sistema de integración continua alojado por nosotros mismos

Drone: Monta tu propio sistema de integración continua

Desde que los procesos de integración continua llegaron a mi vida, he estado experimentando para saber cómo funcionan y en qué aspectos de mis proyectos podrían interesarme. Comencé gestionando una instancia de Jenkins sobre la que construía los pipeline para que mis proyectos compilaran, ejecutaran tests, generaran imágenes Docker, desplegaran... Sin embargo, me consumía demasiados recursos en mi modesto VPS. Tuve que retirar el servicio y rendirme a las GitHub actions o las integraciones que ofrecía Gitlab, pero no terminaba de estar a gusto del todo... Tengo mi propio servidor de Git y no quiero depender de herramientas de terceros para alojar mi código ni para las acciones sobre ellos... Y aquí es donde entró Drone.

Drone es una plataforma de integración continua escrita en Go que se puede autoalojar en un servidor y que resulta muy ligera, además de tener una gran comunidad detrás que la soporta (cosa que se agradece mucho). Soporta multitud de gestores de Git y se integra de maravilla con ellos. Por eso, cuando lo conocí no pude evitar llevármelo al mío.

Actualmente, utilizo un servicio autoalojado de Gitea para mis repositorios, tanto públicos como privados, y estoy en proceso de migrar los que tengo aún en GitHub y Gitlab para, por fin, tener mi código en un lugar controlado por mí (en verdad tengo un servidor Git local y otro espejo en el VPS, por tema de redundancia y seguridad). Así pues, en este tutorial vamos a ver cómo integrar Drone con Gitea.

Preparación del servidor Git

Para comenzar, necesitamos actuar sobre Gitea. Necesitaremos crear una aplicación OAuth para que Drone pueda conectarse a nuestro repo y poder trabajar con él. Para ello, en el menú de nuestro perfil, accederemos a Configuración y seleccionaremos la pestaña Aplicaciones.

En la opción Administrar aplicaciones OAuth2 crearemos una nueva, dándole un nombre identificativo (en mi caso: drone) y la URL de login, la cual deberá coincidir exactamente con el login (esquema, URL y path). Haremos clic en Crear aplicación y tendremos algo como lo siguiente:

Aplicación OAuth creada para Drone
Aplicación OAuth creada para Drone

Como veis en la imagen de arriba, tenemos un ID y un secreto, que debermos apuntar en un lugar seguro, ya que una vez hagamos clic en Guardar no lo volveremos a ver.

Una vez hecho esto, procederemos a crear un secreto compartido (shared secret) que utilizaremos para comunicar nuestro servidor Drone con los agentes (más adelante os explico qué son). Para crear este secreto, bastará con abrir una terminal y hacer uso del comando openssl de la siguiente forma:

$ openssl rand -hex 16
88b047dbe16aa8e0213eab9ae0ec3d29
Generación del secreto compartido

De nuevo, apuntamos o guardamos ese valor obtenido, pues lo usaremos más adelante.

Creación del servidor Drone

Para este paso, nos haremos con un fichero docker-compose.yml que tendrá la siguiente forma:

version: '3'

services:
  drone:
    image: drone/drone:2
    container_name: drone
    ports:
      - 80
      - 443
    volumes:
      - ./drone_data:/data
      - /var/run/docker.sock:/var/run/docker.sock
    env_file: .env
    restart: always
    networks:
      - gitea
      - drone

networks:
  gitea:
    external: true
  drone:
    external: false
Fichero docker-compose.yml para Drone

Como se puede apreciar, mi repositorio de Gitea ya tiene una red de Docker propia y existente, a la cual nos conectamos.

Una vez tenemos preparado el fichero, vamos a crear el fichero .env con la siguiente estructura:

DRONE_GITEA_CLIENT_ID=
DRONE_GITEA_CLIENT_SECRET=
DRONE_GITEA_SERVER=https://repo.example.org
DRONE_GIT_ALWAYS_AUTH=true
DRONE_RPC_SECRET=
DRONE_SERVER_HOST=drone.example.org
DRONE_SERVER_PROTO=https
# Use this to add admin permissions to user. Useful to trust projects or execute pipelines with admin privileges
DRONE_USER_CREATE=username:<MY_USER>,machine:false,admin:true
Fichero .env

La información que tendrá será la siguiente:

  • DRONE_GITEA_CLIENT_ID: El clientId generado anteriormente en Gitea.
  • DRONE_GITEA_CLIENT_SECRET: El secreto generado anteriormente en Gitea.
  • DRONE_GITEA_SERVER: El servidor donde tenemos alojado nuestro Gitea.
  • DRONE_GIT_ALWAYS_AUTH: Si lo ponemos a true, Drone se autenticará cada vez que ejecute un step. Es necesario si nuestro usuario no está visible de manera pública.
  • DRONE_RPC_SECRET: Aquí pondremos ese secreto compartido, o shared secret, que vimos al final del primer paso.
  • DRONE_SERVER_HOST: El host donde estará accesible nuestro servidor Drone.
  • DRONE_SERVER_PROTO: El schema que utilizará el servidor. Debe ser http o https en función de cómo lo expongamos.
  • DRONE_USER_CREATE: Reemplazaremos <MY_USER> por el usuario que vayamos a usar en Gitea, con el fin de poder gestionar nuestros repositorios en Drone de manera más precisa.

Arrancar el servidor de Drone

Una vez tenemos todo preparado, ejecutamos docker-compose up -d y accederemos a https://drone.example.org, donde veremos lo siguiente:

Pantalla de login de Drone
Pantalla de login de Drone

Si hacemos click en Continue nos llevará a nuestro Gitea y se nos solicitará autorización. Haremos clic en Autorizar aplicación:

Autorización para integrar Drone en Gitea
Autorización para integrar Drone en Gitea

Esto nos redigirá de nuevo a Drone, donde deberemos crear una cuenta de usuario en el panel que nos aparece (sólo tendremos que hacerlo la primera vez):

Panel de creación de usuario en Drone
Panel de creación de usuario en Drone

Tras hacer clic en Submit, veremos la pantalla principal de Drone, donde se listarán los repositorios que detecte en nuestro repositorio de Gitea:

Pantalla principal de Drone en el primer login
Pantalla principal de Drone en el primer login

Creación de un drone-runner

Una vez tenemos nuestro servidor Drone enlazado con Gitea, necesitamos levantar los runner. ¿Y qué es un runner os preguntaréis? Pues ni más ni menos que un servicio que se encargará de ejecutar los pipeline de Drone. Podremos tener tantos como queramos y en distintas plataformas.

A modo de ejemplo: Yo tengo mi servidor Drone en un servidor con procesador AMD64. Sin embargo, hay proyectos que deben correr en la RaspberryPi, y ésta funciona sobre una arquitectura ARMv7. Tengo un proyecto que genera una imagen Docker y la sube al repositorio, y si bien podría hacer uso de la herramienta buildx, lo que hago es levantar un runner en mi RaspberryPi que se conecta al servidor de Drone y se encarga de ejecutar las tareas específicas para ARMv7 que tengo definidas en ese pipeline. De esta forma, puedo tener varios runner en distintas máquinas. También me sirve para descargar al servidor principal de trabajos pesados, delegándolos a máquinas dedicadas.

Para crear nuestro runner junto con nuestro servidor Drone, ampliaremos el fichero docker-compose.yml que hemos creado anteriormente con el siguiente contenido:

version: '3'

services:
  drone:
    image: drone/drone:2
    container_name: drone
    ports:
      - 80
      - 443
    volumes:
      - ./drone_data:/data
      - /var/run/docker.sock:/var/run/docker.sock
    env_file: .env
    restart: always
    networks:
      - gitea
      - drone

  drone-runner:
    image: drone/drone-runner-docker:1
    container_name: drone-runner
    restart: always
    networks:
      - drone
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    env_file: .env
    environment:
      - DRONE_RPC_PROTO=https
      - DRONE_RPC_HOST=drone.example.org
      - DRONE_RUNNER_CAPACITY=2
      - DRONE_RUNNER_NAME=drone-runner-1

networks:
  gitea:
    external: true
  drone:
    external: false
Servicio runner agregado al docker-compose.yml

Como veis, hemos agregado un nuevo servicio llamado drone-runner. Le hemos integrado en la misma red que el servidor de Drone y hemos reutilizado su fichero .env. Además, le hemos definido algunas variables más de entorno:

  • DRONE_RPC_PROTO: Define el schema sobre el que está el servidor de Drone.
  • DRONE_RPC_HOST: Indicamos el host donde está nuestro servidor Drone. Esto es útil sobre todo si el runner corre en otra máquina. Aquí podríamos, simplemente, indicarle el nombre del servicio, drone, ya que están bajo la misma subred.
  • DRONE_RUNNER_CAPACITY: Es un valor opcional que nos permite indicar cuántos pipeline puede ejecutar este runner a la vez. El valor por defecto es 2.
  • DRONE_RUNNER_NAME: Nos permite definir un nombre para el runner dentro del servidor de Drone y así tracear desde él el estado de una ejecución concreta y saber dónde se ejecuta.

Fin de la instalación

Con esto concluye el tutorial para instalar Drone, un runner asociado y conectar todo con nuestro repositorio de Gitea. Como no quiero que quede demasiado extenso, dejo para una segunda parte el uso de Drone y cómo crear un pipeline de ejemplo.

Si te ha gustado la entrada, o te ha sido útil y quieres ayudarme a pagar los gastos que conlleva el servidor y mantener así el blog libre completamente de anuncios, puedes hacer una donación en Bitcoin en la siguiente dirección:

Donar