La arquitectura Docker de este proyecto ha sido diseñada para simular un ecosistema de data space completo, con dos participantes independientes (consumer y provider).
En lugar de un único fichero docker-compose.yml monolítico, la carpeta docker/ contiene tres stacks de Docker Compose separados, permitiendo que cada entidad sea lanzada, configurada y gestionada de forma aislada.
La carpeta docker/ está dividida en las siguientes entidades:
issuer/: Representa la Autoridad Confiable (o Issuer). Este stack es responsable de gestionar la identidad y emitir credenciales para los otros participantes.provider/: Representa la infraestructura completa del Proveedor de datos. Contiene su propiodocker-compose.ymly todos los ficheros de configuración, volúmenes y scripts de seeding necesarios para operar sus servicios (Controlplane, Dataplane, Identity Hub, etc.).consumer/: Representa la infraestructura completa del Consumidor de datos. Al igual que el proveedor, es un stack totalmente aislado con sus propios servicios y configuraciones.participants/: Funciona como un "directorio" compartido. El ficheroparticipants.docker.jsoncontiene la información de descubrimiento (con los DIDs) de todos los participantes. Este fichero se monta como un volumen tanto en el stack delconsumercomo en el delprovider, permitiendo que sepan cómo encontrarse y comunicarse.
Cada stack de participante sigue una estructura estandarizada para facilitar la gestión:
docker-compose.yml: El fichero principal que orquesta todos los servicios (contenedores) necesarios para ese participante (ej:controlplane,dataplane,identityhub,postgres,vault).env/: Almacena los ficheros de variables de entorno (.env) para cada servicio. Eldocker-compose.ymlinyecta estas variables en cada contenedor usando la directivaenv_file:.credentials/,vault/: Carpetas que contienen datos iniciales. Se montan como volúmenes en los contenedores durante el arranque para precargar credenciales, configuraciones de realms de Keycloak o secretos de Vault.files/(Específico del Provider): En la carpetaprovider, existe un directoriofiles/que contiene los ficheros que serán montados en el sistema de ficheros (FS) del contenedor Docker. Esto simula un sistema de ficheros ya poblado con los datos que el provider ofrecerá.seed.sh: Un script de bootstrapping crucial. Después de que los contenedores sean lanzados condocker-compose up, este script debe ser ejecutado para poblar los servicios (ej: crear assets, definir políticas, registrar al participante en elidentityhub, etc.) a través de llamadas de API.
Para ejecutar el ecosistema, se necesitan imágenes Docker que deben crearse localmente. Estas imágenes se refieren a los runtimes de backend (EDC).
Estos componentes (Controlplane, Dataplane, IdentityHub) se construyen desde este repositorio.
La carpeta launchers/ en la raíz del proyecto contiene las configuraciones de build para cada uno de estos componentes esenciales. El proceso de build se realiza en dos etapas:
1. Compilar el Código Fuente
./gradlew buildEste comando compila todo el código fuente de Java, incluyendo el núcleo de EDC y cualquier módulo personalizado (como los de la carpeta extensions/), preparándolos para ser empaquetados.
2. Crear las Imágenes Docker
./gradlew -Ppersistence=true dockerizeEste comando utiliza el código compilado de los launchers/ y crea las imágenes Docker finales. La bandera (flag) -Ppersistence=true es obligatoria, ya que es la que incluye los módulos necesarios para la persistencia en PostgreSQL y la integración con HashiCorp Vault, conforme a lo definido en los ficheros docker-compose.yml.
Tras finalizar, las siguientes imágenes estarán disponibles en su caché local de Docker: controlplane:latest, dataplane:latest, catalog-server:latest, e identity-hub:latest.
Para simular el data space completo, tendrá que lanzar cada stack de forma independiente, idealmente en una terminal separada.
1. Lanzar el Issuer
cd docker/issuer
docker-compose up -d2. Lanzar el Provider
cd docker/provider
docker-compose up -d
./seed.sh3. Lanzar el Consumer
cd docker/consumer
docker-compose up -d
./seed.shEl seeding es un paso de bootstrapping esencial. Se ejecuta manualmente después de que cada stack de participante (ej: consumer o provider) se haya iniciado con docker-compose up -d.
Cada participante posee un script seed.sh dedicado, pero sus funciones difieren:
-
seed.shdel Consumer: La función principal de este script es inicializar la identidad del participante. Utiliza la API del IdentityHub para crear el Contexto del Participante, una acción que registra su identidad descentralizada (DID), sus endpoints de servicio (como el DSP) y genera sus claves criptográficas. -
seed.shdel Provider: Este script tiene una responsabilidad adicional y crucial. Además de realizar el mismo paso de creación de identidad en el IdentityHub, también se encarga de poblar el Controlplane con los metadatos iniciales.
Esto asegura que, una vez completado el seeding, el provider no solo es un miembro identificado del espacio de datos, sino que también tiene su catálogo de datos inicial publicado y listo para ser negociado.
El fichero docker-compose.yml (como el que se encuentra en docker/consumer/) es el corazón de la infraestructura de cada participante. Define y orquesta un conjunto completo de servicios en contenedores que, juntos, forman el stack tecnológico completo de ese participante.
De forma global, este fichero es responsable de cuatro tareas principales:
1. Definición de los Servicios
El fichero define todos los contenedores necesarios para la operación. Esto no incluye solo los componentes centrales del conector EDC (como controlplane, dataplane e identityhub), sino también todas las dependencias críticas de infraestructura:
- Gestión de Secretos: Un servicio
vault(HashiCorp Vault) para almacenar claves y secretos de forma segura. - Persistencia de Datos: Una base de datos
postgrespara guardar el estado de las diversas entidades del espacio de datos (contratos, políticas, etc.).
2. Configuración y Conectividad
El fichero docker-compose.yaml conecta todos estos servicios. Utiliza extensivamente las propiedades env_file: y environment: para inyectar variables de entorno en cada contenedor. Es así como el controlplane conoce la dirección de la base de datos (consumer-postgres), o la contraseña del vault.
3. Orquestación de Arranque
Los servicios no se lanzan todos al mismo tiempo. La directiva depends_on: con condition: service_healthy (donde sea aplicable) garantiza un orden de arranque inteligente. Por ejemplo, el consumer-controlplane solo arranca después de que el consumer-identityhub esté totalmente listo para recibir conexiones.
4. Exposición y Redes
El fichero gestiona cómo se accede a los servicios:
- Red Interna: Todos los servicios se conectan a una
mvd_networkexterna. Esto permite que se comuniquen entre sí (y con los otros servicios presentes en la misma red) usando los nombres de los contenedores como hostname (ej:http://consumer-postgres:5432). - Exposición Externa (Traefik): La mayoría de los endpoints de API (como los del
controlplaneydataplane) no usan la directivaports:. En su lugar, usanlabels:para configurarse automáticamente con un reverse proxy (como el Traefik). Es así como el mundo exterior (como el consumer-portal o el provider) puede acceder a ellos a través de una única URL (ej:http://localhost:13000/consumer-controlplane/...).
La carpeta env/ en cada stack de participante es el centro neurálgico de su configuración. Estos ficheros no son leídos directamente por los servicios; en su lugar, el docker-compose.yml utiliza la directiva env_file: para inyectar estas variables en cada contenedor en el momento del arranque.
Esto permite que la misma imagen Docker (ej: controlplane:latest) se comporte de forma completamente diferente (actuando como "provider" o "consumer") dependiendo del fichero de configuración que se le proporcione.
Normalmente, encontrará tres ficheros de entorno principales por participante:
controlplane.env: Este es el fichero más complejo, pues configura el "cerebro" del participante (el Controlplane). Como se ve en el ejemplo, este fichero define la identidad del participante (edc.participant.id), sus endpoints de API (web.http.*), las claves de seguridad (web.http.auth.key) y, crucialmente, cómo se conecta a sus dependencias (ej:edc.vault.hashicorp.urlpara el Vault yedc.datasource.default.urlpara Postgres). También incluye opciones de debugging (JAVA_TOOL_OPTIONS).dataplane.env: Configura el servicio de transferencia de datos. Define sus propios endpoints de API (públicos y de control) y cómo se registra y comunica con el Controlplane.identityhub.env: Configura el servicio de identidad del participante. Define sus conexiones a la base de datos (normalmente la misma del Controlplane) y al Vault (donde almacena claves privadas), así como sus propias APIs.
Nota sobre el Flujo de Datos (MAIL-PUSH): Es importante destacar que esta configuración está diseñada para probar un flujo de Dataplane específico: el envío de datos mediante MAIL-PUSH a un servicio de correo falso. Se utiliza Ethereal Email para simular el envío de un correo electrónico desde el lado del proveedor.
Este email debe ser creado previamente y sus credenciales añadidas como variables de entorno en el fichero env/dataplane.env del provider. Estas variables le permiten al Dataplane conectarse al servidor SMTP y enviar el email con los datos:
edc.dataplane.mail.sender
edc.dataplane.mail.passwordEstos ficheros en la carpeta credentials son Verifiable Credentials (VCs) preemitidas, usadas para el seed del Identity Hub del participante.
En el escenario del MVD (Minimum Viable Dataspace), en lugar de que el participante tenga que solicitar estas credenciales a un Issuer tras el arranque, ya empieza "poseyéndolas". Son la base del sistema de políticas y control de acceso.
1. MembershipCredential.json
Esta es la prueba de afiliación del participante.
- Propósito: Atestiguar que el participante es un miembro legítimo y reconocido del data space.
- Qué Prueba: Conforme a los claims (
"membershipType": "FullMember"), esta credencial certifica que el provider es un Miembro Acreditado. - Función en el MVD: Es la credencial de "nivel base". En el MVD, se exige frecuentemente en todas las interacciones, sirviendo como el "carné de socio" necesario para, por ejemplo, consultar el catálogo de otro participante.
2. DataProcessorCredential.json
Esta es una credencial de control de acceso basada en atributos.
- Propósito: Certificar que el participante tiene autorización para procesar datos en un nivel específico.
- Qué Prueba: Conforme a los claims (
"level": "processing"), esta credencial atestigua que el provider tiene el nivel de autorización "processing". - Función en el MVD: Se usa para aplicar políticas de acceso más granulares. Por ejemplo, un asset de datos puede tener una política que exija que cualquier consumer presente una
DataProcessorCredentialconlevel: "processing"para poder negociar un contrato. Si un asset más sensible exigieralevel: "sensitive", el poseedor de esta credencial no podría acceder.