Ceph 集群从测试走向生产后,Web 管理入口的缺失会让故障定位和日常运维成本明显上升。Ceph 自带的 Dashboard 虽然覆盖了基础监控,但在 UI 风格、权限隔离和业务集成上往往无法满足团队定制需求。借助 Vue 3 的工程化能力,可以快速搭建一个面向 Ceph 的分布式存储管理平台,把存储池、OSD、RADOS Gateway 和监控数据统一到一个可维护的前端项目里。

本文从工程化视角出发,介绍如何用 Vue 3、TypeScript、Pinia 和 Axios 构建 Ceph 存储管理前端,覆盖项目初始化、请求封装、核心模块实现以及生产环境优化,帮助团队降低 Ceph 的日常运维复杂度。
一、为什么需要在 Vue 3 中工程化 Ceph 管理端
Ceph 作为分布式存储系统,核心组件包括 RADOS、RBD、CephFS 和 RADOS Gateway,这些组件本身只提供命令行工具和有限的 Web Dashboard。当集群规模超过几十个 OSD、存储池数量增多后,仅靠命令行检查 ceph -s 或 ceph osd pool ls 很难快速发现异常节点和容量瓶颈。团队需要统一的 Web 界面来查看集群健康状态、管理存储池配额、监控 OSD 的读写延迟。
自建管理前端的优势在于可以按照业务场景裁剪功能。比如只给应用管理员暴露对象存储桶的创建和配额调整入口,而将 OSD 上下线操作留给存储管理员。Vue 3 的组件化开发模式非常适合这种分区清晰的运维面板。工程化也不是简单请求几个接口,而是要把认证、状态管理、错误处理和性能优化纳入统一框架,避免在多个页面中重复编写登录和不稳定的调用逻辑。
另一个关键在于 Ceph 的 API 并不统一。Dashboard 提供基于 JWT 的 REST API,RADOS Gateway 则暴露 S3 兼容接口和 Admin Ops API。直接用浏览器调 S3 接口会遇到跨域和签名问题,需要由前端工程通过代理层或后端来收敛。这就引出了下一节的工程化基础建设。
二、项目基础:Vue 3 工程化与请求层封装
初始化一个 Vue 3 项目可以使用 Vite 的官方模板,TypeScript 支持可以显著提高接口数据结构的可维护性。安装 Axios、Pinia、Vue Router、Element Plus 以及可视化库 ECharts,能够覆盖管理台常见的表格、表单和图表需求。
npm create vite@latest ceph-admin -- --template vue-ts cd ceph-admin npm install axios pinia vue-router element-plus echarts aws-sdk
请求层是工程化的重点。Ceph Dashboard 的登录接口返回短期 token,后续接口需要在请求头中携带 Authorization 字段。统一封装 Axios 实例可以集中处理 token 注入、超时和 401 跳转,而不是在每个组件里重复编写。下面的封装把响应直接解包,业务层拿到的就是接口数据,出错时由拦截器统一提示并清理过期凭证。
import axios from 'axios';
import type { AxiosInstance, InternalAxiosRequestConfig } from 'axios';
const request: AxiosInstance = axios.create({
baseURL: '/api',
timeout: 15000,
});
request.interceptors.request.use((config: InternalAxiosRequestConfig) => {
const token = localStorage.getItem('ceph_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
request.interceptors.response.use(
(response) => response.data,
(error) => {
if (error.response?.status === 401) {
localStorage.removeItem('ceph_token');
window.location.href = '/login';
}
return Promise.reject(error);
}
);
export default request;
Pinia 的状态管理主要用来缓存存储池和 OSD 的列表数据。如果每个页面挂载时都重新拉取完整集群信息,Dashboard API 会承受不小的压力。把数据放在 store 中,页面复用同一份状态,同时通过 loading 标记避免并发重复请求。这样在切换路由时,已经加载过的存储池列表可以立即渲染。
import { defineStore } from 'pinia';
import request from '@/utils/request';
interface Pool {
pool_name: string;
type: string;
size: number;
pg_num: number;
used_bytes: number;
}
export const useCephStore = defineStore('ceph', {
state: () => ({
pools: [] as Pool[],
osds: [] as any[],
loading: false,
}),
actions: {
async fetchPools() {
this.loading = true;
try {
const res = await request.get('/pool');
this.pools = res as Pool[];
} finally {
this.loading = false;
}
},
},
});
三、核心运维模块:存储池、OSD 与 S3 桶管理
存储池管理是 Ceph 运维中最常用的功能。通过 Dashboard 的 /api/pool 接口可以获取所有存储池的副本数、PG 数量和已使用容量。前端需要把这些原始数据处理成易读的格式,例如将字节数转换为 KB、MB、GB。用 Element Plus 的 <el-table> 组件渲染列表,同时支持按类型筛选,可以快速定位到某个 RBD 或 CephFS 池。
<template>
<el-table :data="store.pools" v-loading="store.loading">
<el-table-column prop="pool_name" label="存储池" />
<el-table-column prop="type" label="类型" width="120" />
<el-table-column prop="size" label="副本数" width="100" />
<el-table-column prop="pg_num" label="PG 数量" width="120" />
<el-table-column label="使用量">
<template #default="{ row }">
{{ formatSize(row.used_bytes) }}
</template>
</el-table-column>
</el-table>
</template>
<script setup lang="ts">
import { onMounted } from 'vue';
import { useCephStore } from '@/store/ceph';
const store = useCephStore();
function formatSize(bytes: number): string {
if (!bytes) return '0 B';
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let index = 0;
let size = bytes;
while (size >= 1024 && index < units.length - 1) {
size /= 1024;
index++;
}
return `${size.toFixed(2)} ${units[index]}`;
}
onMounted(() => {
store.fetchPools();
});
</script>
OSD 的读写延迟和状态直接影响整个集群的可用性。通过接口获取 OSD 列表后,前端可以用 ECharts 饼图展示在线和离线的 OSD 数量。轮询频率建议设置为 15 到 30 秒一次,避免给 Dashboard 带来额外负担。如果集群规模很大,还可以把 OSD 数据按照主机分组,形成树状表格,方便定位到具体磁盘。
import * as echarts from 'echarts';
import request from '@/utils/request';
export async function renderOsdChart(el: HTMLElement) {
const osdMap = await request.get('/osd');
const states = osdMap.osds.map((osd: any) => osd.state);
const upCount = states.filter((s: string) => s === 'up').length;
const downCount = states.length - upCount;
const chart = echarts.init(el);
chart.setOption({
tooltip: { trigger: 'item' },
series: [{
type: 'pie',
radius: '60%',
data: [
{ value: upCount, name: '在线' },
{ value: downCount, name: '离线' }
]
}]
});
}
对象存储桶管理则主要面向 RADOS Gateway 的 S3 接口。前端可以直接使用 AWS SDK for JavaScript 完成桶的创建、删除和配额调整。不过浏览器直连 S3 会暴露访问密钥,所以更稳妥的做法是由后端或服务端代理签名。Vue 3 工程化中通常把 S3 调用封装成一个独立模块,只暴露高层方法,组件不直接接触密钥和签名逻辑。
四、生产环境的安全与性能优化
开发阶段可以通过 Vite 的本地代理把 /api 转发到 Ceph Dashboard 地址,从而绕过浏览器的跨域限制。生产部署时建议使用 Nginx 反向代理,集中处理 HTTPS、证书校验和请求头转发。下面的 Nginx 配置同时支持前端静态资源托管和 API 代理,避免直接暴露 Ceph Dashboard 的 8443 端口。
server {
listen 80;
server_name ceph-admin.internal;
location /api/ {
proxy_pass https://127.0.0.1:8443/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_ssl_verify off;
}
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
}
安全层面除了 token 的短期失效机制,还要注意前端存储 token 的方式。虽然 localStorage 使用简单,但容易受到 XSS 攻击。更严格的方案是把 token 放在 HttpOnly Cookie 中,由服务端在登录后写入,前端不直接读取凭证。即便使用本地存储,也应设置较短的过期时间和统一的退出清理逻辑。对于 S3 密钥,绝对不要打包进前端代码,必须通过后端生成预签名 URL 或者使用短期 STS 凭证。
大集群的渲染性能也不可忽视。如果存储池或 OSD 列表包含上千条记录,直接渲染会阻塞页面。虚拟滚动组件可以减少 DOM 节点数量,搜索和筛选操作加上防抖能够显著降低请求频率。对于集群健康状态的展示,可以用 WebSocket 或 SSE 推送替代定时轮询,减少无意义的流量消耗。缓存方面可以把变化不频繁的集群拓扑信息缓存 5 分钟,而容量和延迟数据保持更短的刷新周期。
总体来看,Vue 3 工程化对接 Ceph 的核心不仅是调用几个 API,而是通过统一的请求层、状态管理和安全代理把分散的存储组件纳入可维护的前端体系。当底层 Ceph 集群升级或接口变化时,只需调整封装层,无需改动各个页面组件,这也是工程化带来的长期收益。

