Tornado + Motor 微服务架构(Docker + 测试 + Kubernetes)

Tornado + Motor 微服务架构(Docker + 测试 + Kubernetes)

一、项目结构

复制代码
project-root/
├── docker-compose.yml
├── k8s/                    # Kubernetes 配置文件
│   ├── api-deployment.yaml
│   ├── api-service.yaml
│   ├── user-deployment.yaml
│   ├── user-service.yaml
│   ├── mongo-deployment.yaml
│   ├── mongo-service.yaml
│   └── ingress.yaml
├── common/
│   ├── config.py
│   ├── db.py
│   ├── utils.py
├── api_service/
│   ├── Dockerfile
│   ├── main.py
│   ├── handlers/
│   │   └── user_handler.py
│   ├── services/
│   │   └── user_service.py
│   └── tests/
│       └── test_user.py
├── user_service/
│   ├── Dockerfile
│   ├── main.py
│   ├── handlers/
│   │   └── user_handler.py
│   ├── services/
│   │   └── user_service.py
│   └── tests/
│       └── test_user.py
└── requirements.txt

二、核心依赖(requirements.txt)

复制代码
tornado==6.4
motor==3.3.2
pytest==8.2.0
pytest-asyncio==0.24.0
requests==2.32.3

三、公共模块(common/)

config.py

python 复制代码
import os

MONGO_URI = os.getenv('MONGO_URI', 'mongodb://mongo:27017')
DB_NAME = os.getenv('DB_NAME', 'microdb')
SERVICE_NAME = os.getenv('SERVICE_NAME', 'default-service')
PORT = int(os.getenv('PORT', 8000))

db.py

python 复制代码
from motor.motor_tornado import MotorClient
from common.config import MONGO_URI, DB_NAME

client = MotorClient(MONGO_URI)
db = client[DB_NAME]

utils.py

python 复制代码
import json
import tornado.web

class BaseHandler(tornado.web.RequestHandler):
    def set_default_headers(self):
        self.set_header('Content-Type', 'application/json')

    def write_json(self, data, status=200):
        self.set_status(status)
        self.write(json.dumps(data))

四、API 服务(api_service/)

Dockerfile

Dockerfile 复制代码
FROM python:3.11-slim
WORKDIR /app
COPY ../../requirements.txt ./
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "main.py"]

main.py

python 复制代码
import tornado.ioloop
import tornado.web
from tornado.process import fork_processes
from handlers.user_handler import UserHandler
from common.config import PORT


def make_app():
    return tornado.web.Application([
        (r"/user", UserHandler),
    ])

if __name__ == '__main__':
    fork_processes(None)  # 多进程 worker
    app = make_app()
    app.listen(PORT)
    tornado.ioloop.IOLoop.current().start()

handlers/user_handler.py

python 复制代码
from common.utils import BaseHandler
from services.user_service import UserService

class UserHandler(BaseHandler):
    async def get(self):
        users = await UserService().get_all_users()
        self.write_json({"users": users})

    async def post(self):
        data = self.request.body.decode()
        result = await UserService().create_user(data)
        self.write_json(result)

services/user_service.py

python 复制代码
from common.db import db
import json

class UserService:
    async def get_all_users(self):
        cursor = db.users.find()
        return [doc async for doc in cursor]

    async def create_user(self, data):
        user = json.loads(data)
        result = await db.users.insert_one(user)
        return {"_id": str(result.inserted_id)}

tests/test_user.py

python 复制代码
import pytest
import asyncio
from services.user_service import UserService

@pytest.mark.asyncio
async def test_create_user():
    service = UserService()
    res = await service.create_user('{"name":"test_user"}')
    assert "_id" in res

五、User 服务(user_service/)

结构相同,只是接口路径不同,例如 /profile


六、Docker Compose

docker-compose.yml

yaml 复制代码
version: '3.8'
services:
  mongo:
    image: mongo:6.0
    container_name: mongo
    ports:
      - "27017:27017"

  api_service:
    build: ./api_service
    container_name: api_service
    environment:
      - MONGO_URI=mongodb://mongo:27017
      - DB_NAME=microdb
      - PORT=8000
    ports:
      - "8000:8000"
    depends_on:
      - mongo

  user_service:
    build: ./user_service
    container_name: user_service
    environment:
      - MONGO_URI=mongodb://mongo:27017
      - DB_NAME=microdb
      - PORT=8001
    ports:
      - "8001:8001"
    depends_on:
      - mongo

七、Kubernetes 配置示例(k8s/)

api-deployment.yaml

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api-service
  template:
    metadata:
      labels:
        app: api-service
    spec:
      containers:
        - name: api-service
          image: api_service:latest
          ports:
            - containerPort: 8000

api-service.yaml

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: api-service
spec:
  type: ClusterIP
  selector:
    app: api-service
  ports:
    - port: 8000
      targetPort: 8000

ingress.yaml

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: micro-ingress
spec:
  rules:
    - host: micro.local
      http:
        paths:
          - path: /user
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8000

八、运行与测试

  1. 启动开发环境:

    bash 复制代码
    docker-compose up --build
  2. 本地运行测试:

    bash 复制代码
    pytest -v
  3. 部署到 Kubernetes:

    bash 复制代码
    kubectl apply -f k8s/

九、说明

  • Tornado 使用多进程 worker(fork_processes(None))自动创建与 CPU 核数相同的进程。
  • MongoDB 异步连接由 Motor 驱动支持。
  • 测试通过 pytest-asyncio 实现异步单元测试。
  • Kubernetes YAML 已含 Ingress,可直接对外暴露 API 服务。

这一结构可直接扩展为完整的微服务体系,每个服务都独立运行、可水平扩展。

相关推荐
七歌杜金房8 小时前
我终于又有了自己的 Linux 电脑
linux·debian·mac
SelectDB12 小时前
Apache Doris Python UDF:让 SQL 直接调用 Python 生态,支撑 Agent 时代复杂业务逻辑
大数据·数据库·python
荣码20 小时前
GraphRAG:普通RAG只能回答"点"的问题,我踩了4个坑才搞懂
java·python
fanly111 天前
Surging AI Agent 完整产品介绍
微服务·microservice
金銀銅鐵1 天前
[Python] 基于欧几里得算法,实现分数约分计算器
python·数学
tntxia1 天前
linux curl命令详解_curl详解
linux
Lyn_Li1 天前
Kaggle Top 5 | 198只股票、200条数据的金融预测——BattleFin高分方案从零复现
python·kaggle·比赛复盘·金融预测
扛枪的书生1 天前
Linux 网络管理器用法速查
linux
小九九的爸爸2 天前
前端想要入门Agent开发,要具备哪些Python基础?
python·agent·ai编程
顺风尿一寸2 天前
Java Socket 内核之旅:从 SocketChannel.read() 到 tcp_recvmsg 与 epoll 的完整调用链路
linux