En esta sección, vamos a llevar a cabo una implementación completa de un sistema basado en microservicios. Este ejercicio práctico te permitirá aplicar los conceptos y técnicas aprendidas en los módulos anteriores. Vamos a construir una aplicación sencilla de gestión de pedidos que incluye varios microservicios.
Objetivos del Ejemplo Práctico
- Diseñar y definir los microservicios necesarios.
 - Implementar los microservicios utilizando una tecnología de tu elección (por ejemplo, Node.js, Spring Boot, etc.).
 - Configurar la comunicación entre los microservicios.
 - Desplegar los microservicios utilizando contenedores Docker.
 - Orquestar los microservicios con Kubernetes.
 - Implementar monitoreo y logging.
 - Asegurar los microservicios.
 
- Diseño y Definición de Microservicios
 
Microservicios Identificados
Para la aplicación de gestión de pedidos, identificamos los siguientes microservicios:
- Servicio de Usuarios: Gestiona la información de los usuarios.
 - Servicio de Productos: Gestiona el catálogo de productos.
 - Servicio de Pedidos: Gestiona la creación y seguimiento de pedidos.
 - Servicio de Notificaciones: Envía notificaciones a los usuarios sobre el estado de sus pedidos.
 
Diagrama de Arquitectura
+------------------+       +------------------+       +------------------+
| Servicio de      |       | Servicio de      |       | Servicio de      |
| Usuarios         |<----->| Pedidos          |<----->| Productos        |
+------------------+       +------------------+       +------------------+
        |                        |                        |
        v                        v                        v
+------------------+       +------------------+       +------------------+
| Servicio de      |       | Base de Datos   |       | Base de Datos    |
| Notificaciones   |       | de Pedidos      |       | de Productos     |
+------------------+       +------------------+       +------------------+
        |
        v
+------------------+
| Base de Datos    |
| de Usuarios      |
+------------------+
- Implementación de Microservicios
 
Servicio de Usuarios
Estructura del Proyecto
user-service/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── userservice/ │ │ │ ├── UserServiceApplication.java │ │ │ ├── controller/ │ │ │ │ └── UserController.java │ │ │ ├── model/ │ │ │ │ └── User.java │ │ │ └── repository/ │ │ │ └── UserRepository.java │ └── resources/ │ └── application.yml └── pom.xml
Código de Ejemplo
UserServiceApplication.java
package com.example.userservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}UserController.java
package com.example.userservice.controller;
import com.example.userservice.model.User;
import com.example.userservice.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserRepository userRepository;
    @GetMapping
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    @PostMapping
    public User createUser(@RequestBody User user) {
        return userRepository.save(user);
    }
}User.java
package com.example.userservice.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;
    // Getters and Setters
}UserRepository.java
package com.example.userservice.repository;
import com.example.userservice.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/userdb
    username: root
    password: password
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: trueServicio de Productos
Estructura del Proyecto
product-service/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── productservice/ │ │ │ ├── ProductServiceApplication.java │ │ │ ├── controller/ │ │ │ │ └── ProductController.java │ │ │ ├── model/ │ │ │ │ └── Product.java │ │ │ └── repository/ │ │ │ └── ProductRepository.java │ └── resources/ │ └── application.yml └── pom.xml
Código de Ejemplo
ProductServiceApplication.java
package com.example.productservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ProductServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductServiceApplication.class, args);
    }
}ProductController.java
package com.example.productservice.controller;
import com.example.productservice.model.Product;
import com.example.productservice.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/products")
public class ProductController {
    @Autowired
    private ProductRepository productRepository;
    @GetMapping
    public List<Product> getAllProducts() {
        return productRepository.findAll();
    }
    @PostMapping
    public Product createProduct(@RequestBody Product product) {
        return productRepository.save(product);
    }
}Product.java
package com.example.productservice.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private Double price;
    // Getters and Setters
}ProductRepository.java
package com.example.productservice.repository;
import com.example.productservice.model.Product;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
}application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/productdb
    username: root
    password: password
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: trueServicio de Pedidos
Estructura del Proyecto
order-service/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── orderservice/ │ │ │ ├── OrderServiceApplication.java │ │ │ ├── controller/ │ │ │ │ └── OrderController.java │ │ │ ├── model/ │ │ │ │ └── Order.java │ │ │ └── repository/ │ │ │ └── OrderRepository.java │ └── resources/ │ └── application.yml └── pom.xml
Código de Ejemplo
OrderServiceApplication.java
package com.example.orderservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}OrderController.java
package com.example.orderservice.controller;
import com.example.orderservice.model.Order;
import com.example.orderservice.repository.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/orders")
public class OrderController {
    @Autowired
    private OrderRepository orderRepository;
    @GetMapping
    public List<Order> getAllOrders() {
        return orderRepository.findAll();
    }
    @PostMapping
    public Order createOrder(@RequestBody Order order) {
        return orderRepository.save(order);
    }
}Order.java
package com.example.orderservice.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long userId;
    private Long productId;
    private Integer quantity;
    // Getters and Setters
}OrderRepository.java
package com.example.orderservice.repository;
import com.example.orderservice.model.Order;
import org.springframework.data.jpa.repository.JpaRepository;
public interface OrderRepository extends JpaRepository<Order, Long> {
}application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/orderdb
    username: root
    password: password
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: trueServicio de Notificaciones
Estructura del Proyecto
notification-service/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── notificationservice/ │ │ │ ├── NotificationServiceApplication.java │ │ │ ├── controller/ │ │ │ │ └── NotificationController.java │ │ │ ├── model/ │ │ │ │ └── Notification.java │ │ │ └── repository/ │ │ │ └── NotificationRepository.java │ └── resources/ │ └── application.yml └── pom.xml
Código de Ejemplo
NotificationServiceApplication.java
package com.example.notificationservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class NotificationServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(NotificationServiceApplication.class, args);
    }
}NotificationController.java
package com.example.notificationservice.controller;
import com.example.notificationservice.model.Notification;
import com.example.notificationservice.repository.NotificationRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/notifications")
public class NotificationController {
    @Autowired
    private NotificationRepository notificationRepository;
    @GetMapping
    public List<Notification> getAllNotifications() {
        return notificationRepository.findAll();
    }
    @PostMapping
    public Notification createNotification(@RequestBody Notification notification) {
        return notificationRepository.save(notification);
    }
}Notification.java
package com.example.notificationservice.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Notification {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long userId;
    private String message;
    // Getters and Setters
}NotificationRepository.java
package com.example.notificationservice.repository;
import com.example.notificationservice.model.Notification;
import org.springframework.data.jpa.repository.JpaRepository;
public interface NotificationRepository extends JpaRepository<Notification, Long> {
}application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/notificationdb
    username: root
    password: password
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
- Configuración de la Comunicación entre Microservicios
 
Para la comunicación entre microservicios, utilizaremos APIs RESTful. Cada microservicio expone endpoints que pueden ser consumidos por otros microservicios.
Ejemplo de Comunicación
El Servicio de Pedidos necesita obtener información del Servicio de Usuarios y del Servicio de Productos para crear un pedido.
OrderController.java (modificado)
package com.example.orderservice.controller;
import com.example.orderservice.model.Order;
import com.example.orderservice.repository.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/orders")
public class OrderController {
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private RestTemplate restTemplate;
    @GetMapping
    public List<Order> getAllOrders() {
        return orderRepository.findAll();
    }
    @PostMapping
    public Order createOrder(@RequestBody Order order) {
        // Obtener información del usuario
        String userUrl = "http://localhost:8081/users/" + order.getUserId();
        User user = restTemplate.getForObject(userUrl, User.class);
        // Obtener información del producto
        String productUrl = "http://localhost:8082/products/" + order.getProductId();
        Product product = restTemplate.getForObject(productUrl, Product.class);
        // Lógica adicional para crear el pedido
        return orderRepository.save(order);
    }
}User.java (cliente)
package com.example.orderservice.controller;
public class User {
    private Long id;
    private String name;
    private String email;
    // Getters and Setters
}Product.java (cliente)
package com.example.orderservice.controller;
public class Product {
    private Long id;
    private String name;
    private Double price;
    // Getters and Setters
}
- Despliegue con Docker
 
Dockerfile para el Servicio de Usuarios
Dockerfile
FROM openjdk:11-jre-slim COPY target/user-service-0.0.1-SNAPSHOT.jar user-service.jar ENTRYPOINT ["java", "-jar", "user-service.jar"]
Construcción y Ejecución del Contenedor
# Construir la imagen docker build -t user-service . # Ejecutar el contenedor docker run -d -p 8081:8080 --name user-service user-service
Repite el proceso para los otros microservicios cambiando los puertos y nombres de contenedores según sea necesario.
- Orquestación con Kubernetes
 
Despliegue de Kubernetes
user-service-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
      - name: user-service
        image: user-service:latest
        ports:
        - containerPort: 8080user-service-service.yml
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080Aplica los archivos de configuración:
Repite el proceso para los otros microservicios.
- Monitoreo y Logging
 
Configuración de Prometheus y Grafana
- Despliega Prometheus y Grafana en tu clúster de Kubernetes.
 - Configura los microservicios para exportar métricas a Prometheus.
 
application.yml (modificado)
Configuración de ELK Stack (Elasticsearch, Logstash, Kibana)
- Despliega ELK Stack en tu clúster de Kubernetes.
 - Configura los microservicios para enviar logs a Logstash.
 
logback-spring.xml
<configuration>
    <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>logstash:5000</destination>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
    </appender>
    <root level="INFO">
        <appender-ref ref="LOGSTASH"/>
    </root>
</configuration>
- Seguridad en Microservicios
 
Autenticación y Autorización
Implementa OAuth2 para la autenticación y autorización de los microservicios.
application.yml (modificado)
Seguridad en la Comunicación
Configura TLS para asegurar la comunicación entre los microservicios.
application.yml (modificado)
Conclusión
En esta sección, hemos implementado una aplicación completa basada en microservicios, cubriendo desde el diseño y desarrollo hasta el despliegue y monitoreo. Este ejercicio práctico te proporciona una comprensión integral de cómo construir y gestionar aplicaciones de microservicios en un entorno real. Asegúrate de revisar y experimentar con cada componente para consolidar tu conocimiento y habilidades en microservicios.
Curso de Microservicios
Módulo 1: Introducción a los Microservicios
- Conceptos Básicos de Microservicios
 - Ventajas y Desventajas de los Microservicios
 - Comparación con Arquitectura Monolítica
 
Módulo 2: Diseño de Microservicios
- Principios de Diseño de Microservicios
 - Descomposición de Aplicaciones Monolíticas
 - Definición de Bounded Contexts
 
Módulo 3: Comunicación entre Microservicios
Módulo 4: Implementación de Microservicios
- Elección de Tecnologías y Herramientas
 - Desarrollo de un Microservicio Simple
 - Gestión de Configuración
 
