GreenWheels es una plataforma distribuida para el análisis de datos urbanos en tiempo real, que combina información ambiental (calidad del aire) y operativa (disponibilidad de bicicletas). Fue desarrollada en el marco del Máster en Tecnologías Web, Computación en la Nube y Aplicaciones Móviles de la Universitat de València, y está orientada a su despliegue completo en entornos escalables mediante Kubernetes.
Proyecto desarrollado por:
Estudiantes del Máster en Tecnologías Web, Computación en la Nube y Aplicaciones Móviles.
- Java 17, Spring Boot y Spring Cloud
- Docker y Docker Compose
- Kubernetes
- MongoDB (NoSQL) y MySQL (relacional)
- Spring Security con JWT
- NGINX Ingress Controller
- Eureka Service Discovery
- Spring Cloud Config Server
El sistema está organizado en capas funcionales, promoviendo la separación de responsabilidades:
- 🔴 API Layer: Exposición de endpoints públicos y administrativos.
- 🟢 Data-Access Layer: Microservicios dedicados al acceso a bases de datos relacionales y no relacionales.
- 🔵 Persistencia Layer: Bases de datos físicas desplegadas en contenedores y gestionadas como servicios de estado.
- 🔐 Seguridad: Autenticación y autorización basada en JWT a través del microservicio
auth-service.
| Servicio | Descripción | Puerto | Tipo de Persistencia |
|---|---|---|---|
auth-service |
Gestión de usuarios y generación de tokens JWT | 8085 | - |
config-server |
Centralización de configuración para todos los servicios | 8888 | - |
ayuntamiento-service |
Agregación de datos urbanos (bicicletas + polución) | 8090 | - |
bicicleta-service |
Gestión lógica de aparcamientos de bicicletas | 8084 | - |
polucion-service |
Gestión lógica de estaciones de polución | 8091 | - |
data-ayuntamiento |
Persistencia de estadísticas urbanas | 8087 | MongoDB |
data-bicicletas |
Persistencia de aparcamientos | 8083 | MySQL + MongoDB |
data-polucion |
Persistencia de calidad del aire | 8086 | MySQL + MongoDB |
| Worker | Rol | Puerto | Funcionalidad |
|---|---|---|---|
worker-estacion |
ESTACION | 8092 | Guarda lecturas ambientales periódicamente |
worker-aparcamiento |
APARCAMIENTO | 8089 | Envía eventos de disponibilidad de bicicletas |
worker-servicio |
SERVICIO | 8095 | Agrega y persiste estadísticas cruzadas |
Kubernetes permite orquestar los microservicios del sistema GreenWheels de forma escalable, modular y automatizada. En esta arquitectura, todo se organiza dentro del namespace twcam y se divide en tres capas:
-
🔴 API Layer: gestiona el acceso externo a través de un Ingress Controller y gateways.
-
🟢 Data-Access Layer: se encarga de la lógica de persistencia, conectando con las bases de datos.
-
🔵 Persistencia Layer: aloja las bases de datos MySQL y MongoDB usando
StatefulSetsy volúmenes persistentes. Cada capa se comunica con la siguiente mediante servicios internos, facilitando el mantenimiento y la escalabilidad del sistema.
Ideal para desarrollo local y debugging.
-
Navegar a la raíz del proyecto:
cd MRDS_TWCAM -
Levantar las bases de datos únicamente (otros servicios comentados en
docker-compose.yml):docker compose up -d
-
Lanzar los microservicios deseados desde su directorio:
cd <carpeta-del-servicio> mvn spring-boot:run
-
Se debe iniciar primero el
config-server.
📌 Notas:
- Las tareas programadas (cron jobs) son opcionales y no son necesarias para las pruebas básicas.
- Las bases de datos ya incluyen datos precargados para pruebas.
Este es un mapa con datos que se encuentran precargados, en las bases de datos, puedes consultar mas detalles en graficas.ipynb
-
Asegúrate de descomentar todos los servicios en el
docker-compose.yml. -
Ejecutar:
docker compose up -d
Este modo garantiza la ejecución íntegra del sistema, con todos los microservicios y bases de datos dentro de contenedores aislados.
Claro, aquí tienes una versión ampliada y detallada del apartado de Despliegue en Kubernetes, ideal tanto para documentación académica como para facilitar la comprensión técnica paso a paso:
El despliegue en Kubernetes es el enfoque más completo y profesional para orquestar los microservicios de GreenWheels. A continuación, se describen los pasos detallados para realizar un despliegue exitoso en un clúster de Kubernetes:
Todos los recursos del sistema se agrupan bajo un namespace específico para evitar conflictos con otros servicios del clúster y mantener la modularidad.
kubectl create -f twcam-namespace.yamlEste archivo define un namespace llamado twcam que será usado en todos los recursos posteriores.
Se crean primero los secrets con información sensible (como credenciales de base de datos o claves JWT):
kubectl apply -f twcam-secrets.yamlDespués, se cargan los ConfigMaps que contienen scripts de inicialización de las bases de datos:
kubectl apply -f Persistencia_Layer/init-scripts-configmap.yamlEsto asegura que, al iniciarse, las bases de datos contengan la estructura y los datos iniciales necesarios para pruebas y funcionamiento del sistema.
Cada base de datos utiliza volúmenes persistentes que almacenan los datos fuera del ciclo de vida de los contenedores, evitando su pérdida en caso de reinicio:
kubectl apply -f Persistencia_Layer/persistent-volumes.yamlEste archivo incluye los PersistentVolumenecesarios, configurados con almacenamiento local.
Se despliegan primero los StatefulSets que controlan la creación de los pods con identidad persistente (necesaria para MongoDB y MySQL) y PersistentVolumeClaims que apuntan a sus respectivos PersistentVolume :
kubectl apply -f Persistencia_Layer/mongo-sts.yaml
kubectl apply -f Persistencia_Layer/mysql-sts.yamlY luego, se crean los servicios correspondientes:
kubectl apply -f Persistencia_Layer/mongo-services.yaml
kubectl apply -f Persistencia_Layer/mysql-services.yaml- Se utilizan servicios headless para permitir el descubrimiento de pods individuales por parte de los microservicios que se conectan a las bases de datos.
- Los pods pueden tardar algunos segundos en estar disponibles. Se puede monitorear con:
kubectl get pods -n twcam -wUna vez las bases de datos están listas y funcionando, se procede a desplegar los microservicios del Data-Access Layer. Estos microservicios son los responsables de interactuar directamente con las bases de datos.
kubectl apply -f DataAccess_Layer/data-cm.yaml
kubectl apply -f DataAccess_Layer/data-deploy.yaml
kubectl apply -f DataAccess_Layer/data-services.yaml🔁 Este paso puede repetirse si se desea actualizar los servicios de acceso a datos sin reinstalar las bases de datos.
Los microservicios principales (ayuntamiento, bicicleta, polución, auth, etc.) se despliegan a través de los manifiestos de la capa API. Incluyen también los gateways de cada bloque.
kubectl apply -f API_Layer/api-cm.yaml
kubectl apply -f API_Layer/api-deploy.yaml
kubectl apply -f API_Layer/api-service.yamlEl Ingress Controller permite exponer los servicios internos de Kubernetes a través de una única IP o dominio público, organizando las rutas mediante reglas declarativas. Esto es esencial para acceder a los microservicios desde fuera del clúster (por ejemplo, desde un navegador o Postman).
Para instalar el NGINX Ingress Controller en entornos sin proveedor cloud (como Minikube, kind o máquinas virtuales en local), ejecuta lo siguiente:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yamlEsto desplegará todos los recursos necesarios en el namespace ingress-nginx.
Es necesario anotar la clase de ingress nginx como predeterminada para que los manifiestos Ingress la utilicen correctamente:
kubectl -n ingress-nginx annotate ingressclasses nginx ingressclass.kubernetes.io/is-default-class="true"Por defecto, el Ingress Controller se expone como LoadBalancer, lo cual no funcionará en entornos locales. Por eso, lo cambiamos a NodePort:
kubectl patch svc ingress-nginx-controller -n ingress-nginx -p "{\"spec\": {\"type\": \"NodePort\"}}"Esto permitirá acceder al controlador desde el puerto de red del nodo.
Para verificar que el controlador se ha desplegado correctamente y está corriendo:
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginxUna vez desplegado el controlador, obtén la IP del nodo y el puerto asignado al servicio:
kubectl get svc ingress-nginx-controller -n ingress-nginxBusca el valor bajo la columna PORT(S) (por ejemplo: 80:30345/TCP) y accede mediante:
Este puerto es de suma importancia ya que este sera al que apuntemos desde nuestra maquina local.
-
En Linux: Edita el archivo
/etc/hosts:sudo nano /etc/hosts
Añade una línea como:
192.168.1.100 twcam.local -
En Windows (CMD ejecutado como administrador): Edita el archivo de hosts:
notepad C:\Windows\System32\drivers\etc\hostsAñade la misma línea:
192.168.1.100 twcam.local
🔎 Reemplaza 192.168.1.100 por la IP del nodo donde se ejecuta el clúster de Kubernetes.
Con el Ingress Controller operativo, puedes aplicar el manifiesto Ingress de tu API Gateway:
kubectl apply -f API_Layer/api-ingress.yamlEste recurso define rutas como:
/ayuntamiento→ redirige alayuntamiento-service/bicicletas→ redirige albicicleta-service/polucion→ redirige alpolucion-service/auth→ redirige alauth-service
Podrás acceder a todas las rutas desde el navegador o Postman usando la URL:
http://twcam.local:30345/<recurso (ej: polucion)>/<ruta>
Una vez aplicados todos los manifiestos, es fundamental comprobar que todos los pods están en estado Running, que los servicios se exponen correctamente y que el Ingress está redireccionando las peticiones.
kubectl get all -n twcamEsto mostrará:
- Pods (estado:
Running) - Services (tipo:
ClusterIPoHeadless) - Deployments y ReplicaSets
Puedes revisar los logs de cada pod para confirmar que las aplicaciones han arrancado correctamente:
kubectl logs -f deployment/<nombre-del-deployment> -n twcamEjemplo para bicicletas:
kubectl logs -f deployment/bicicletas-service -n twcamPara confirmar que el recurso Ingress ha sido correctamente registrado:
kubectl get ingress -n twcamEste comando te mostrará las rutas expuestas por el Ingress Controller. Verifica que aparezca algo como:
NAME CLASS HOSTS ADDRESS PORTS
twcam-ingress nginx twcam.local <external-ip> 80
Accede a las rutas definidas en el Ingress desde tu maquina local, por ejemplo:
http://twcam.local:</PORTs>/bicicletas/<ruta>
http://twcam.local:</PORTs>/polucion/<ruta>
http://twcam.local:</PORTs>/ayuntamiento/<ruta>
http://twcam.local:</PORTs>/auth/<ruta>
Esto suponiendo que el port del servicio del nodeport es 30912
Obtener todos los aparcamientos de bicicletas
GET http://twcam.local:30912/bicicletas/api/v1/bicicletas/aparcamientos
Obtener todas las estaciones de polución
GET http://twcam.local:30912/polucion/api/v1/polucion/estaciones
Obtener los ultimos datos agregados del ayuntamiento
GET http://twcam.local:30912/ayuntamiento/api/v1/ayuntamiento/aggregatedData
Comprobar que un token es valido y los roles
curl -i -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJBZG1pbiIsInJvbGVzIjpbIkFETUlOIl0sImlzcyI6IlRXQ0FNIn0.5bPoaiJLSga_0sTeYnjcH0mK0tI4Tmh2UCPuDoDpgaQ" http://twcam.local:30912/auth/api/v1/auth/authorize
🛡️ Si el endpoint está protegido, asegúrate de incluir un JWT válido en los headers (Authorization: Bearer <token>).
Desde tu máquina, puedes probar la resolución del dominio con:
ping twcam.localY si usas curl:
curl http://twcam.local:<port>/bicicletasEsto confirmará tanto la resolución del dominio como el funcionamiento de la cadena Ingress → Gateway → Microservicio.
Si deseas eliminar todo el entorno desplegado:
kubectl delete namespace twcam| Servicio | Tipo | Puerto | Contenido |
|---|---|---|---|
data-ayuntamiento |
MongoDB | 27019 | Estadísticas agregadas |
data-bicicletas |
MySQL + MongoDB | 3308 + 27017 | Aparcamientos, eventos |
data-polucion |
MySQL + MongoDB | 3309 + 27018 | Lecturas y estaciones |
El sistema utiliza JWT para autenticación y autorización. Se define control de acceso por roles:
| Rol | Descripción |
|---|---|
ADMIN |
Control total sobre el sistema |
APARCAMIENTO |
Envío de eventos desde aparcamientos |
ESTACION |
Registro de lecturas ambientales |
SERVICIO |
Agregación y consulta de datos internos |
Puedes utilizar los siguientes JWT para pruebas en Postman o Swagger UI:
ADMIN:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
SERVICIO:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
APARCAMIENTO:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
ESTACION:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
TODOS LOS ROLES:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...Todos los endpoints cuentan con documentación OpenAPI/Swagger accesible desde el navegador. Es necesario introducir un JWT válido en la sección de autorización.
Este proyecto está licenciado bajo la MIT License.
Aviso legal: Este software se proporciona "tal cual", sin garantía expresa o implícita. Su uso está permitido con fines educativos y personales. Los autores no se hacen responsables de su uso indebido.
Este proyecto ha sido desarrollado como parte del módulo de Persistencia Relacional y No Relacional, abordando retos reales de integración, orquestación y análisis de datos distribuidos en entornos urbanos.
Se exploran conceptos clave como:
- Diseño orientado a microservicios
- Hibridación de bases de datos (SQL/NoSQL)
- Autenticación y control de acceso robusto
- Automatización con tareas programadas
- Despliegue profesional con Kubernetes


