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 服务。

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

相关推荐
看兵马俑的程序员5 小时前
RAG实现-本地PDF内容加载和切片
开发语言·python·pdf
FJW0208146 小时前
【Linux】系统中的文件管理
linux·运维·服务器
豆是浪个6 小时前
Linux(Centos 7.6)命令详解:rpm
linux·运维·centos
-指短琴长-6 小时前
Docker基础【Ubuntu安装/Windows安装】
windows·ubuntu·docker
Z_Xshan6 小时前
docker 容器web站点 中文文件名访问404问题
linux·开发语言·docker
是梦终空7 小时前
计算机毕业设计240—基于python+爬虫+html的微博舆情数据可视化系统(源代码+数据库)
爬虫·python·pandas·课程设计·毕业论文·计算机毕业设计·微博舆情可视化
CodeJourney.7 小时前
Python开发可视化音乐播放器教程(附代码)
数据库·人工智能·python
晓梦.7 小时前
Linux
linux·运维·服务器
回忆是昨天里的海7 小时前
k8s集群-节点间通信之安装kube-flannel插件
java·docker·kubernetes