FastAPI+Vue 搭建运维平台(一):项目架构

18 阅读8分钟

前言

做了 16 年运维,从手动操作到全自动化,我深刻体会到:好的工具能让运维效率提升 10 倍

之前分享过 Python 自动化脚本,但脚本终究是零散的。今天开始,我用一个系列,教大家从零搭建一套完整的运维管理平台

技术栈:

  • 后端:FastAPI + SQLAlchemy + MySQL
  • 前端:Vue 3 + Element Plus
  • 部署:Docker + Nginx

功能模块:

  1. 服务器管理(CMDB)
  2. 批量执行命令
  3. 自动化部署
  4. 监控告警
  5. 工单系统

本系列共 5 篇:

  • 第一篇:项目架构(本文)
  • 第二篇:后端开发
  • 第三篇:前端开发
  • 第四篇:功能实现
  • 第五篇:部署上线

适合人群:

  • 有 Python 基础的运维
  • 想转型运维开发的同学
  • 需要内部工具的团队

代码已开源: GitHub 搜索 ops-platform(文末有链接)


一、为什么做这个平台?

1.1 运维的痛点

你在工作中是否遇到过这些问题:

❌ 每天登录几十台服务器检查状态
❌ 部署应用时一台台手动操作
❌ 出了问题不知道是哪台服务器
❌ 配置信息分散在 Excel/文档里
❌ 重复性工作太多,没时间学习

如果有,那这个平台就是为你做的。

1.2 现有工具的不足

市面上的运维工具很多,但都有局限:

工具优点缺点
Ansible功能强大学习曲线陡,需要额外学习
JumpServer堡垒机功能好侧重安全,运维功能弱
Zabbix监控强大配置复杂,不够灵活
自研脚本灵活零散,不成体系

我们的目标: 做一个轻量、易用、可扩展的运维平台。


二、需求分析

2.1 核心功能

根据我 16年运维经验,一个运维平台最核心的功能是:

1. 服务器管理(CMDB)
   - 服务器信息录入
   - 分组/标签管理
   - 快速搜索过滤

2. 批量执行
   - 选择多台服务器
   - 同时执行命令
   - 实时查看结果

3. 自动化部署
   - 上传代码/包
   - 执行部署脚本
   - 回滚功能

4. 监控告警
   - 基础指标采集
   - 阈值告警
   - 通知推送

5. 工单系统
   - 资源申请
   - 变更审批
   - 操作记录

2.2 用户角色

管理员:
- 所有权限
- 用户管理
- 系统配置

运维人员:
- 服务器管理
- 批量执行
- 部署操作

开发人员:
- 查看服务器状态
- 提交部署申请
- 查看日志

只读用户:
- 只能查看
- 不能操作

三、技术选型

3.1 后端:为什么选 FastAPI?

框架性能学习成本文档异步支持
Flask⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Django⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
FastAPI⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

FastAPI 优势:

  1. 性能高 - 基于 Starlette,性能接近 NodeJS
  2. 自动文档 - 自动生成 Swagger UI
  3. 类型检查 - 基于 Pydantic,减少 bug
  4. 异步支持 - 原生支持 async/await
  5. 开发快 - 代码量少,开发效率高

3.2 前端:为什么选 Vue 3?

框架学习成本生态性能社区
React⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Vue 3⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Angular⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

Vue 3 优势:

  1. 上手快 - 模板语法简单
  2. 组件丰富 - Element Plus 组件库
  3. 性能好 - Composition API
  4. 中文友好 - 文档和社区都是中文

3.3 数据库:MySQL

  • 运维数据关系复杂,适合关系型数据库
  • MySQL 稳定、成熟、资料多
  • 后期可扩展 Redis 缓存

3.4 部署:Docker

  • 环境一致,避免"在我机器上能跑"
  • 一键部署,降低维护成本
  • 方便扩展和迁移

四、项目架构

4.1 整体架构图

┌─────────────────────────────────────────────────────────┐
│                      Nginx (反向代理)                     │
└─────────────────────────────────────────────────────────┘
              │                        │
              ▼                        ▼
    ┌─────────────────┐      ┌─────────────────┐
    │   Vue 前端       │      │  FastAPI 后端    │
    │   (80 端口)      │      │  (8000 端口)     │
    └─────────────────┘      └─────────────────┘
                                      │
                                      ▼
                              ┌─────────────────┐
                              │    MySQL        │
                              │    (3306 端口)   │
                              └─────────────────┘
                                      │
                                      ▼
                              ┌─────────────────┐
                              │   目标服务器     │
                              │   (SSH 连接)     │
                              └─────────────────┘

4.2 后端目录结构

ops-platform/
├── backend/                    # 后端代码
│   ├── app/
│   │   ├── __init__.py
│   │   ├── main.py            # FastAPI 入口
│   │   ├── config.py          # 配置文件
│   │   ├── database.py        # 数据库连接
│   │   ├── models/            # 数据模型
│   │   │   ├── __init__.py
│   │   │   ├── server.py      # 服务器模型
│   │   │   ├── user.py        # 用户模型
│   │   │   └── task.py        # 任务模型
│   │   ├── schemas/           # Pydantic 模型
│   │   │   ├── __init__.py
│   │   │   ├── server.py
│   │   │   ├── user.py
│   │   │   └── task.py
│   │   ├── api/               # API 路由
│   │   │   ├── __init__.py
│   │   │   ├── servers.py
│   │   │   ├── users.py
│   │   │   └── tasks.py
│   │   ├── utils/             # 工具函数
│   │   │   ├── __init__.py
│   │   │   ├── ssh_client.py  # SSH 客户端
│   │   │   └── auth.py        # 认证工具
│   │   └── core/              # 核心配置
│   │       ├── __init__.py
│   │       └── security.py
│   ├── tests/                 # 测试代码
│   ├── requirements.txt       # Python 依赖
│   └── Dockerfile             # Docker 镜像
├── frontend/                   # 前端代码
│   ├── src/
│   │   ├── main.js
│   │   ├── App.vue
│   │   ├── views/             # 页面
│   │   ├── components/        # 组件
│   │   ├── router/            # 路由
│   │   ├── store/             # 状态管理
│   │   └── api/               # API 请求
│   ├── public/
│   ├── package.json
│   └── Dockerfile
├── docker-compose.yml          # Docker 编排
├── README.md
└── docs/                       # 文档

4.3 前端目录结构

frontend/
├── src/
│   ├── main.js                # 入口文件
│   ├── App.vue                # 根组件
│   ├── views/                 # 页面视图
│   │   ├── Login.vue          # 登录页
│   │   ├── Dashboard.vue      # 首页
│   │   ├── Servers.vue        # 服务器管理
│   │   ├── Tasks.vue          # 任务管理
│   │   └── Settings.vue       # 设置
│   ├── components/            # 公共组件
│   │   ├── Header.vue
│   │   ├── Sidebar.vue
│   │   └── Table.vue
│   ├── router/                # 路由配置
│   │   └── index.js
│   ├── store/                 # Vuex 状态管理
│   │   ├── index.js
│   │   └── modules/
│   ├── api/                   # API 封装
│   │   ├── request.js
│   │   ├── server.js
│   │   └── task.js
│   └── utils/                 # 工具函数
│       ├── auth.js
│       └── format.js
├── public/
│   └── index.html
├── package.json
└── vite.config.js

五、数据库设计

5.1 ER 图

┌─────────────┐      ┌─────────────┐
│    users    │      │   groups    │
├─────────────┤      ├─────────────┤
│ id          │      │ id          │
│ username    │      │ name        │
│ password    │      │ description │
│ email       │      └─────────────┘
│ role        │             │
│ group_id    │             │
└─────────────┘             │
        │                   │
        │                   │
        ▼                   ▼
┌─────────────┐      ┌─────────────┐
│   servers   │      │  server_    │
├─────────────┤      │   group     │
│ id          │      ├─────────────┤
│ hostname    │      │ server_id   │
│ ip          │      │ group_id    │
│ port        │      └─────────────┘
│ username    │
│ password    │
│ group_id    │
└─────────────┘
        │
        │
        ▼
┌─────────────┐
│    tasks    │
├─────────────┤
│ id          │
│ name        │
│ type        │
│ server_ids  │
│ command     │
│ status      │
│ result      │
│ created_by  │
│ created_at  │
└─────────────┘

5.2 核心表结构

users 表

CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    email VARCHAR(100),
    role ENUM('admin', 'ops', 'dev', 'readonly') DEFAULT 'readonly',
    group_id INT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

servers 表

CREATE TABLE servers (
    id INT PRIMARY KEY AUTO_INCREMENT,
    hostname VARCHAR(100) NOT NULL,
    ip VARCHAR(50) NOT NULL,
    port INT DEFAULT 22,
    username VARCHAR(50) DEFAULT 'root',
    password VARCHAR(255),
    os VARCHAR(50),
    cpu_cores INT,
    memory_gb INT,
    disk_gb INT,
    group_id INT,
    status ENUM('online', 'offline', 'maintenance') DEFAULT 'offline',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

tasks 表

CREATE TABLE tasks (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    type ENUM('command', 'deploy', 'backup') NOT NULL,
    server_ids TEXT,
    command TEXT,
    status ENUM('pending', 'running', 'success', 'failed') DEFAULT 'pending',
    result TEXT,
    created_by INT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    started_at TIMESTAMP NULL,
    finished_at TIMESTAMP NULL
);

六、核心代码(抢先看)

6.1 FastAPI 入口

# backend/app/main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.api import servers, users, tasks
from app.database import engine, Base

# 创建数据库表
Base.metadata.create_all(bind=engine)

app = FastAPI(
    title="运维管理平台",
    description="基于 FastAPI + Vue 的运维自动化平台",
    version="1.0.0"
)

# 跨域配置
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 注册路由
app.include_router(servers.router, prefix="/api/servers", tags=["服务器"])
app.include_router(users.router, prefix="/api/users", tags=["用户"])
app.include_router(tasks.router, prefix="/api/tasks", tags=["任务"])

@app.get("/")
async def root():
    return {"message": "欢迎使用运维管理平台"}

6.2 SSH 客户端

# backend/app/utils/ssh_client.py
import paramiko
from typing import Tuple, Optional

class SSHClient:
    def __init__(self, host: str, port: int = 22, 
                 username: str = 'root', password: Optional[str] = None,
                 key_file: Optional[str] = None):
        self.host = host
        self.ssh = paramiko.SSHClient()
        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        
        if key_file:
            self.ssh.connect(host, port, username, key_filename=key_file)
        elif password:
            self.ssh.connect(host, port, username, password)
        else:
            raise ValueError("必须提供 password 或 key_file")
    
    def exec_command(self, command: str) -> Tuple[int, str, str]:
        """执行命令,返回 (退出码,输出,错误)"""
        stdin, stdout, stderr = self.ssh.exec_command(command)
        exit_code = stdout.channel.recv_exit_status()
        return exit_code, stdout.read().decode(), stderr.read().decode()
    
    def upload_file(self, local_path: str, remote_path: str):
        """上传文件"""
        sftp = self.ssh.open_sftp()
        sftp.put(local_path, remote_path)
        sftp.close()
    
    def close(self):
        self.ssh.close()

6.3 批量执行任务

# backend/app/api/tasks.py
from fastapi import APIRouter, BackgroundTasks
from app.models.task import Task
from app.utils.ssh_client import SSHClient
from app.database import get_db
from concurrent.futures import ThreadPoolExecutor

router = APIRouter()

def execute_task(task_id: int, server_ids: list, command: str):
    """后台执行任务"""
    db = next(get_db())
    task = db.query(Task).filter(Task.id == task_id).first()
    
    results = []
    with ThreadPoolExecutor(max_workers=10) as executor:
        for server_id in server_ids:
            server = db.query(Server).filter(Server.id == server_id).first()
            
            def run_on_server(s):
                try:
                    ssh = SSHClient(s.ip, s.port, s.username, s.password)
                    exit_code, output, error = ssh.exec_command(command)
                    ssh.close()
                    return {
                        "server": s.hostname,
                        "success": exit_code == 0,
                        "output": output,
                        "error": error
                    }
                except Exception as e:
                    return {
                        "server": s.hostname,
                        "success": False,
                        "error": str(e)
                    }
            
            results.append(executor.submit(run_on_server, server))
    
    # 收集结果
    task.result = [r.result() for r in results]
    task.status = "success" if all(r.result()["success"] for r in results) else "failed"
    db.commit()

@router.post("/")
async def create_task(task: TaskCreate, background_tasks: BackgroundTasks):
    """创建批量执行任务"""
    db = next(get_db())
    
    # 创建任务记录
    db_task = Task(**task.dict())
    db_task.status = "pending"
    db.add(db_task)
    db.commit()
    
    # 后台执行
    background_tasks.add_task(
        execute_task,
        db_task.id,
        task.server_ids,
        task.command
    )
    
    return {"task_id": db_task.id, "status": "pending"}

七、开发环境搭建

7.1 后端环境

# 1. 克隆项目
git clone https://gitee.com/wgsummer/ops-platform.git

cd ops-platform/backend

# 2. 创建虚拟环境
python3 -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

# 3. 安装依赖
pip install -r requirements.txt

# 4. 配置数据库
# 修改 app/config.py 中的数据库连接

# 5. 启动服务
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

requirements.txt:

fastapi==0.104.1
uvicorn[standard]==0.24.0
sqlalchemy==2.0.23
pymysql==1.1.0
paramiko==3.4.0
pydantic==2.5.0
pydantic-settings==2.1.0
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
python-multipart==0.0.6
email-validator==2.3.0

依赖说明:

  • fastapi - Web 框架
  • uvicorn - ASGI 服务器
  • sqlalchemy - ORM 框架
  • pymysql - MySQL 驱动
  • paramiko - SSH 库
  • pydantic - 数据验证
  • python-jose - JWT 认证
  • passlib - 密码加密

7.2 前端环境

# 1. 进入前端目录
cd ops-platform/frontend

# 2. 安装依赖
npm install

# 3. 启动开发服务器
npm run dev

package.json 关键依赖:

{
  "dependencies": {
    "vue": "^3.3.8",
    "vue-router": "^4.2.5",
    "vuex": "^4.1.0",
    "element-plus": "^2.4.3",
    "axios": "^1.6.2"
  }
}

7.3 Docker 一键启动

# 项目根目录
docker-compose up -d

docker-compose.yml:

version: '3.8'

services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: ops_platform
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"

  backend:
    build: ./backend
    ports:
      - "8000:8000"
    depends_on:
      - mysql
    environment:
      DATABASE_URL: mysql://root:root123@mysql/ops_platform

  frontend:
    build: ./frontend
    ports:
      - "80:80"
    depends_on:
      - backend

  nginx:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - frontend
      - backend

volumes:
  mysql_data:

八、API 文档

FastAPI 自动生成 Swagger UI 文档:

访问地址: http://localhost:8000/docs

主要 API 列表:

方法路径说明
GET/api/servers获取服务器列表
POST/api/servers添加服务器
PUT/api/servers/{id}更新服务器
DELETE/api/servers/{id}删除服务器
POST/api/tasks创建任务
GET/api/tasks/{id}获取任务状态
POST/api/users/login用户登录

九、下一步

本文介绍了项目架构,下一篇我们开始后端开发

第二篇预告:

  • 用户认证(JWT)
  • 服务器管理 API
  • 批量执行 API
  • 数据库操作

项目进度:

  • ✅ 架构设计
  • ✅ 后端开发(代码已开源)
  • ⏳ 前端开发(下一篇)
  • ⏳ 功能实现
  • ⏳ 部署上线

十、源码地址

GitHub: github.com/WGsummer/op…

Gitee(国内镜像): gitee.com/wgsummer/op…


结语

运维平台是一个系统工程,需要前后端配合。但这个系列我会尽量拆解得简单易懂,即使你没有开发经验,也能跟着做出来。

如果你觉得有用:

  1. 点赞支持一下
  2. 关注我,不错过后续文章
  3. 有问题评论区交流

周三更新第二篇:后端开发


(完)

本文是《FastAPI+Vue 搭建运维平台》系列第一篇,共 5 篇。

作者:运维老王,16年运维经验,专注运维自动化。

知乎/掘金:运维老王