En aquest tema, implementarem un sistema de microserveis complet des de zero. Aquest exemple pràctic ens permetrà aplicar els conceptes apresos en els mòduls anteriors i veure com es poden integrar en una aplicació real.

Objectius

  1. Desenvolupar diversos microserveis que interactuïn entre ells.
  2. Utilitzar tecnologies i eines adequades per a la implementació.
  3. Desplegar els microserveis en un entorn de contenidors.
  4. Configurar la comunicació entre els microserveis.
  5. Implementar monitoratge i seguretat bàsica.

Descripció del Sistema

Crearem un sistema de comerç electrònic senzill amb els següents microserveis:

  1. Servei d'Usuari: Gestió d'usuaris (registre, autenticació).
  2. Servei de Productes: Gestió de productes (creació, actualització, eliminació).
  3. Servei de Comandes: Gestió de comandes (creació, actualització, estat).

Tecnologies Utilitzades

  • Llenguatge de Programació: Python
  • Framework: Flask per a APIs RESTful
  • Base de Dades: PostgreSQL
  • Contenidors: Docker
  • Orquestració: Kubernetes
  • Monitoratge: Prometheus i Grafana
  • Autenticació: JWT (JSON Web Tokens)

Estructura del Projecte

ecommerce-system/
├── user-service/
│   ├── app/
│   ├── Dockerfile
│   ├── requirements.txt
│   └── ...
├── product-service/
│   ├── app/
│   ├── Dockerfile
│   ├── requirements.txt
│   └── ...
├── order-service/
│   ├── app/
│   ├── Dockerfile
│   ├── requirements.txt
│   └── ...
├── docker-compose.yml
└── k8s/
    ├── user-service-deployment.yml
    ├── product-service-deployment.yml
    ├── order-service-deployment.yml
    └── ...

Desenvolupament dels Microserveis

Servei d'Usuari

Estructura del Servei d'Usuari

user-service/
├── app/
│   ├── __init__.py
│   ├── models.py
│   ├── routes.py
│   └── utils.py
├── Dockerfile
├── requirements.txt
└── ...

Codi del Servei d'Usuari

app/__init__.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:password@db:5432/user_db'
db = SQLAlchemy(app)

from app import routes

app/models.py

from app import db

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(120), nullable=False)

app/routes.py

from flask import request, jsonify
from app import app, db
from app.models import User
from app.utils import generate_token, verify_password

@app.route('/register', methods=['POST'])
def register():
    data = request.get_json()
    new_user = User(username=data['username'], password=generate_password_hash(data['password']))
    db.session.add(new_user)
    db.session.commit()
    return jsonify({'message': 'User registered successfully'}), 201

@app.route('/login', methods=['POST'])
def login():
    data = request.get_json()
    user = User.query.filter_by(username=data['username']).first()
    if user and verify_password(user.password, data['password']):
        token = generate_token(user.id)
        return jsonify({'token': token}), 200
    return jsonify({'message': 'Invalid credentials'}), 401

app/utils.py

import jwt
from werkzeug.security import generate_password_hash, check_password_hash

SECRET_KEY = 'your_secret_key'

def generate_token(user_id):
    return jwt.encode({'user_id': user_id}, SECRET_KEY, algorithm='HS256')

def verify_password(stored_password, provided_password):
    return check_password_hash(stored_password, provided_password)

Dockerfile

FROM python:3.8-slim

WORKDIR /app

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt

COPY . .

CMD ["python", "app/__init__.py"]

requirements.txt

Flask==2.0.1
Flask-SQLAlchemy==2.5.1
psycopg2-binary==2.9.1
Werkzeug==2.0.1
PyJWT==2.1.0

Servei de Productes

Estructura del Servei de Productes

product-service/
├── app/
│   ├── __init__.py
│   ├── models.py
│   ├── routes.py
│   └── utils.py
├── Dockerfile
├── requirements.txt
└── ...

Codi del Servei de Productes

app/__init__.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:password@db:5432/product_db'
db = SQLAlchemy(app)

from app import routes

app/models.py

from app import db

class Product(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True, nullable=False)
    price = db.Column(db.Float, nullable=False)

app/routes.py

from flask import request, jsonify
from app import app, db
from app.models import Product

@app.route('/products', methods=['POST'])
def add_product():
    data = request.get_json()
    new_product = Product(name=data['name'], price=data['price'])
    db.session.add(new_product)
    db.session.commit()
    return jsonify({'message': 'Product added successfully'}), 201

@app.route('/products', methods=['GET'])
def get_products():
    products = Product.query.all()
    return jsonify([{'id': p.id, 'name': p.name, 'price': p.price} for p in products]), 200

Dockerfile

FROM python:3.8-slim

WORKDIR /app

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt

COPY . .

CMD ["python", "app/__init__.py"]

requirements.txt

Flask==2.0.1
Flask-SQLAlchemy==2.5.1
psycopg2-binary==2.9.1

Servei de Comandes

Estructura del Servei de Comandes

order-service/
├── app/
│   ├── __init__.py
│   ├── models.py
│   ├── routes.py
│   └── utils.py
├── Dockerfile
├── requirements.txt
└── ...

Codi del Servei de Comandes

app/__init__.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:password@db:5432/order_db'
db = SQLAlchemy(app)

from app import routes

app/models.py

from app import db

class Order(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, nullable=False)
    product_id = db.Column(db.Integer, nullable=False)
    quantity = db.Column(db.Integer, nullable=False)
    status = db.Column(db.String(50), nullable=False, default='Pending')

app/routes.py

from flask import request, jsonify
from app import app, db
from app.models import Order

@app.route('/orders', methods=['POST'])
def create_order():
    data = request.get_json()
    new_order = Order(user_id=data['user_id'], product_id=data['product_id'], quantity=data['quantity'])
    db.session.add(new_order)
    db.session.commit()
    return jsonify({'message': 'Order created successfully'}), 201

@app.route('/orders', methods=['GET'])
def get_orders():
    orders = Order.query.all()
    return jsonify([{'id': o.id, 'user_id': o.user_id, 'product_id': o.product_id, 'quantity': o.quantity, 'status': o.status} for o in orders]), 200

Dockerfile

FROM python:3.8-slim

WORKDIR /app

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt

COPY . .

CMD ["python", "app/__init__.py"]

requirements.txt

Flask==2.0.1
Flask-SQLAlchemy==2.5.1
psycopg2-binary==2.9.1

Desplegament amb Docker i Kubernetes

Docker Compose

docker-compose.yml

version: '3.8'

services:
  user-service:
    build: ./user-service
    ports:
      - "5001:5000"
    environment:
      - SQLALCHEMY_DATABASE_URI=postgresql://user:password@db:5432/user_db

  product-service:
    build: ./product-service
    ports:
      - "5002:5000"
    environment:
      - SQLALCHEMY_DATABASE_URI=postgresql://user:password@db:5432/product_db

  order-service:
    build: ./order-service
    ports:
      - "5003:5000"
    environment:
      - SQLALCHEMY_DATABASE_URI=postgresql://user:password@db:5432/order_db

  db:
    image: postgres:13
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: user_db

Kubernetes

k8s/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: 5000
        env:
        - name: SQLALCHEMY_DATABASE_URI
          value: "postgresql://user:password@db:5432/user_db"

k8s/product-service-deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: product-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: product-service
  template:
    metadata:
      labels:
        app: product-service
    spec:
      containers:
      - name: product-service
        image: product-service:latest
        ports:
        - containerPort: 5000
        env:
        - name: SQLALCHEMY_DATABASE_URI
          value: "postgresql://user:password@db:5432/product_db"

k8s/order-service-deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
    spec:
      containers:
      - name: order-service
        image: order-service:latest
        ports:
        - containerPort: 5000
        env:
        - name: SQLALCHEMY_DATABASE_URI
          value: "postgresql://user:password@db:5432/order_db"

Monitoratge i Seguretat

Monitoratge amb Prometheus i Grafana

docker-compose.yml (afegint serveis de monitoratge)

services:
  ...
  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml

  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"

prometheus.yml

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'user-service'
    static_configs:
      - targets: ['user-service:5000']

  - job_name: 'product-service'
    static_configs:
      - targets: ['product-service:5000']

  - job_name: 'order-service'
    static_configs:
      - targets: ['order-service:5000']

Seguretat amb JWT

Ja hem implementat JWT en el servei d'usuari per a l'autenticació. Assegurem-nos que els altres serveis validin el token JWT en les seves peticions.

app/utils.py (Servei de Productes i Comandes)

import jwt
from flask import request, jsonify

SECRET_KEY = 'your_secret_key'

def token_required(f):
    def decorator(*args, **kwargs):
        token = request.headers.get('Authorization')
        if not token:
            return jsonify({'message': 'Token is missing!'}), 403
        try:
            jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
        except:
            return jsonify({'message': 'Token is invalid!'}), 403
        return f(*args, **kwargs)
    return decorator

app/routes.py (Servei de Productes i Comandes)

from app.utils import token_required

@app.route('/products', methods=['POST'])
@token_required
def add_product():
    ...

Conclusió

En aquest exemple pràctic, hem creat un sistema de comerç electrònic senzill utilitzant microserveis. Hem desenvolupat serveis per a la gestió d'usuaris, productes i comandes, i hem desplegat aquests serveis utilitzant Docker i Kubernetes. També hem implementat monitoratge amb Prometheus i Grafana, i hem assegurat la comunicació entre serveis amb JWT.

Aquest exemple ens proporciona una base sòlida per a la implementació de sistemes de microserveis més complexos i ens permet aplicar els conceptes apresos en els mòduls anteriors del curs.

© Copyright 2024. Tots els drets reservats