No desenvolvimento moderno de software, os microsserviços surgiram como uma arquitetura essencial, permitindo o dimensionamento, a flexibilidade e o gerenciamento eficiente de sistemas complexos.

Microsserviços são pequenos aplicativos independentes que executam tarefas específicas, permitindo uma implantação flexível e escalonamento. Essa abordagem modular para o design de software reduz o acoplamento entre componentes, aumentando a flexibilidade e a capacidade de gerenciamento ao longo do desenvolvimento.

O artigo apresenta uma visão geral dos microsserviços, sua funcionalidade e sua criação usando Python. Ele também demonstra a implantação de seus microsserviços na Kinsta usando um Dockerfile.

O que são microsserviços?

Os microsserviços são serviços independentes e autônomos dentro de um aplicativo, cada um atendendo a necessidades comerciais específicas. Eles se comunicam por meio de APIs leves ou corretores de mensagens, formando um sistema abrangente.

Ao contrário dos sistemas monolíticos que são dimensionados inteiramente com base na demanda, os microsserviços permitem o dimensionamento de componentes individuais de alto tráfego. Essa arquitetura facilita o gerenciamento de falhas e as atualizações de recursos, contrariando as limitações monolíticas.

Há vários benefícios no uso de microsserviços, tais como:

  • Flexibilidade e dimensionamento – O desacoplamento de serviços individuais permite que você aumente o número de nodes que executam uma instância de um determinado serviço com alto tráfego.
  • Modularidade do código – Cada serviço pode usar uma pilha de tecnologia discreta, o que significa que você pode escolher as melhores ferramentas de desenvolvimento para cada um deles.

No entanto, algumas dificuldades acompanham as arquiteturas de microsserviços:

  • Monitoramento de vários serviços – O monitoramento de serviços individuais em um sistema torna-se um desafio à medida que as instâncias de um determinado serviço são implantadas e distribuídas em vários nodes. Essa dificuldade é especialmente aparente durante falhas de rede ou outros problemas do sistema.
  • Custo – O desenvolvimento de aplicativos de microsserviços pode ser significativamente mais caro do que a criação de sistemas monolíticos devido aos custos associados ao gerenciamento de vários serviços. Cada serviço requer sua própria infraestrutura e seus próprios recursos, o que pode se tornar dispendioso, principalmente quando você estiver ampliando o sistema.

Como projetar um microsserviço usando Python

Agora que você conhece os benefícios de usar uma arquitetura de microsserviço, é hora de criar uma com Python.

Para este exemplo, suponha que você queira criar um aplicativo web de eCommerce. O site tem vários componentes, incluindo o catálogo de produtos, uma lista de pedidos e um sistema de processamento de pagamentos e registros, cada um dos quais você precisa implementar como um serviço independente. Além disso, você precisa estabelecer um método de comunicação serviço a serviço para transferir dados entre esses serviços, como HTTP, de forma eficiente.

Vamos criar um microsserviço usando Python para gerenciar um catálogo de produtos. O microsserviço buscará dados de produtos de uma fonte especificada e retornará os dados no formato JSON.

Pré-requisitos

Para seguir este tutorial, certifique-se de que você tenha:

1. Crie seu projeto

  1. Para começar, crie uma pasta para o seu projeto chamado flask-microservice e o diretório atual no diretório do projeto.
  2. Em seguida, execute python3 --version para confirmar se o Python está instalado corretamente em seu computador.
  3. Instale o site virtualenv para criar um ambiente de desenvolvimento isolado para o microsserviço Flask executando o comando abaixo:
    pip3 install virtualenv
  4. Crie um ambiente virtual executando o seguinte:
    virtualenv venv
  5. Por fim, ative o ambiente virtual usando um dos seguintes comandos, de acordo com o sistema operacional do seu computador:
    # Windows: 
    .\venv\Scripts\activate
    # Unix or macOS:
    source venv/bin/activate

2. Configure um servidor Flask

No diretório raiz, crie um arquivo requirements.txt e adicione essas dependências.

flask
requests

Execute o arquivo pip3 command on your terminal to install the dependencies.

pip install -r requirements.txt

Em seguida, crie uma nova pasta no diretório raiz e nomeie-a como services. Dentro dessa pasta, crie um novo arquivo, products.py, e adicione o código abaixo para configurar um servidor Flask.

import requests
import os
from flask import Flask, jsonify
app = Flask(__name__)
port = int(os.environ.get('PORT', 5000))

@app.route("/")
def home():
    return "Hello, this is a Flask Microservice"
if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=port)

No código acima, um servidor Flask básico é configurado. Ele inicializa um aplicativo Flask, define uma única rota para a URL raiz ("/") e, quando acessado, exibe a mensagem "Hello, this is a Flask Microservice". O servidor é executado em uma porta especifica, obtida de uma variável de ambiente ou tem como padrão a porta 5000, e é iniciado no modo de depuração, deixando pronto para lidar com as solicitações recebidas.

3. Defina os endpoints da API

Com o servidor configurado, crie um endpoint de API para um microsserviço que busca dados de produtos em uma API disponível publicamente. Adicione este código ao arquivo products.py:

BASE_URL = "https://dummyjson.com"
@app.route('/products', methods=['GET'])
def get_products():
    response = requests.get(f"{BASE_URL}/products")
    if response.status_code != 200:
        return jsonify({'error': response.json()['message']}), response.status_code
    products = []
    for product in response.json()['products']:
        product_data = {
            'id': product['id'],
            'title': product['title'],
            'brand': product['brand'],
            'price': product['price'],
            'description': product['description']
        }
        products.append(product_data)
    return jsonify({'data': products}), 200 if products else 204

O código acima cria um endpoint /products no servidor Flask. Quando acessado via uma requisição GET, ele busca dados de produtos de uma API dummy. Se bem-sucedido, processa os dados obtidos, extrai detalhes do produto e retorna as informações em formato JSON. Em caso de erros ou ausência de dados disponíveis, responde com uma mensagem de erro apropriada e código de status.

4. Teste o microsserviço

Neste ponto, você configurou com êxito um microsserviço simples. Para iniciar o serviço, ative o servidor de desenvolvimento, que começará a ser executado em http://localhost:5000.

flask --app services/products run

Em seguida, você pode fazer uma solicitação GET para o endpoint /products usando o cliente Postman. Você deverá ver uma resposta semelhante à captura de tela abaixo.

Testando a solicitação da API HTTP GET no Postman.
Testando a solicitação da API HTTP GET no Postman.

Como implementar a autenticação e a autorização em um microsserviço Python

Ao criar microsserviços, é importante implementar medidas de segurança robustas, como autenticação e autorização. A segurança do microsserviço garante que somente usuários autorizados possam acessar e usar o serviço, protegendo dados confidenciais e evitando ataques mal-intencionados.

Um método eficaz para implementar autenticação e autorização seguras em microsserviços são os JWTs (JSON Web Tokens).

O JWT é um padrão aberto amplamente usado que oferece uma maneira segura e eficiente de transmitir informações de autenticação entre clientes e servidores. Eles são tokens compactos, criptografados e assinados digitalmente que você transmite junto com as solicitações HTTP. Quando você inclui um JWT em cada solicitação, o servidor pode verificar rapidamente a identidade e as permissões de um usuário.

Para implementar a autenticação JWT no microsserviço, faça o seguinte:

  1. Adicione o pacote pyjwt do Python ao seu arquivo requirements.txt e reinstale as dependências usando pip install -r requirements.txt.
  2. Como o serviço não tem um banco de dados dedicado, crie um arquivo users.json no diretório raiz do seu projeto para armazenar uma lista de usuários autorizados. Cole o código abaixo no arquivo:
    [
        {   
            "id": 1,
            "username": "admin",
            "password": "admin"
        
        }
    ]

  3. Em seguida, em seu arquivo services/products.py, substitua as instruções de importação pelo seguinte:
    import requests 
    from flask import Flask, jsonify, request, make_response
    import jwt
    from functools import wraps
    import json
    import os
    from jwt.exceptions import DecodeError

    Você está importando esses módulos para lidar com solicitações HTTP, criar um aplicativo Flask, gerenciar dados JSON, implementar autenticação baseada em JWT e lidar com exceções, permitindo uma ampla gama de recursos no servidor Flask.

  4. Adicione o seguinte código abaixo da criação da instância do aplicativo Flask para gerar uma chave secreta que será usada para assinar os tokens JWT.
    app.config['SECRET_KEY'] = os.urandom(24)
  5. Para verificar os JWTs, crie uma função de decorador e adicione o seguinte código acima das rotas de API no código do servidor Flask. Essa função de decorador autenticará e validará os usuários antes que eles acessem as rotas protegidas.
    def token_required(f):
        @wraps(f)
        def decorated(*args, **kwargs):
            token = request.cookies.get('token')
            if not token:
                return jsonify({'error': 'Authorization token is missing'}), 401
            try:
                data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
                current_user_id = data['user_id']
            except DecodeError:
                return jsonify({'error': 'Authorization token is invalid'}), 401
            return f(current_user_id, *args, **kwargs)
        return decorated

    Essa função de decorador verifica as solicitações HTTP de entrada em busca de um token de autorização JWT, que deve estar nos cabeçalhos de solicitação ou nos cookies. Se o token estiver faltando ou for inválido, o decorador enviará uma mensagem unauthorized status code como resposta.

    Por outro lado, se um token válido estiver presente, o decorador extrai a ID do usuário após decodificá-la. Esse processo protege os endpoints de API protegidos, concedendo acesso somente a usuários autorizados.

  6. Defina um endpoint de API para autenticação de usuário usando o código abaixo.
    with open('users.json', 'r') as f:
        users = json.load(f)
    @app.route('/auth', methods=['POST'])
    def authenticate_user():
        if request.headers['Content-Type'] != 'application/json':
            return jsonify({'error': 'Unsupported Media Type'}), 415
        username = request.json.get('username')
        password = request.json.get('password')
        for user in users:
            if user['username'] == username and user['password'] == password:
                token = jwt.encode({'user_id': user['id']}, app.config['SECRET_KEY'],algorithm="HS256")
                response = make_response(jsonify({'message': 'Authentication successful'}))
                response.set_cookie('token', token)
                return response, 200
        return jsonify({'error': 'Invalid username or password'}), 401

    Para autenticar e autorizar os usuários, o endpoint da API /auth verifica as credenciais no payload JSON da solicitação POST em relação à lista de usuários permitidos. Se as credenciais forem válidas, ele gera um token JWT usando o ID do usuário e a chave secreta do aplicativo e define o token como um cookie na resposta. Os usuários agora podem usar esse token para fazer solicitações de API subsequentes.

    Depois de criar o endpoint /auth, use o Postman para enviar uma solicitação HTTP POST para http://localhost:5000/auth. No corpo da solicitação, inclua as credenciais do usuário administrador simulado que você criou.

    Solicitação do Postman mostrando o corpo da solicitação.
    Solicitação do Postman mostrando o corpo da solicitação.

    Se a solicitação for bem-sucedida, a API gerará um token JWT, o definirá nos cookies do Postman e enviará uma resposta de sucesso autenticada.

  7. Por fim, atualize o endpoint da API GET para verificar o token JWT usando o código abaixo:
    @app.route('/products', methods=['GET'])
    @token_required
    def get_products(current_user_id):
        headers = {'Authorization': f'Bearer {request.cookies.get("token")}'}    
        response = requests.get(f"{BASE_URL}/products", headers=headers)
        if response.status_code != 200:
            return jsonify({'error': response.json()['message']}), response.status_code
        products = []
        for product in response.json()['products']:
            product_data = {
                'id': product['id'],
                'title': product['title'],
                'brand': product['brand'],
                'price': product['price'],
                'description': product['description']
            }
            products.append(product_data)
        return jsonify({'data': products}), 200 if products else 204

Como colocar microsserviços Python em contêineres com o Docker

O Docker é uma plataforma que empacota aplicativos e suas dependências em um ambiente de desenvolvimento isolado. O empacotamento de microsserviços em contêineres simplifica os processos de implantação e gerenciamento nos servidores, pois cada serviço é executado de forma independente em seu contêiner.

Para contêinerizar o microsserviço, você deve criar uma imagem do Docker a partir de um Dockerfile que especifique as dependências necessárias para executar o aplicativo em um contêiner. Crie um Dockerfile no diretório raiz do seu projeto e adicione estas instruções:

FROM python:3.9-alpine
WORKDIR /app
COPY requirements.txt ./
RUN pip install -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "./services/products.py"]

Antes de criar a imagem, você deve revisar estes comandos:

  • FROM – Instrui o Docker sobre qual imagem de base você deve usar. Uma imagem de base é uma instância pré-criada que contém o software e as dependências para executar o aplicativo Flask em um contêiner.
  • WORKDIR – Define o diretório especificado dentro do contêiner como o diretório de trabalho.
  • COPY requirements.txt ./ – Copia as dependências do arquivo requirements.txt para o arquivo requirements.txt do contêiner.
  • RUN – Executa o comando especifico para instalar as dependências que a imagem requer.
  • COPY . . – Copia todos os arquivos do diretório raiz do projeto para o diretório de trabalho dentro do contêiner.
  • EXPOSE – Especifica a porta em que o contêiner escutará as solicitações. No entanto, o Docker não publica a porta na máquina host.
  • CMD – Especifica o comando padrão a ser executado quando o contêiner for iniciado.

Em seguida, adicione um arquivo .dockerignore no diretório raiz do seu projeto para especificar os arquivos que a imagem do Docker deve excluir. Limitar o conteúdo da imagem reduzirá seu tamanho final e o tempo de build associado.

/venv
/services/__pycache__/
.gitignore

Agora, execute o comando abaixo para criar a imagem do Docker:

docker build -t flask-microservice .

Por fim, depois que a imagem for criada, você poderá executar o microsserviço em um contêiner do Docker usando o seguinte comando:

docker run -p 5000:5000 flask-microservice

Este comando iniciará um contêiner Docker executando o microsserviço e mapeará a porta 5000 do contêiner para a porta 5000 na máquina host, permitindo que você faça requisições HTTP a partir do seu navegador web ou Postman usando a URL http://localhost:5000.

Implante microsserviços Python com a Kinsta

A Kinsta oferece soluções de hospedagem gerenciada para aplicativos web e bancos de dados – você pode implantar e gerenciar perfeitamente seus microsserviços Python e APIs de backend em um ambiente de produção.

Siga estas etapas para configurar seu microsserviço Flask para implantação com o MyKinsta:

  1. Primeiro, crie um novo Procfile no diretório raiz e adicione o código abaixo. Ele especifica o comando para executar o microsserviço do Flask no servidor HTTP Gunicorn WSGI da Kinsta para aplicativos Python.
    web: gunicorn services.wsgi
  2. Em seu arquivo requirements.txt, adicione a dependência do Gunicorn:
    gunicorn==20.1.*
  3. Em seguida, crie um novo arquivo services/wsgi.py e adicione o código abaixo.
    from services.products import app as application
    if __name__ == "__main__":
                    application.run()
  4. Crie um arquivo .gitignore na pasta raiz do projeto e adicione o seguinte:
    services/__pycache__
    venv
  5. Por fim, crie um novo repositório no GitHub e faça push dos arquivos do projeto.

Quando seu repositório estiver pronto, siga estas etapas para implantar o microsserviço do Flask na Kinsta:

  1. Faça login ou crie uma conta para visualizar seu painel MyKinsta.
  2. Autorize a Kinsta no seu provedor Git (Bitbucket, GitHub ou GitLab).
  3. Clique em Aplicativos na barra lateral esquerda e, em seguida, clique em Adicionar aplicativo.
  4. No painel, clique em Adicionar serviço e selecione Aplicativo.
  5. Escolha o repositório e a branch que você deseja usar para a implantação.
  6. Atribua um nome exclusivo ao seu aplicativo e escolha um local de centro de dados.
  7. Para configurar o ambiente de build, selecione a opção para usar um Dockerfile para criar a imagem do contêiner.
  8. Forneça o caminho para o seu Dockerfile e o contexto.
  9. Por fim, revise outras informações e clique em Criar aplicativo.

Teste o microsserviço

Quando o processo de implantação for bem-sucedido, clique na URL fornecida para testar o microsserviço fazendo solicitações HTTP no Postman. Faça uma solicitação GET para o endpoint raiz.

Faça uma solicitação HTTP API GET para o endpoint product do microsserviço.
Faça uma solicitação HTTP API GET para o endpoint product do microsserviço.

Para autenticar e gerar um token JWT, envie uma solicitação POST para o endpoint da API /auth, passando as credenciais de administrador no corpo da solicitação.

Solicitação de API HTTP POST para o endpoint do microsserviço auth.
Solicitação de API HTTP POST para o endpoint do microsserviço auth.

Por fim, após a autenticação bem-sucedida, faça uma solicitação GET para o endpoint /products para buscar dados.

Solicitação da API HTTP GET para um endpoint do microsserviço products.
Solicitação da API HTTP GET para um endpoint do microsserviço products.

Resumo

À medida que os aplicativos aumentam em tamanho e complexidade, é fundamental adotar padrões de arquitetura que permitam que os sistemas de software sejam dimensionados sem sobrecarregar os recursos disponíveis.

A arquitetura de microsserviços oferece escalabilidade, flexibilidade de desenvolvimento e facilidade de manutenção, tornando mais fácil para você gerenciar aplicativos complexos.

A Kinsta simplifica o processo de hospedagem de seus microsserviços. Ele permite que você use sem esforço o banco de dados de sua preferência e hospede de forma conveniente o aplicativo e o banco de dados por meio de um painel unificado.

Jeremy Holcombe Kinsta

Content & Marketing Editor at Kinsta, WordPress Web Developer, and Content Writer. Outside of all things WordPress, I enjoy the beach, golf, and movies. I also have tall people problems ;).