跳到主要内容

Virtual Server 存储

1. 概述

PGOS 支持在标题区域内创建一个或多个数据存储服务,称为Virtual Server存储(简称“VS 存储”)。这些服务只能通过 PGOS 内网访问,确保安全使用,无需担心其他安全问题。

PGOS 为不同用例提供多种存储服务,包括:

  1. Redis
  2. MongoDB
  3. 磁盘

通过阅读本章,您可以了解:

  1. 如何申请 VS 存储;
  2. 如何使用 Web 控制台;
  3. 如何编写Virtual Server代码以使用存储;
  4. 如何操作和维护数据库。

VS 存储页面位于Extension > Virtual Server Storage中。所有已创建的 VS 存储都会列在该页面中,如下所示:

VS Storage List

提示

注意:

  1. 由于 VS 存储属于硬件资源,PGOS 不支持在 DevOps 工具中导入和同步 VS 存储。
  2. 如果Virtual Server挂载了磁盘,则在 DevOps 工具中导入或同步时,挂载的磁盘不会被转移。

2. 申请 VS 存储

申请后,VS 存储即可自动部署。要申请 VS 存储,请点击页面左上角的“新建Virtual Server存储”按钮。这将打开申请表单,您可以在其中填写创建新 VS 存储所需的详细信息。

VS Storage Application Form

申请表字段:

  • Storage name 存储名称:为您的存储输入一个唯一的名称。
  • Storage type 存储类型:选择存储类型(MongoDB、Redis、磁盘)。
  • Cluster Type 集群类型(仅限数据库):选择标准或集群。
  • Version 版本(仅限数据库):选择存储类型的版本。
  • Specification 规格:根据 CPU、内存、磁盘和副本数选择规格。

填写完表格后,点击“提交”提交您的申请以供审核。PGOS 团队将审核您的申请,批准后系统将自动部署所请求的存储。

3. 使用 VS 存储

存储服务实例的连接和身份验证信息显示在“信息”列表中。但是,这些信息仅用于调试目的,不应在生产代码中使用。请使用环境变量来获取存储信息。

3.1 数据库信息

VS Storage Application Form

  • Connection:当前存储服务的连接信息;
  • Spec:当前存储服务的 CPU、内存规格;
  • Type:当前存储服务的集群类型;
  • Disk:当前存储服务的可用磁盘大小(集群类型显示磁盘总大小);
  • Replicas:当前存储服务的副本数。

3.2 磁盘信息

info for disk

  • 状态:磁盘的状态(已绑定或未绑定)。
  • 大小:磁盘的可用大小。
  • 类型:磁盘的类型(目前仅提供“SSD”类型;如有需要,可提供“HSSD”类型)。

4. Web 控制台

点击“Web 控制台”按钮,弹出当前实例的管理界面,如下图所示:

Redis Web 控制台

image-20240321145241106

MongoDB Web 控制台

image-20240321145305994

在管理对话框中,您可以对当前存储实例进行以下操作:

  1. 查看存储服务实例的状态信息;
  2. 操作存储服务实例,添加、删除、修改和查看数据;
  3. 存储服务实例控制台操作更加便捷,灵活性更高;
提示

目前云盘暂不支持网页端管理。如果您需要浏览云盘文件,建议您将其挂载到Virtual Server(例如使用 filebrowser/filebrowser 等开源 Docker 镜像)上,通过网页端浏览文件。

5. 编写 Virtual Server 代码以使用存储

首先,在 Virtual Server 中保存要使用的存储服务实例的信息。其次,在 Virtual Server 中安装相应的第三方依赖项(注意依赖项的版本是否与当前运行时兼容),并根据第三方依赖项的文档进行操作。

提示

建议使用环境变量获取存储信息

  • 我们建议使用环境变量获取Virtual Server存储信息,这样可以避免硬编码并提高代码的可维护性。
  • 在未来版本中,我们将隐藏门户的Virtual Server存储信息,仅允许通过环境变量访问。
  • 如果您不知道如何使用环境变量,请参阅Virtual Server环境变量

5.1 如何在Virtual Server中使用 Redis

以下内容基于 NodeJS,其他语言的操作方法类似。

5.1.1. 安装 Redis 依赖项

修改Virtual Server的 package.json 文件,并在 dependencies 中添加 "redis": "4.0.0"。完整文件内容如下:

{
"name": "helloworld",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"redis": "4.0.0"
}
}

5.1.2. 编写代码操作 Redis

请参考第三方依赖库的文档操作 Redis。文档地址:https://www.npmjs.com/package/redis/v/4.0.0。我们编写一个简单的 Demo 来实现 Redis 的连接、基本的存储和查询操作。

首先,封装创建 Redis 实例的工具函数和连接池信息。

工具函数文件目录地址:"./redis/redis.ts"

import * as redis from 'redis';

// Redis connection pool, which caches established connections.
const RedisConnectPool = new Map();

interface RedisConfig {
host: string;
port: number;
account?: string;
password?: string;
database?: number;
}

/**
* @author PGOS Team
* @time 2022.10.27 11:30:40
* @description PGOS get Redis client.
* @param {Object} redisConfig
* @param {String} redisConfig.host - default: 127.0.0.1.
* @param {Number} redisConfig.port - default: 6379.
* @param {String} redisConfig.account - Redis account, optional.
* @param {String} redisConfig.password - Redis password, optional.
* @param {Number} redisConfig.database - default: 0
*/
export const getRedisConnectedClient = async (options: RedisConfig) => {
const { host, port, account, password, database } = options;
const key = `${host}:${port}:${account}:${password}:${database}`;

if (RedisConnectPool.has(key)) {
console.log('getRedisConnectedClient --> RedisConnectPool has key');
return RedisConnectPool.get(key);
}

const [err, client] = await createRedisConnectClient(options);
if (err) {
throw err;
}

RedisConnectPool.set(key, client);
return client;
};

/**
* @description PGOS create Redis client.
* @author PGOS Team
* @time 2022.10.27 11:13:28
*/
const createRedisConnectClient = (redisConfig: RedisConfig) => {
const { host, port, account, password, database } = redisConfig;
console.log('createRedisConnectClient -->', host, port, account, password, database);

const result = new Promise<[Error | null, any]>(resolve => {
const client = redis.createClient({
url: `redis://${host}:${port}`,
username: account,
password,
database
});

client.on('ready', () => {
console.log('RedisTool.createRedisConnectClient --> ready');
resolve([null, client]);
});

client.on('error', err => {
console.error('RedisTool.createRedisConnectClient --> error', err);
resolve([err, null]);
});

client.connect();
});

return result;
};
其次,建立连接并执行操作
import Koa from 'koa';
import Router from 'koa-router';
import koaBodyParser from 'koa-bodyparser';
import serve from 'koa-static';
import path from 'path';

import { getRedisConnectedClient } from './redis/redis';

const app = new Koa();
const router = new Router();

router.all('/redis', async ctx => {
console.log(`[/redis] ${new Date().toLocaleString()} ${ctx.request.method} ${ctx.request.url}}`);
console.log('[/redis]', ctx.request.body);

// Use the environment variable to get the Redis configuration information
const redisConfig = process.env.['PGOS_VS_Storage_<RedisName>'];
const parsedRedisConfig = JSON.parse(redisConfig);

// Please fill in the values from VS Storage in the options below.
const redisClient = await getRedisConnectedClient({
host: parsedRedisConfig.network[0].inner_ip,
port: parsedRedisConfig.network[0].port,
account: '',
password: parsedRedisConfig.password,
database: 0
});

redisClient.set('key', 'value');
const value = await redisClient.get('key');

console.log('[/redis] value -->', value);

// Return the data to the client
ctx.body = {
code: 200,
message: 'success',
time: new Date().toISOString(),
request: {
method: ctx.request.method,
url: ctx.request.url,
body: ctx.request.body,
query: ctx.request.query
},
data: value
};
});

app.use(koaBodyParser());
app.use(router.routes()).use(router.allowedMethods());
app.listen(8080);
console.log('Server is running at http://localhost:8080');

5.2 如何在Virtual Server中使用 MongoDB

以下内容基于 NodeJS,其他语言的操作方法类似。

5.2.1. 安装 MongoDB 依赖项

修改Virtual Server的 package.json 文件,并在 dependencies 中添加 "mongoose": "5.10.7"。完整文件内容如下:

{
"name": "helloworld",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"mongoose": "5.10.7"
}
}

5.2.2. 编写代码操作 MongoDB

请按照第三方依赖项的文档操作 MongoDB。文档地址:https://mongoosejs.com/docs/。我们编写了一个简单的 Demo 来实现 MongoDB 的连接、基本的存储和查询操作。

首先,封装了创建 MongoDB 实例的工具函数和连接池信息。

工具函数文件目录地址:"./mongodb/mongodb.ts"

import mongoose from 'mongoose';

// MongoDB connection pool, which caches established connections.
const MongoDBConnectPool = new Map();

interface MongoDBConfig {
host: string;
port: number;
account?: string;
password?: string;
database?: string;
}

/**
* @description PGOS get MongoDB client.
* @author PGOS Team
* @time 2023.08.11 11:30:40
* @param {Object} mongoDBConfig
* @param {String} mongoDBConfig.host - default: 127.0.0.1.
* @param {Number} mongoDBConfig.port - default: 6379.
* @param {String} mongoDBConfig.account - MongoDB account, optional.
* @param {String} mongoDBConfig.password - MongoDB password, optional.
* @param {Number} mongoDBConfig.database - default: test.
*/
export const getMongoDBConnectedClient = async (options: MongoDBConfig) => {
const { host, port, account, password, database } = options;
const key = `${host}:${port}:${account}:${password}:${database}`;

if (MongoDBConnectPool.has(key)) {
console.log('getMongoDBConnectedClient --> MongoDBConnectPool has key');
return MongoDBConnectPool.get(key);
}

const [err, client] = await createMongoDBConnectClient(options);
if (err) {
throw err;
}

MongoDBConnectPool.set(key, client);
return client;
};

/**
* @author PGOS Team
* @time 2022.10.27 11:13:28
* @description PGOS create MongoDB client.
*/
const createMongoDBConnectClient = (mongoDBConfig: MongoDBConfig) => {
const { host, port, account, password, database } = mongoDBConfig;
console.log('createMongoDBConnectClient -->', host, port, account, password, database);

const result = new Promise<[Error | null, any]>(resolve => {
const url = `mongodb://${account}:${password}@${host}:${port}/${database}?authSource=admin&retryWrites=false`;
console.log('mongodb url', url);

const client = mongoose.createConnection(url, {
useUnifiedTopology: true,
useNewUrlParser: true,
useFindAndModify: false,
keepAlive: true,
keepAliveInitialDelay: 30000
});

client.on('connected', err => {
console.log('MongoDBTool.createMongoDBConnectClient --> connected', err);
resolve([err, client]);
});

client.on('disconnected', () => {
const deleteConnections: Array<any> = [];
MongoDBConnectPool.forEach((item, key) => {
if (item === this) deleteConnections.push(key);
});
deleteConnections.forEach(item => MongoDBConnectPool.delete(item));
console.log('MongoDBTool.createMongoDBConnectClient --> disconnected', deleteConnections, MongoDBConnectPool.size);
});
});

return result;
};
其次,建立连接并执行操作
import Koa from 'koa';
import Router from 'koa-router';
import koaBodyParser from 'koa-bodyparser';
import serve from 'koa-static';
import path from 'path';

import { Schema } from 'mongoose';

import { getMongoDBConnectedClient } from './mongodb/mongodb';

const app = new Koa();
const router = new Router();

router.all('/mongodb', async ctx => {
console.log(`[/mongodb] ${new Date().toLocaleString()} ${ctx.request.method} ${ctx.request.url}}`);
console.log('[/mongodb]', ctx.request.body);

// Use the environment variable to get the MongoDB configuration information
const mongoDBConfig = process.env.['PGOS_VS_Storage_<MongoDBName>'];
const parsedMongoDBConfig = JSON.parse(mongoDBConfig);

// Please fill in the values from VS Storage in the options below.
const mongodbClient = await getMongoDBConnectedClient({
host: parsedMongoDBConfig.network[0].inner_ip,
port: parsedMongoDBConfig.network[0].port,
account: parsedMongoDBConfig.account,
password: parsedMongoDBConfig.password,
database: 'test'
});

const TestSchema = new Schema({
id: { type: Number, default: null },
name: { type: String, default: null },
age: { type: String, default: null }
});

const model = mongodbClient.model('test_collection_1', TestSchema, 'test_collection_1');

// 测试新增数据
const res = await model.create({ id: 1000, name: 'PGOS', age: 3 });
console.log('[/mongodb] mongodb create -->', JSON.stringify(res));

const list = await model.find({}, {}, {});
console.log('[/mongodb] mongodb find -->', JSON.stringify(list));

// Return the data to the client
ctx.body = {
code: 200,
message: 'success',
time: new Date().toISOString(),
request: {
method: ctx.request.method,
url: ctx.request.url,
body: ctx.request.body,
query: ctx.request.query
},
data: list
};
});

app.use(koaBodyParser());
app.use(router.routes()).use(router.allowedMethods());
app.listen(8080);
console.log('Server is running at http://localhost:8080');

5.3 如何为Virtual Server挂载云盘

创建云盘后,您可以将其挂载到您的Virtual Server。请访问链接创建和管理Virtual Server了解如何挂载云盘。

6. 数据库运维

目前,PGOS 暂不提供数据库监控、报警等运维功能。您可以使用 Web 控制台中的 Terminal 功能执行相关命令来实现运维功能。

image-20221027162649561