Visión general de la Arquitectura¶
QFieldCloud tiene una arquitectura en contenedores con múltiples contenedores y volúmenes.
docker-compose.yml
, el resto del texto es la función del contenedor. Las flechas entre contenedores indican quién inicia la comunicación. Las flechas entre un contenedor y un volumen representan si el contenedor lee (flecha que señala al contenedor) o escribe (flecha que señala al volumen) datos. Las flechas y contenedores en gris representan servicios obsoletos
Ver una versión interactiva de el dibujo anterior.
Nota Por simplicidad y claridad, todos los gráficos muestran el llamado "camino feliz" sin detallar la gestión de errores a lo largo del proceso.
Objetos Docker¶
Contenedores¶
[nginx]
Proxy inverso¶
El proxy inverso que se sitúa delante de QFieldCloud.
Debe tener un nginx
para este propósito, ya que la cabecera HTTP X-Accel-Redirect
se utiliza mucho en producción para servir archivos directamente desde el [minio] Almacenamiento de Archivos.
Requiere la presencia de un certificado SSL: autofirmado, Let's Encrypt u otro.
[app]
Aplicación QFieldCloud¶
El software principal que ejecuta QFieldCloud, incluyendo autenticación, gestión de permisos, modelos de datos, archivos estáticos, interfaz administrativa y más.
Consta de varias aplicaciones Django, a saber:
autenticación
- responsable de la autenticación de la API.core
- modelos de datos, permisos, gestión de colas de trabajo, API REST, interfaz administrativa y todo lo demás de QFieldCloud que no gestionan las otras aplicaciones Django.filestorage
- responsable de la gestión de archivos del proyecto y de su respectiva API REST.notifs
- módulo de notificaciones.suscripción
- gestión de los planes de usuario, suscripción y cuota de almacenamiento.
[memcached]
Caché en memoria¶
Utiliza memcached
para la caché en memoria de la configuración de Django y otros valores calculados.
[ofelia]
Runner CRON¶
Utiliza ofelia
para el runner CRON.
[mkcert]
Creador del certificado autofirmado¶
Crea automáticamente un certificado SSL autofirmado para el desarrollo local y las implantaciones de prueba.
[certbot]
Gestor de Letsencrypt¶
Utiliza certbot
para gestionar los certificados Let's Encrypt.
Recrea automáticamente los certificados SSL que caducan y son recargados automáticamente por [nginx
] Reverse Proxy.
[worker_wrapper]
Cola Consumer¶
Uno o más contenedores para consumir y gestionar trabajos desde la cola.
El [worker_wrapper] Consumidor de Cola consulta periódicamente la [db] Base de Datos de Aplicaciones para detectar nuevos trabajos pendientes.
Al encontrar un trabajo en estado PENDIENTE
, el [worker_wrapper] Consumidor de Cola lo establece en estado EN COLA
y comienza a procesarlo.
A continuación, el contenedor establece una serie de metadatos en el objeto Trabajo en la [db] Base de Datos de Aplicaciones e inicia un nuevo contenedor temporal [qgis] Worker.
Espera a que el contenedor [qgis] Worker finalice, obtiene los registros y los almacena en la [db] Base de Datos de Aplicaciones.
Por último, actualiza un conjunto de metadatos de otros Trabajos en la [db] Base de Datos basándose en el código de salida y en los registros del [qgis] Worker, y establece el estado del Trabajo en FINISHED
o FAILED
.
El contenedor ejecuta el mismo código Django utilizado en [app
] QFieldCloud App.
Lee cómo funciona la cola del consumer [worker_wrapper]
en la sección Cola de trabajos.
[qgis]
Worker¶
El contenedor del Worker es el lugar real donde se ejecutan los Trabajos creados por la [app
] QFieldCloud App.
Cada contenedor Worker es creado dinámicamente por el [worker_wrapper
] Cola del Consumer para ejecutar un único trabajo para un único proyecto y eliminado justo después.
La ejecución típica de un Worker consiste en iniciar una aplicación QGIS cualquiera, descargar los archivos del proyecto, procesar los archivos del proyecto y volver a cargar los archivos procesados resultantes.
El contenedor [qgis]
Worker obtiene variables de entorno, incluido un token temporal de autenticación QFieldCloud, del [worker_wrapper]
Cola de Consumer, y le devuelve datos escribiendo registros en el STDERR
y escribiendo archivos en el volumen compartido temporal, principalmente feedback.json
.
Volúmenes¶
[cerbot_www]
¶
Almacena los certificados SSL creados por [mkcert]
Creador de certificados autofirmados o [certbot]
Gestor de Letsencrypt.
[transformation_grids]
¶
Contiene todos los grip de transformación disponibles, descargadas de https://cdn.proj.org/ y puestas a disposición de todos los Trabajos.
[static_volume]
¶
Contiene todos los activos estáticos, como fuentes, CSS, JS o archivos de imagen.
[media_volume]
¶
Aviso Obsoleto, puede ser eliminado en cualquier momento.
La ubicación por defecto para los archivos subidos por el usuario. No debe utilizarse nunca.
Servicios de desarrollo¶
Los siguientes contenedores sólo están disponibles para fines de desarrollo local y no deben utilizarse en producción, ya que estos servicios no están monitorizados, no tienen copia de seguridad y, en general, están diseñados para un uso crítico dentro del stack.
[minio
] Almacenamiento de archivos¶
Almacenamiento local de objetos (tipo S3) utilizado para el desarrollo.
Los datos se almacenan en 4 volúmenes [minio_data
], ya que minio
impone la replicación.
Debería sustituirse por un proveedor SaaS de almacenamiento de objetos similar a S3.
Si se está ejecutando minio
, asegúrate de que el cortafuegos del host permite el puerto 8009
, requerido por el servicio minio
(o el puerto configurado con la variable de entorno MINIO_API_PORT
).
[createbuckets
] Crear Buckets de Minio¶
Contenedor de un solo shot para crear los buckets necesarios en el Almacenamiento de Objetos bajo [minio
] Almacenamiento de Archivos.
[webdav
] Almacenamiento de archivos alternativo¶
Almacenamiento WebDAV local utilizado para el desarrollo, utilizando el protocolo y las especificaciones WebDAV.
Los datos se almacenan en el volumen [webdav_data
].
Se puede usar alternativamente en lugar del almacenamiento de archivos minio
para almacenar archivos. Opcionalmente, se puede usar para almacenar solo archivos adjuntos.
Info
El almacenamiento webdav es opcional; no es un requisito para el correcto funcionamiento del sistema.
Si se utiliza, el servicio de almacenamiento webDAV debe reemplazarse por un servidor WebDAV adecuado, por ejemplo, NextCloud.
[db
] Aplicación PostgreSQL¶
Servidor local de base de datos PostgreSQL para alojar los datos de la [app
] QFieldCloud Aplicación.
El esquema de la base de datos está totalmente gestionado por Django.
El esquema no debe ser modificado por servicios externos.
Debería reemplazarse por una base de datos PostgreSQL adecuada con un proveedor SaaS PostGIS instalado.
[smtpdev
] Servidor de correo¶
Servidor de correo local para gestionar el envío de correos electrónicos, como activación de registro, restablecimiento de contraseña o notificaciones.
Debería reemplazarse por un proveedor SaaS de correo electrónico adecuado que admita el protocolo SMTP.
[geodb
] GeoDB PostgreSQL¶
¡!!! alerta Obsoleto, podría eliminarse en cualquier momento.
Almacena bases de datos PostGIS del usuario creadas dinámicamente.
[minio_data
]¶
Almacena datos para el servicio [minio
] S3.
[webdav_data
]¶
Almacena datos para el servicio de almacenamiento [webdav
] si está presente.
[postgres_data
]¶
Almacena datos para [db
] Aplicación PostgreSQL.
[smtp4dev_data
]¶
Almacena datos para el servidor de correo [smtpdev
].
[geodb_data
]¶
!!! advertencia! Obsoleto, podría eliminarse en cualquier momento.
Almacena datos para [geodb
] GeoDB PostgreSQL.
Cola de trabajos¶
QFieldCloud ejecuta operaciones muy pesadas para que la sincronización del proyecto funcione sin problemas para los usuarios. Por lo tanto, estas operaciones se ejecutan mediante los trabajos (jobs.md) que se ejecutan en segundo plano.
Aquí tenemos un diagrama de secuencia de las etapas que sigue cada ejecución de trabajo.
Algunos de los pasos se acortan intencionalmente para mayor claridad..
sequenceDiagram
autonumber
participant DB as QFieldCloud DB
participant Queue as QFieldCloud Queue
loop poll database
Queue->>DB: select the oldest Job with `PENDING` status
Queue->>DB: set the status of Job to `STARTED` status
Queue->>DB: create a new temporary authentication token
create participant Worker
Queue->>Worker: create the worker and pass the authentication token
note over Worker: job specific processing...
destroy Worker
Queue-xWorker: get worker's structured and free text logs and exit code
Queue->>DB: set job's structured logs, free text logs and exit code
alt Worker has zero exit status
Queue->>DB: set the Job status to `FINISHED`
else Worker has non-zero exit status
Queue->>DB: set the Job status to `FAILED`
end
break when any of the steps above fails
Queue-->DB: set the status Job to `FAILED`
end
end
Si bien algunos de los pasos aún están simplificados, este diagrama contiene mucha más información sobre el ciclo de vida de los atributos del trabajo.
sequenceDiagram
autonumber
participant DB as QFieldCloud DB
participant Queue as QFieldCloud Queue
loop [every few seconds]
Queue->>DB: select the oldest job with `PENDING` status
Queue->>DB: set the status of current job to `QUEUED`
Queue->>DB: set the status of current job to `STARTED` and `started_at` to `now()`
Queue->>DB: create a new temporary authentication token
Queue->>DB: set `docker_started_at` to `now()`
create participant Worker
Queue->>Worker: - mount `transformation_grids` volume <br> - set shared data volume <br> - set the environment variable with the authentication token <br> - set the environment variables from secrets <br> - set the `pgservice` file from secrets <br><br> Create the worker
activate Worker
par run worker
Worker->>API: Download files
API->>Worker: Files downloaded
note over Worker: job specific processing...
Worker->>API: Upload files
API->>Worker: Files uploaded
deactivate Worker
and wait for Worker to finish on Queue
Queue->>DB: set `container_id` to the newly created Docker container id
Queue->>Queue: wait until the Worker is finished or timeout reached
end
Queue->>DB: set `docker_finished_at` to `now()`
destroy Worker
Queue-xWorker: - get Worker's `stdout` logs <br> - get Worker's structured logs from the `feedback.json` in the shared volume <br> - get Worker's exit status code <br><br> Remove the container and cleanup all Job data
Queue->>DB: set job's `output` and `feedback`
alt [Worker has zero exit status]
Queue->>DB: set the status of current job to `FINISHED` and `finished_at` to `now()`
else [Worker has non-zero exit status]
Queue->>DB: set the status of current job to `FAILED`
end
break when any of the steps above fails
Queue-->DB: set the status of the current job to `FAILED`
end
end
participant API as QFieldCloud App