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

  1. Diseñar y definir los microservicios necesarios.
  2. Implementar los microservicios utilizando una tecnología de tu elección (por ejemplo, Node.js, Spring Boot, etc.).
  3. Configurar la comunicación entre los microservicios.
  4. Desplegar los microservicios utilizando contenedores Docker.
  5. Orquestar los microservicios con Kubernetes.
  6. Implementar monitoreo y logging.
  7. Asegurar los microservicios.

  1. Diseño y Definición de Microservicios

Microservicios Identificados

Para la aplicación de gestión de pedidos, identificamos los siguientes microservicios:

  1. Servicio de Usuarios: Gestiona la información de los usuarios.
  2. Servicio de Productos: Gestiona el catálogo de productos.
  3. Servicio de Pedidos: Gestiona la creación y seguimiento de pedidos.
  4. 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      |
+------------------+

  1. 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: true

Servicio 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: true

Servicio 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: true

Servicio 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

  1. 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
}

  1. 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.

  1. 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: 8080

user-service-service.yml

apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

Aplica los archivos de configuración:

kubectl apply -f user-service-deployment.yml
kubectl apply -f user-service-service.yml

Repite el proceso para los otros microservicios.

  1. Monitoreo y Logging

Configuración de Prometheus y Grafana

  1. Despliega Prometheus y Grafana en tu clúster de Kubernetes.
  2. Configura los microservicios para exportar métricas a Prometheus.

application.yml (modificado)

management:
  endpoints:
    web:
      exposure:
        include: "*"
  metrics:
    export:
      prometheus:
        enabled: true

Configuración de ELK Stack (Elasticsearch, Logstash, Kibana)

  1. Despliega ELK Stack en tu clúster de Kubernetes.
  2. 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>

  1. Seguridad en Microservicios

Autenticación y Autorización

Implementa OAuth2 para la autenticación y autorización de los microservicios.

application.yml (modificado)

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://your-issuer-uri

Seguridad en la Comunicación

Configura TLS para asegurar la comunicación entre los microservicios.

application.yml (modificado)

server:
  ssl:
    key-store: classpath:keystore.jks
    key-store-password: password
    key-password: password

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.

© Copyright 2024. Todos los derechos reservados