Entorno de desarrollo
Este documento detalla la configuración del entorno de desarrollo proporcionado por CodeDesignPlus. Su objetivo principal es simplificar y acelerar la configuración inicial, permitiendo a los desarrolladores centrarse en la lógica de negocio y reducir las tareas repetitivas.
El entorno de desarrollo de CodeDesignPlus esta disponible en el repositorio de GitHub CodeDesignPlus.Environment.Dev
Requisitos Previos
Para desarrollar microservicios con CodeDesignPlus, necesitas tener instaladas las siguientes herramientas en tu máquina:
- Tener instaladas las herramientas de desarrollo descritas en el artículo Herramientas de Desarrollo.
- Clona el repositorio de GitHub CodeDesignPlus.Environment.Dev en tu máquina local.
Docker Compose
El archivo docker-compose.yaml
define un entorno de desarrollo completo utilizando contenedores Docker. Este entorno proporciona las siguientes ventajas:
- Consistencia: Asegura que todos los desarrolladores trabajen con las mismas versiones de dependencias y servicios, evitando problemas de “funciona en mi máquina”.
- Aislamiento: Los servicios se ejecutan en contenedores aislados, previniendo conflictos y simplificando la gestión de dependencias.
- Rápida Configuración: Permite levantar rápidamente un entorno de desarrollo con un solo comando.
- Simulación de Producción: El entorno se asemeja a una configuración de producción, facilitando la detección temprana de problemas.
Cómo Utilizar docker-compose.yaml
-
Asegúrate de tener Docker y Docker Compose instalados.
-
Navega a la carpeta
resources
en el proyecto. -
Ejecuta el siguiente comando para levantar todos los servicios:
Terminal window docker-compose up -d -
Para detener los servicios:
Terminal window docker-compose down
Vault (HashiCorp)
Vault es una herramienta para gestionar secretos, como contraseñas, tokens, claves API y certificados. Proporciona un almacenamiento seguro y un acceso controlado a estos secretos, evitando que se almacenen directamente en el código o archivos de configuración.
Vault se integra con múltiples sistemas de autenticación y motores de secretos, como base de datos, AWS, Azure y otros. Permite la rotación automática de claves y la generación de credenciales temporales para mejorar la seguridad y la gestión de secretos.
- Key Vault: Almacena y gestiona claves y secretos sensibles.
- Database: Almacena credenciales de bases de datos y genera credenciales temporales.
- Transient: Almacena secretos temporales y de corta duración.
- RabbitMQ: Almacena credenciales de RabbitMQ y genera credenciales temporales.
Convenciones de Nombres:
Muchas de las convenciones que se deben implementar en HashiCorp Vault, son con base a la configuración del microservicio, especialmente en la sección Core
y Vault
:
{ "Core": { "AppName": "ms-archetype", "Version": "v1", "Description": "Microservice Archetype Template", "Business": "CodeDesignPlus", "Contact": { "Name": "CodeDesignPlus", "Email": "codedesignplus@outlook.com" } }, "Vault": { "Enable": true, "Address": "http://127.0.0.1:8200", "AppName": "ms-archetype", "Solution": "archetype", "Token": "root", "Mongo": { "Enable": true, "TemplateConnectionString": "mongodb://{0}:{1}@localhost:27017" }, "RabbitMQ": { "Enable": true } }}
De acuerdo a la configuración anterior, es importante tener en cuenta los siguientes conceptos:
- Solution: Nombre de la solución o proyecto como por ejemplo Jira, Trello, Management, etc. En este caso, se ha definido como
archetype
- Microservice: Nombre del microservicio o componente como por ejemplo Auth, Gateway, Users, Organization, etc. En este caso, se ha definido como
ms-archetype
Ahora profundicemos en las convenciones de nombres para cada uno de los motores de secretos:
El motor de secretos Key Vault
se encarga de almacenar y gestionar claves y secretos sensibles.
-
El administrador crea un
App Role
con el nombre de la solución y la política de acceso para la autenticación del microservicio con ayuda de la librearíaCodeDesignPlus.Net.Vault
.Ejemplo:
- archetype-approle
- jira-approle
- trello-approle
- management-approle
Terminal window vault write auth/approle/role/archetype-approle policies="full-access" -
El administrador habilita el motor de secretos
Key Vault
Ejemplo:
- ms-archetype
- ms-organization
- ms-products
- ms-orders
Terminal window vault secrets enable -path=archetype-keyvalue kv-v2 -
El administrador crea los secretos sensibles del microservicio con base al archivo
appsettings.json
.Ejemplo: Supongamos que el
appsettings.json
tiene las siguientes claves:{"Redis": {"Instances": {"Core": {"ConnectionString": "localhost:6379"}}}}El administrador almacena los siguientes secretos en el
Key Vault
:Terminal window vault kv put -mount=archetype-keyvalue ms-archetype Redis:Instances:Core:ConnectionString=localhost:6379 -
Para visualizar los secretos almacenados en el
Key Vault
, el administrador pudede ejecutar el siguiente comando:Terminal window vault kv get -mount=archetype-keyvalue ms-archetypePero tambien puede ingresar a la plataforma de
Vault
y visualizar los secretos almacenados en elKey Vault
.-
Ingresar a la plataforma de
Vault
en la URLhttp://localhost:8200
. -
Ingresar a la sección de
Secrets
y seleccionar elKey Vault
del microservicio. -
Visualizar los secretos almacenados en el
Key Vault
.
-
El motor de secretos Database
se encarga de almacenar credenciales de administración de la base de datos y generar credenciales temporales para acceder a las bases de datos de los microservicios. La libreriá CodeDesignPlus.Net.Vault
facilita la gestión de las credenciales y la rotación de claves.
-
El administrador crea un
App Role
con el nombre de la solución y la política de acceso para la autenticación del microservicio con ayuda de la librearíaCodeDesignPlus.Net.Vault
.Ejemplo:
- archetype-approle
- jira-approle
- trello-approle
- management-approle
Terminal window vault write auth/approle/role/archetype-approle policies="full-access" -
El administrador habilita el motor de secretos
Database
Ejemplo:
- ms-archetype
- ms-organization
- ms-products
- ms-orders
Terminal window vault secrets enable -path=archetype-database database -
El administrador crea la conexión a la base de datos para el microservicio
Ejemplo:
- db-ms-archetype
- db-ms-organization
- db-ms-products
- db-ms-orders
Terminal window vault write archetype-database/config/db-ms-archetype \plugin_name=mongodb-database-plugin \allowed_roles="ms-archetype-mongo-role" \connection_href="mongodb://{{username}}:{{password}}@mongo:27017/admin?ssl=false" \username="admin" \password="password" -
El administrador crea el rol de acceso para obtener las credenciales dinamicas de la base de datos.
Ejemplo:
- ms-archetype-mongo-role
- ms-organization-mongo-role
- ms-products-mongo-role
- ms-orders-mysql-role
Terminal window vault write archetype-database/roles/ms-archetype-mongo-role \db_name=db-ms-archetype \creation_statements='{ "db": "admin", "roles": [{ "role": "readWrite", "db": "db-ms-archetype" }] }' \default_ttl="1h" \max_ttl="24h" -
Para obtener las conexiones creadas en el
Vault
el administrador puede ejecutar el siguiente comando:Terminal window vault read archetype-database/creds/ms-archetype-mongo-rolePero tambien puede ingresar a la plataforma de
Vault
y visualizar las conexiones creadas en elDatabase
.-
Ingresar a la plataforma de
Vault
en la URLhttp://localhost:8200
. -
Ingresar a la sección de
Database
y seleccionar elDatabase
del microservicio. -
Visualizar las conexiones creadas en el
Database
.
-
El motor de secretos Transit
se encarga de almacenar secretos temporales y de corta duración. Es útil para almacenar secretos que deben ser eliminados después de un corto período de tiempo, como tokens de acceso o claves temporales.
-
El administrador crea un
App Role
con el nombre de la solución y la política de acceso para la autenticación del microservicio con ayuda de la librearíaCodeDesignPlus.Net.Vault
.Ejemplo:
- archetype-approle
- jira-approle
- trello-approle
- management-approle
Terminal window vault write auth/approle/role/archetype-approle policies="full-access" -
El administrador habilita el motor de secretos
Transit
Ejemplo:
- ms-archetype
- ms-organization
- ms-products
- ms-orders
Terminal window vault secrets enable -path=archetype-transit transit -
El desarrollador crea un secreto temporal con la ayuda de la librearía
CodeDesignPlus.Net.Vault
y el servicioIVaultTransit
.var transit = serviceProvider.GetRequiredService<IVaultTransit>();var context = Guid.NewGuid().ToString();var (key, ciphertext) = await transit.EncryptAsync("Custom Value", context);var decrypt = await transit.DecryptAsync(key, ciphertext, context); -
Para visualizar los secretos almacenados en el
Transit
, el administrador puede ingresar a la plataforma deVault
y visualizar los secretos almacenados en elTransit
.-
Ingresar a la plataforma de
Vault
en la URLhttp://localhost:8200
. -
Visualizar los secretos almacenados en el
Transit
.
-
El motor de secretos RabbitMQ
se encarga de almacenar credenciales de RabbitMQ y generar credenciales temporales para cada microservicio. La libreriá CodeDesignPlus.Net.Vault
facilita la gestión de las credenciales y la rotación de claves.
-
El administrador crea un
App Role
con el nombre de la solución y la política de acceso para la autenticación del microservicio con ayuda de la librearíaCodeDesignPlus.Net.Vault
.Ejemplo:
- archetype-approle
- jira-approle
- trello-approle
- management-approle
Terminal window vault write auth/approle/role/archetype-approle policies="full-access" -
El administrador habilita el motor de secretos
Transit
Ejemplo:
- ms-archetype
- ms-organization
- ms-products
- ms-orders
Terminal window vault secrets enable -path=archetype-rabbitmq rabbitmq -
El administrador crea la conexión a RabbitMQ para la solución
Ejemplo:
- archetype-rabbitmq
- jira-rabbitmq
- trello-rabbitmq
- management-rabbitmq
Terminal window vault write archetype-rabbitmq/config/connection \connection_uri="http://rabbitmq:15672" \username="admin" \password="password" -
El administrador crea el rol de acceso para obtener las credenciales dinamicas de RabbitMQ que usara el microservicio.
Ejemplo:
- ms-archetype-rabbitmq-role
- ms-organization-rabbitmq-role
- ms-products-rabbitmq-role
- ms-orders-rabbitmq-role
Terminal window vault write archetype-rabbitmq/roles/ms-archetype-rabbitmq-role \vhosts='{"/":{"write": ".*", "read": ".*", "configure": ".*"}}' -
Para visualizar las conexiones creadas en el
RabbitMQ
, el administrador puede ejecutar el siguiente comando:Terminal window vault read archetype-rabbitmq/creds/ms-archetype-rabbitmq-role
Beneficios:
- Permite almacenar y acceder de forma segura a credenciales, claves API y otros datos sensibles.
- Mejora la seguridad al evitar el almacenamiento de secretos en archivos de configuración o código fuente.
- Facilita la rotación de claves y la gestión de secretos en entornos de desarrollo, pruebas y producción.
Acceso:
Para acceder a la interfaz de usuario de Vault, visita http://localhost:8200
(usando el token root
para el entorno de desarrollo).
Para ingresar a la plataforma de Vault
se debe ingresar el token de acceso root
en el campo Token
y presionar el botón Sign in
.

Una vez ingresado el token de acceso, se visualiza la página principal de Vault
con los motores de secretos habilitados que se habilitaron desde el archivo config-vault.sh
o config-vault.ps1
.

El motor de secretos Key Vault
se encarga de almacenar y gestionar claves y secretos sensibles.

El motor de secretos Database
se encarga de almacenar credenciales de administración de la base de datos y generar credenciales temporales para acceder a las bases de datos de los microservicios.

El motor de secretos Transit
se encarga de almacenar secretos temporales y de corta duración.

El motor de secretos RabbitMQ
se encarga de almacenar credenciales de RabbitMQ y generar credenciales temporales para cada microservicio.

Configuración:
El archivo docker-compose.yaml
incluye un servicio de Vault sin ninguna configuración adicional. Para configurar Vault con métodos de autenticación, motores de secretos, políticas y roles, y escribir los secretos iniciales, el arquetipo de CodeDesignPlus proporciona dos scripts de configuración (Windows y Linux) que se pueden ejecutar en el entorno de desarrollo. Estos scripts se encuentran en la carpeta tools/vault
del microservicio creado con el generador de CodeDesignPlus.
Configura Vault con métodos de autenticación, motores de secretos, políticas y roles, y escribe los secretos iniciales.
#!/bin/bash
# Define colorsBLUE='\033[0;34m'NC='\033[0m' # No color
# ASCII Art for CodeDesignPlusascii_art=$(cat <<'EOF' ___ _ ___ _ ___ _ / __\___ __| | ___ / \___ ___(_) __ _ _ __ / _ \ |_ _ ___ / / / _ \ / _` |/ _ \ / /\ / _ \/ __| |/ _` | '_ \ / /_)/ | | | / __|/ /__| (_) | (_| | __// /_// __/\__ \ | (_| | | | / ___/| | |_| \__ \\____/\___/ \__,_|\___/___,' \___||___/_|\__, |_| |_\/ |_|\__,_|___/ |___/EOF)echo "$ascii_art"
# Your Vault Address and Loginexport VAULT_ADDR="http://localhost:8200"echo "${BLUE}-Logging in to Vault...${NC}"vault login token=root
newlines=$'\n'
# Enable AppRoleecho "$newlines"echo "${BLUE}1. Enabling auth methods...${NC}"if vault auth list | grep -q 'approle/'; then echo " - The method of authentication 'approle' already exists."else echo " - Enabling the method of authentication 'approle'..." vault auth enable approlefi
# Enable Secret, database and rabbtimqecho "$newlines"echo "${BLUE}2. Enabling secrets engines...${NC}"if vault secrets list | grep -q 'vault-keyvalue/'; then echo " - The secrets engine 'kv-v2' already exists in 'vault-keyvalue/'."else echo " - Enabling the secrets engine 'kv-v2' in 'vault-keyvalue/'..." vault secrets enable -path=vault-keyvalue kv-v2fi
if vault secrets list | grep -q 'vault-database/'; then echo " - The secrets engine 'database' already exists in 'vault-database/'."else echo " - Enabling the secrets engine 'database' in 'vault-database/'..." vault secrets enable -path=vault-database databasefi
if vault secrets list | grep -q 'vault-rabbitmq/'; then echo " - The secrets engine 'rabbitmq' already exists in 'vault-rabbitmq/'."else echo " - Enabling the secrets engine 'rabbitmq' in 'vault-rabbitmq/'..." vault secrets enable -path=vault-rabbitmq rabbitmqfi
if vault secrets list | grep -q 'vault-transit/'; then echo " - The secrets engine 'transit' already exists in 'vault-transit/'."else echo " - Enabling the secrets engine 'transit' in 'vault-transit/'..." vault secrets enable -path=vault-transit transitfi
# Create policiesecho "$newlines"policy_name="full-access"if vault policy read $policy_name > /dev/null 2>&1; then echo "${BLUE}3. The policy '$policy_name' already exists.${NC}"else echo "${BLUE}3. Creating policy '$policy_name'...${NC}" vault policy write $policy_name - <<EOFpath "*" { capabilities = ["create", "read", "update", "delete", "list"]}EOFfi
# Create rolesecho "$newlines"role_name="vault-approle"if vault read auth/approle/role/$role_name > /dev/null 2>&1; then echo "${BLUE}4. The AppRole '$role_name' already exists.${NC}"else echo "${BLUE}4. Creating AppRole '$role_name'...${NC}" vault write auth/approle/role/$role_name policies="full-access"fi
# Get Role ID and Secret ID, etc...role_id=$(vault read auth/approle/role/vault-approle/role-id | grep 'role_id' | awk '{print $2}')
secret_id=$(vault write -f auth/approle/role/vault-approle/secret-id | grep 'secret_id ' | awk '{print $2}')
if [ -z "$role_id" ] || [ -z "$secret_id" ]; then echo "Error: Not found role_id or secret_id" exit 1fi
echo " Role ID: $role_id"echo " Secret ID: $secret_id"
# Login with approleecho "$newlines"echo "${BLUE}5. Login with approle...${NC}"vault write auth/approle/login role_id=$role_id secret_id=$secret_id
# Write secrets, db config, rabbitmq configecho "$newlines"echo "${BLUE}6. Writing secrets...${NC}"vault kv put -mount=vault-keyvalue ms-archetype \ Security:ClientId=a74cb192-598c-4757-95ae-b315793bbbca \ Security:ValidAudiences:0=a74cb192-598c-4757-95ae-b315793bbbca \ Security:ValidAudiences:1=api://a74cb192-598c-4757-95ae-b315793bbbca
vault kv get -mount=vault-keyvalue ms-archetype
# Write database configurationecho "$newlines"echo "${BLUE}7. Writing database configuration...${NC}"vault write vault-database/config/db-ms-archetype \ plugin_name=mongodb-database-plugin \ allowed_roles="ms-archetype-mongo-role" \ connection_url="mongodb://{{username}}:{{password}}@mongo:27017/admin?ssl=false" \ username="admin" \ password="password"
vault write vault-database/roles/ms-archetype-mongo-role \ db_name=db-ms-archetype \ creation_statements='{ "db": "admin", "roles": [{ "role": "readWrite", "db": "db-ms-archetype" }] }' \ default_ttl="1h" \ max_ttl="24h"
vault read vault-database/creds/ms-archetype-mongo-role
# Write rabbitmq configurationecho "$newlines"echo "${BLUE}8. Writing rabbitmq configuration...${NC}"
sleep 12
vault write vault-rabbitmq/config/connection \ connection_uri="http://rabbitmq:15672" \ username="admin" \ password="password"
vault write vault-rabbitmq/roles/ms-archetype-rabbitmq-role \ vhosts='{"/":{"write": ".*", "read": ".*", "configure": ".*"}}'
vault read vault-rabbitmq/creds/ms-archetype-rabbitmq-role
Configura Vault con métodos de autenticación, motores de secretos, políticas y roles, y escribe los secretos iniciales.
$newlines = "`n"
# --- ASCII Art for CodeDesignPlus ---$asciiArt = @" ___ _ ___ _ ___ _ / __\___ __| | ___ / \___ ___(_) __ _ _ __ / _ \ |_ _ ___ / / / _ \ / _` |/ _ \ / /\ / _ \/ __| |/ _` | '_ \ / /_)/ | | | / __|/ /__| (_) | (_| | __// /_// __/\__ \ | (_| | | | / ___/| | |_| \__ \\____/\___/ \__,_|\___/___,' \___||___/_|\__, |_| |_\/ |_|\__,_|___/ |___/"@Write-Host $asciiArt
# Set Vault Address$env:VAULT_ADDR = "http://localhost:8200"
# Vault LoginWrite-Host "-Logging in to Vault..." -ForegroundColor Bluevault login token=root
# --- 1. Enabling Auth Methods ---Write-Host $newlinesWrite-Host "1. Enabling auth methods..." -ForegroundColor Blueif (vault auth list | Select-String -Pattern 'approle/' -Quiet) { Write-Host " - The method of authentication 'approle' already exists."}else { Write-Host " - Enabling the method of authentication 'approle'..." vault auth enable approle}
# --- 2. Enabling Secret Engines ---Write-Host $newlinesWrite-Host "2. Enabling secrets engines..." -ForegroundColor Blue
if (vault secrets list | Select-String -Pattern 'vault-keyvalue/' -Quiet) { Write-Host " - The secrets engine 'kv-v2' already exists in 'vault-keyvalue/'."}else { Write-Host " - Enabling the secrets engine 'kv-v2' in 'vault-keyvalue/'..." vault secrets enable -path=vault-keyvalue kv-v2}
if (vault secrets list | Select-String -Pattern 'vault-database/' -Quiet) { Write-Host " - The secrets engine 'database' already exists in 'vault-database/'."}else { Write-Host " - Enabling the secrets engine 'database' in 'vault-database/'..." vault secrets enable -path=vault-database database}
if (vault secrets list | Select-String -Pattern 'vault-rabbitmq/' -Quiet) { Write-Host " - The secrets engine 'rabbitmq' already exists in 'vault-rabbitmq/'."}else { Write-Host " - Enabling the secrets engine 'rabbitmq' in 'vault-rabbitmq/'..." vault secrets enable -path=vault-rabbitmq rabbitmq}
if (vault secrets list | Select-String -Pattern 'vault-transit/' -Quiet) { Write-Host " - The secrets engine 'transit' already exists in 'vault-transit/'."}else { Write-Host " - Enabling the secrets engine 'transit' in 'vault-transit/'..." vault secrets enable -path=vault-transit transit}
# --- 3. Applying Policies ---Write-Host $newlinesWrite-Host "3. Applying policies..." -ForegroundColor Blue$policyName = "full-access"vault policy read $policyNameif ($?) { Write-Host " - The policy '$policyName' already exists."}else { Write-Host " - Creating policy '$policyName'..." $policyContent = @"path "*" { capabilities = ["create", "read", "update", "delete", "list"]}"@ $policyContent | vault policy write $policyName -}
# --- 4. Creating Roles ---Write-Host $newlinesWrite-Host "4. Creating roles..." -ForegroundColor Blue$roleName = "vault-approle"vault read auth/approle/role/$roleNameif ($?) { Write-Host " - The AppRole '$roleName' already exists."}else { Write-Host " - Creating AppRole '$roleName'..." vault write auth/approle/role/$roleName policies="full-access"}
# Get role_id$role_id_output = vault read auth/approle/role/vault-approle/role-id$role_id_match = $role_id_output | Select-String -Pattern 'role_id\s+([\w-]+)'if ($role_id_match) { $role_id = $role_id_match.Matches[0].Groups[1].Value}else { Write-Error "Error: Could not find role_id" exit 1}
# Get secret_id$secret_id_output = vault write -f auth/approle/role/vault-approle/secret-id$secret_id_match = $secret_id_output | Select-String -Pattern 'secret_id\s+([\w-]+)'if ($secret_id_match) { $secret_id = $secret_id_match.Matches[0].Groups[1].Value}else { Write-Error "Error: Could not find secret_id" exit 1}
if (-not $role_id -or -not $secret_id) { Write-Error "Error: Not found role_id or secret_id" exit 1}
Write-Host " Role ID: $role_id"Write-Host " Secret ID: $secret_id"
# --- 5. Login with approle ---Write-Host $newlinesWrite-Host "5. Login with approle..." -ForegroundColor Bluevault write auth/approle/login role_id=$role_id secret_id=$secret_id
# --- 6. Writing secrets ---Write-Host $newlinesWrite-Host "6. Writing secrets..." -ForegroundColor Bluevault kv put -mount=vault-keyvalue ms-archetype ` Security:ClientId=a74cb192-598c-4757-95ae-b315793bbbca ` Security:ValidAudiences:0=a74cb192-598c-4757-95ae-b315793bbbca ` Security:ValidAudiences:1=api://a74cb192-598c-4757-95ae-b315793bbbca
vault kv get -mount=vault-keyvalue ms-archetype
# --- 7. Writing database configuration ---Write-Host $newlinesWrite-Host "7. Writing database configuration..." -ForegroundColor Bluevault write vault-database/config/db-ms-archetype ` plugin_name=mongodb-database-plugin ` allowed_roles="ms-archetype-mongo-role" ` connection_url="mongodb://{{username}}:{{password}}@mongo:27017/admin?ssl=false" ` username="admin" ` password="password"
vault write vault-database/roles/ms-archetype-mongo-role ` db_name=db-ms-archetype ` creation_statements="{ """db""": """admin""", """roles""": [{ """role""": """readWrite""", """db""": """db-ms-archetype""" }] }" ` default_ttl="1h" ` max_ttl="24h"
vault read vault-database/creds/ms-archetype-mongo-role
# --- 8. Writing rabbitmq configuration ---Write-Host $newlinesWrite-Host "8. Writing rabbitmq configuration..." -ForegroundColor Blue
Write-Host "Waiting for RabbitMQ to start..."Start-Sleep -Seconds 12
vault write vault-rabbitmq/config/connection ` connection_uri="http://rabbitmq:15672" ` username="admin" ` password="password"
vault write vault-rabbitmq/roles/ms-archetype-rabbitmq-role ` vhosts="{"""/""":{"""write""": """.*""", """read""": """.*""", """configure""": """.*"""}}"
vault read vault-rabbitmq/creds/ms-archetype-rabbitmq-role
RabbitMQ
RabbitMQ es un broker de mensajes de código abierto que implementa el protocolo AMQP (Advanced Message Queuing Protocol). Permite la comunicación asíncrona entre servicios, desacoplando las aplicaciones y facilitando la escalabilidad y resiliencia.
Se basa en el patrón de diseño Publicar/Suscribir (Publish/Subscribe) y se utiliza en arquitecturas Orientadas a Eventos (Event-Driven Architecture). Los servicios publican mensajes en un exchange, y otros servicios se suscriben a las colas para recibir mensajes de interés.
Convenciones de Nombres:
El SDK de CodeDesignPlus implementa una serie de convenciones para los exchanges, colas y rutas de RabbitMQ. Estas convenciones se basan en la configuración del microservicio, especialmente en la sección Core
:
{ "Core": { "AppName": "ms-archetype", "Version": "v1", "Description": "Microservice Archetype Template", "Business": "CodeDesignPlus", "Contact": { "Name": "CodeDesignPlus", "Email": "codedesignplus@outlook.com" } }}
- Exchange:
[bussiness].[appname].v[number-version].[aggregate|entity].[event]
- Queue:
[bussiness].[appname].v[number-version].[aggregate|entity].[event]
- Exchange Dlx:
[bussiness].[appname].v[number-version].[aggregate|entity].[event].dlx
- Queue Dlx:
[bussiness].[appname].v[number-version].[aggregate|entity].[event].dlx
Beneficios:
- Permite la comunicación asíncrona entre servicios, mejorando la escalabilidad y desacoplamiento.
- Facilita la implementación de arquitecturas orientadas a eventos y patrones de diseño de mensajería.
- Proporciona mecanismos de colas, exchanges y enrutamiento para gestionar mensajes de forma eficiente.
Acceso:
El entorno de desarrollo incluye un servicio de RabbitMQ con las siguientes credenciales y accesos:
-
UI:
http://localhost:15672
(con usuarioadmin
y contraseñapassword
). -
AMQP:
amqp://localhost:5672
(conexión para aplicaciones).
MongoDB
MongoDB es una base de datos NoSQL orientada a documentos. Almacena datos en formato JSON-like (BSON), lo que permite una gran flexibilidad en el esquema de datos. Es ideal para aplicaciones con requisitos de datos variados y que necesitan una alta escalabilidad horizontal.
Es común en microservicios que necesitan flexibilidad de datos. Al no tener un esquema rígido como las bases de datos relacionales, permite evolucionar fácilmente los datos de cada microservicio.

Convenciones de Nombres:
El SDK de CodeDesignPlus implementa una serie de convenciones para el nombre de las bases de datos y las colecciones de MongoDB. Estas convenciones se basan en la configuración del microservicio, especialmente en la sección Core
:
{ "Core": { "AppName": "ms-archetype", "Version": "v1", "Description": "Microservice Archetype Template", "Business": "CodeDesignPlus", "Contact": { "Name": "CodeDesignPlus", "Email": "codedesignplus@outlook.com" } }}
- Base de Datos:
db-[appname]
- Colección:
[aggregate|entity]
Beneficios:
- Almacenamiento flexible de datos, ideal para aplicaciones con requisitos de datos variados.
- Escalabilidad horizontal, permitiendo manejar grandes volúmenes de datos y tráfico.
- Facilidad de uso y mantenimiento, con una sintaxis similar a JSON y una comunidad activa.
Acceso:
El servicio de MongoDB se encuentra disponible en mongodb://localhost:27017
(con usuario admin
y contraseña password
). Sin embargo, el servicio de Vault se encarga de gestionar las credenciales para los microserviciosa partir de la siguiente configuración:
# ...# Write database configurationecho "7. Writing database configuration..."vault write archetype-database/config/db-ms-archetype \ plugin_name=mongodb-database-plugin \ allowed_roles="ms-archetype-mongo-role" \ connection_href="mongodb://{{username}}:{{password}}@mongo:27017/admin?ssl=false" \ username="admin" \ password="password"
vault write archetype-database/roles/ms-archetype-mongo-role \ db_name=db-ms-archetype \ creation_statements='{ "db": "admin", "roles": [{ "role": "readWrite", "db": "db-ms-archetype" }] }' \ default_ttl="1h" \ max_ttl="24h"
vault read archetype-database/creds/ms-archetype-mongo-role# ...
Este script de configuración de Vault es responsable de escribir la configuración de la base de datos y los roles de acceso, y de generar credenciales temporales para acceder a la base de datos.
Redis
Redis es una base de datos en memoria de tipo clave-valor que puede usarse como cache, broker de mensajes y base de datos. Su principal fortaleza es su velocidad y baja latencia, ideal para aplicaciones que requieren respuestas rápidas y manejo de sesiones.
Se usa como cache para datos que no cambian frecuentemente o como un almacenamiento rápido de datos volátiles que se requiere que sean accedidos muy rápidamente por la aplicación.
Convenciones de Nombres:
El SDK de CodeDesignPlus implementa una serie de convenciones para los nombres de las bases de datos y las claves de Redis. Estas convenciones se basan en la configuración del microservicio, especialmente en la sección Core
:
{ "Core": { "AppName": "ms-archetype", "Version": "v1", "Description": "Microservice Archetype Template", "Business": "CodeDesignPlus", "Contact": { "Name": "CodeDesignPlus", "Email": "codedesignplus@outlook.com" } }}
- Key:
[bussiness]:[appname]:[key]

Beneficios:
- Cache de alto rendimiento y broker de mensajes, ideal para aplicaciones que requieren respuestas rápidas.
- Almacenamiento en memoria, lo que permite una baja latencia y alta velocidad de acceso a los datos.
- Persistencia de datos, permitiendo almacenar datos en disco para recuperarlos en caso de fallo.
Acceso:
-
Disponible en
redis://localhost:6379
para clientes instalados en la máquina local oredis://redis:6379
para clientes en contenedores como Redis Insight aal que se puede acceder enhttp://localhost:5540/
.
Grafana
Grafana es una plataforma de código abierto para visualización y análisis de datos. Permite crear dashboards personalizados con gráficos, tablas y paneles para monitorear métricas de la aplicación y la infraestructura. Se integra con múltiples fuentes de datos como Prometheus, Loki y otros.
Es esencial para observar la salud y el rendimiento de los microservicios. Facilita la detección temprana de problemas y la optimización de recursos.
Beneficios:
- Permite crear dashboards para visualizar métricas de la aplicación y la infraestructura.
- Integración con múltiples fuentes de datos como Prometheus, Loki y otros.
- Alertas y notificaciones para detectar problemas y optimizar recursos.
Acceso:
Para acceder a Grafana, visita http://localhost:3000
.
La pagina de inicio de Grafana muestra los dashboards y las fuentes de datos disponibles.

La sección de Dashboards permite crear, editar y visualizar dashboards personalizados con gráficos, tablas y paneles.

La sección de Data Sources permite configurar y administrar las fuentes de datos para los dashboards.

Configuración:
El archivo docker-compose.yaml
incluye configuraciones para Grafana, como fuentes de datos y dashboards predefinidos.
Configuración de las fuentes de datos para Grafana, incluyendo Prometheus y Loki.
apiVersion: 1
datasources:- name: Prometheus type: prometheus uid: prometheus access: proxy orgId: 1 url: http://prometheus:9090 basicAuth: false isDefault: false version: 1 editable: false jsonData: httpMethod: GET- name: Tempo type: tempo access: proxy orgId: 1 url: http://tempo:3200 basicAuth: false isDefault: true version: 1 editable: false apiVersion: 1 uid: tempo jsonData: httpMethod: GET serviceMap: datasourceUid: prometheus- name: Loki type: loki access: proxy orgId: 1 url: http://loki:3100 basicAuth: false isDefault: false version: 1 editable: false
Configura el proveedor de dashboards para que cargue los dashboards desde el directorio /var/lib/grafana/dashboards
.
apiVersion: 1
providers: - name: 'default' orgId: 1 folder: '' type: 'file' disableDeletion: false editable: true options: path: /var/lib/grafana/dashboards
OpenTelemetry Collector
El OpenTelemetry Collector es un componente que recibe datos de telemetría (métricas, logs y trazas) generados por las aplicaciones y los envía a los sistemas de back-end de monitoreo. Es un componente flexible y configurable que simplifica la recolección y envío de datos de telemetría.
Beneficios:
- Recolecta, procesa y exporta datos de telemetría (métricas, logs y trazas) hacia los diferentes backends.
- Simplifica la configuración y recolección de datos de telemetría, reduciendo la complejidad de la instrumentación.
- Permite la integración con múltiples sistemas de monitoreo como Prometheus, Loki y Jaeger.
Acceso:
Para enviar datos de telemetría al OpenTelemetry Collector, las aplicaciones deben configurar los puertos de recolección definidos en el archivo de configuración otel-config.yaml
:
- OTLP gRPC:
localhost:4317
- OTLP HTTP:
localhost:4318
Pero el componente de OpenTelemetry Collector al no tener una interfaz gráfica. Sin embargo, se puede visualizar el estado del mismo en los paneles de grafana Grafana como processors
, receivers
, exporters
y el estado del OTEL en el panel Collector
. Estos pueden o no mostrar información dependiendo de la interacción con el OTEL.
El panel de Receivers
muestra el comportamiento de los receptores de datos del OTEL.

El panel de Processors
muestra el comportamiento de los procesadores de datos del OTEL.

El panel de Exporters
muestra el comportamiento de los exportadores de datos del OTEL.

El panel de Collector
muestra el estado general del OTEL.

Configuración:
El archivo docker-compose.yaml
incluye configuraciones para el OpenTelemetry Collector, como el archivo de configuración otel-config.yaml
.
receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 prometheus: config: # Automatically scrape the Prometheus metrics scrape_configs: - job_name: otel-collector-metrics scrape_interval: 10s static_configs: - targets: ['localhost:8888'] - job_name: 'loki' scrape_interval: 10s static_configs: - targets: ['host.docker.internal:3100'] - job_name: 'tempo' scrape_interval: 10s static_configs: - targets: ['host.docker.internal:3200']
exporters: debug: verbosity: detailed loki: endpoint: "http://host.docker.internal:3100/loki/api/v1/push" otlp: endpoint: host.docker.internal:5317 # Send to Tempo tls: insecure: true prometheus: endpoint: 0.0.0.0:8889 # Endpoint to scrape metrics from prometheus
service: pipelines: traces: receivers: [otlp] exporters: [otlp]
logs: receivers: [otlp] exporters: [loki]
metrics: receivers: [otlp, prometheus] exporters: [prometheus]
Loki
Loki es un sistema de agregación de logs de código abierto. Está diseñado para ser rentable y fácil de operar, lo que lo hace ideal para el monitoreo de logs en microservicios. Es especialmente efectivo en combinación con Grafana para la visualización y el análisis de logs.
Beneficios:
- Almacenamiento de logs en texto plano y agregacion de forma simple.
- Integración con Grafana para visualización y análisis de logs.
- Bajo costo y fácil operación, ideal para microservicios y aplicaciones distribuidas.
Acceso:
El componente de Loki no tiene una interfaz gráfica. Sin embargo, el servicio expone un puerto para la recolección de datos en 3100
que es usado por Open Telemetry Collector para enviar los logs y por Grafana para visualizarlos.
Para visualizar los logs en Grafana, se debe configurar una fuente de datos de Loki y proceder al panel de logs en Grafana.
El panel de Explore
en Grafana permite realizar consultas y visualizar logs de Loki.

Las ultimas versiones de Grafana permiten visualizar los logs en un panel dedicado.

Configuración:
El archivo docker-compose.yaml
incluye configuraciones para Loki, como el archivo de configuración loki-config.yaml
que configura el servidor con almacenamiento en filesystem y habilitación de la API.
auth_enabled: false
server: http_listen_port: 3100 grpc_listen_port: 9096
memberlist: bind_addr: - 0.0.0.0
common: instance_addr: 127.0.0.1 path_prefix: /tmp/loki storage: filesystem: chunks_directory: /tmp/loki/chunks rules_directory: /tmp/loki/rules replication_factor: 1 ring: kvstore: store: inmemory
query_range: results_cache: cache: embedded_cache: enabled: true max_size_mb: 100
schema_config: configs: - from: 2020-10-24 store: tsdb object_store: filesystem schema: v13 index: prefix: index_ period: 24h
ruler: alertmanager_url: http://localhost:9093
Tempo
Tempo es un sistema de código abierto para el almacenamiento de trazas. Permite realizar un seguimiento de las peticiones a través de los distintos servicios de una arquitectura de microservicios, lo que facilita el diagnóstico de problemas y la optimización de la aplicación.
Es esencial para el seguimiento y la observabilidad en entornos de microservicios. Facilita la identificación de bottlenecks y errores en las solicitudes que atraviesan varios servicios.
Beneficios:
- Almacenamiento de trazas.
- Seguimiento de peticiones a través de los servicios.
- Diagnóstico de problemas y optimización de la aplicación.
Acceso:
El servicio de Tempo no cuenta con una interfaz gráfica. Sin embargo, se exponen los siguientes puertos:
5317
: Puerto de recepción de trazas OTLP gRPC.5318
: Puerto de recepción de trazas OTLP HTTP.3200
: Puerto de la API de Tempo y metricas.
Para visualizar las trazas en Grafana, se debe configurar una fuente de datos de Tempo y proceder al panel de trazas en Grafana.

Configuración:
El archivo docker-compose.yaml
incluye configuraciones para Tempo, como el archivo de configuración tempo-config.yaml
encargado de configurar el servidor con el backend local y el recolector de métricas.
stream_over_http_enabled: trueserver: http_listen_port: 3200 log_level: info
query_frontend: search: duration_slo: 5s throughput_bytes_slo: 1.073741824e+09 trace_by_id: duration_slo: 5s
distributor: receivers: otlp: protocols: http: endpoint: 0.0.0.0:4318 grpc: endpoint: 0.0.0.0:4317
ingester: max_block_duration: 5m # cut the headblock when this much time passes. this is being set for demo purposes and should probably be left alone normally
compactor: compaction: block_retention: 1h # overall Tempo trace retention. set for demo purposes
metrics_generator: registry: external_labels: source: tempo cluster: docker-compose storage: path: /tmp/tempo/generator/wal remote_write: - url: http://prometheus:9090/api/v1/write send_exemplars: true
storage: trace: backend: local # backend configuration to use wal: path: /tmp/tempo/wal # where to store the the wal locally local: path: /tmp/tempo/blocks
overrides: defaults: metrics_generator: processors: [service-graphs, span-metrics] # enables metrics generator
Prometheus
Prometheus es un sistema de monitoreo y alertas de código abierto. Recopila métricas de las aplicaciones y los servicios y las almacena en una base de datos de series temporales. Permite realizar consultas y crear alertas basadas en estas métricas. De esta forma se puede monitorear la salud y el rendimiento de la aplicación y la infraestructura.
Beneficios:
- Recolección y consulta de métricas para monitorear la salud y el rendimiento de la aplicación.
- Almacenamiento de métricas en una base de datos de series temporales.
- Creación de alertas para detectar problemas y optimizar recursos.
Acceso:
A diferencia de los otros servicios, Prometheus cuenta con una interfaz gráfica que se puede acceder en http://localhost:9090
.

En este punto, vemos que Prometheus realiza scraping de los datos de telemetría del OpenTelemetry Collector y los almacena en su base de datos de series temporales.
Para interactuar de una mejor manera con Prometheus, se puede configurar Grafana para que muestre las métricas de Prometheus en dashboards personalizados, lo que facilita la visualización y el análisis de las métricas. Los dashboards disponibles son:
- 15983: Dashboard de métricas de OpenTelemetry Collector.
- 17781: Dashboard de métricas de Loki.
- 19924: ASP.NET Core metrics from OpenTelemetry
- 19925: ASP.NET Core endpoint metrics from OpenTelemetry
El dashboard de métricas de OpenTelemetry Collector muestra información sobre los procesadores, receptores y exportadores de datos.

El dashboard de métricas de Loki muestra información sobre las métricas de logs y el estado del servicio.

El dashboard de métricas de ASP.NET Core muestra información sobre las métricas de la aplicación ASP.NET Core.

El dashboard de métricas de ASP.NET Core muestra información sobre las métricas de los endpoints de la aplicación ASP.NET Core.

Configuración:
El archivo docker-compose.yaml
incluye configuraciones para Prometheus, como el archivo de configuración prometheus-config.yaml
que define las reglas de alerta, los targets y los jobs para realizar scraping del otel collector.
global:
scrape_configs: - job_name: "otel-collector" scrape_interval: 10s static_configs: - targets: ["otel-collector-contrib:8889"]
SonarQube
SonarQube es una plataforma de análisis estático de código que identifica problemas de calidad, vulnerabilidades y errores en el código fuente. Es esencial para mantener la calidad del código y prevenir problemas en producción.
Beneficios:
- Identifica problemas de calidad, vulnerabilidades y errores en el código fuente.
- Mejora la calidad del código y reduce los errores y vulnerabilidades.
- Facilita la revisión del código y la detección temprana de problemas.
Cómo usar:
El arquetipo de CodeDesignPlus incluye scripts para ejecutar los análisis de SonarQube en el código fuente. Estos scripts se encuentran en la carpeta tools/sonarqube
del microservicio creado con el generador de CodeDesignPlus.
-
Navegar a
http://localhost:9000
y loguearse con las credencialesadmin
yadmin
. -
Creamos el token de acceso para el análisis de código, para eso navegamos a
My Account
->Security
->Generate Tokens
. Ingresamos el nombre y seleccionamos Global Analysis Token. -
Asignamos el token a los scripts
sonarqube/sonar.ps1
osonarqube/sonar.sh
en la variabletoken
.Terminal window $token = "sqa_12f3d20d51de2b4c9639db0035d1c68dc4f2fff1"Terminal window token="sqa_12f3d20d51de2b4c9639db0035d1c68dc4f2fff1" -
Ejecuta el script
sonarqube/sonar.ps1
(Windows) osonarqube/sonar.sh
(Linux).#!/usr/bin/env pwsh#echo "Install dotnet-sonarscanner ----------------------------------------------------------------------------------------------------------------------"#dotnet tool install --global dotnet-sonarscannerWrite-Host "Start Sonarscanner -------------------------------------------------------------------------------------------------------------------------------"$org = "codedesignplus"$key = "CodeDesignPlus.Net.Microservice"$csproj = "CodeDesignPlus.Net.Microservice.sln"$report = "tests/**/coverage.opencover.xml"$server = "http://localhost:9000"$token = "sqa_12f3d20d51de2b4c9639db0035d1c68dc4f2fff1"cd ..dotnet test $csproj /p:CollectCoverage=true /p:CoverletOutputFormat=opencoverdotnet sonarscanner begin /o:$org /k:$key /d:sonar.host.url=$server /d:sonar.coverage.exclusions="**Tests*.cs,**/tests/load/*.js" /d:sonar.cs.opencover.reportsPaths=$report /d:sonar.login=$tokendotnet builddotnet sonarscanner end /d:sonar.login=$tokenTerminal window 404: Not Found -
El script ejecuta pruebas, genera reportes de cobertura, inicia un análisis de SonarQube, compila el código y finaliza el análisis.
Beneficios Clave para el Desarrollador
- Reducción del tiempo de configuración: El entorno Docker Compose reduce drásticamente el tiempo necesario para configurar un entorno de desarrollo, permitiendo que los desarrolladores empiecen a trabajar en la lógica de negocio rápidamente.
- Mayor calidad de código: El análisis de código estático con SonarQube/SonarCloud mejora la calidad del código, reduciendo errores y vulnerabilidades.
- Enfoque en el negocio: Al automatizar las tareas repetitivas, los desarrolladores pueden centrarse en el desarrollo de la lógica de negocio, aumentando la productividad y reduciendo la frustración.
- Consistencia en el equipo: El uso de Docker garantiza que todos los miembros del equipo trabajen con el mismo entorno, reduciendo las diferencias entre entornos de desarrollo y producción.
Con estas herramientas, CodeDesignPlus busca ofrecer una experiencia de desarrollo más eficiente, estable y agradable, acelerando la entrega de microservicios de alta calidad.