add deploy.md of deploy modelRT project
This commit is contained in:
parent
14d2a7ff65
commit
86199269f8
|
|
@ -0,0 +1,211 @@
|
||||||
|
# 项目依赖服务部署指南
|
||||||
|
|
||||||
|
本项目依赖于 $\text{PostgreSQL}$ 数据库和 $\text{Redis Stack Server}$(包含 $\text{Redisearch}$ 等模块)部署文档将使用 $\text{Docker}$ 容器化技术部署这两个依赖服务
|
||||||
|
|
||||||
|
## 前提条件
|
||||||
|
|
||||||
|
1. 已安装 $\text{Docker}$
|
||||||
|
2. 下载相关容器镜像
|
||||||
|
3. 确保主机的 $\text{5432}$ 端口($\text{Postgres}$)和 $\text{6379}$ 端口($\text{Redis}$)未被占用
|
||||||
|
|
||||||
|
### 1\. 部署 PostgreSQL 数据库
|
||||||
|
|
||||||
|
使用官方的 `postgres:13.16` 镜像,并设置默认的用户、密码和端口
|
||||||
|
|
||||||
|
#### 1.1 部署命令
|
||||||
|
|
||||||
|
运行以下命令启动 $\text{PostgreSQL}$ 容器
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --name postgres \
|
||||||
|
-e POSTGRES_USER=postgres \
|
||||||
|
-e POSTGRES_PASSWORD=coslight \
|
||||||
|
-p 5432:5432 \
|
||||||
|
-d postgres:13.16
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.2 连接信息
|
||||||
|
|
||||||
|
| 参数 | 值 | 说明 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| **容器名称** | `postgres` | 容器名 |
|
||||||
|
| **镜像版本** | `postgres:13.16` | 镜像名 |
|
||||||
|
| **主机端口** | `5432` | 外部应用连接使用的端口 |
|
||||||
|
| **用户名** | `postgres` | 默认超级用户 |
|
||||||
|
| **密码** | `coslight` | 配置的密码 |
|
||||||
|
|
||||||
|
#### 1.3 状态检查
|
||||||
|
|
||||||
|
要确认容器是否正在运行,请执行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 检查容器启动状态
|
||||||
|
docker ps -a |grep postgres
|
||||||
|
# 检查容器启动日志信息
|
||||||
|
docker logs postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2\. 部署 Redis Stack Server
|
||||||
|
|
||||||
|
我们将使用 `redis/redis-stack-server:latest` 镜像该镜像内置了 $\text{Redisearch}$ 模块,用于 $\text{ModelRT}$ 项目中补全功能
|
||||||
|
|
||||||
|
#### 2.1 部署命令
|
||||||
|
|
||||||
|
运行以下命令启动 $\text{Redis Stack Server}$ 容器
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --name redis -p 6379:6379 \
|
||||||
|
-d redis/redis-stack-server:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.2 连接信息
|
||||||
|
|
||||||
|
| 参数 | 值 | 说明 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| **容器名称** | `redis` | 容器名 |
|
||||||
|
| **镜像版本** | `redis/redis-stack-server:latest` | 镜像名 |
|
||||||
|
| **主机端口** | `6379` | 外部应用连接使用的端口 |
|
||||||
|
| **地址** | `localhost:6379` | |
|
||||||
|
| **密码** | **无** | 默认未设置密码 |
|
||||||
|
|
||||||
|
> **注意:** 生产环境中建议使用 `-e REDIS_PASSWORD=<your_secure_password>` 参数来设置 $\text{Redis}$ 访问密码
|
||||||
|
|
||||||
|
#### 2.3 状态检查
|
||||||
|
|
||||||
|
要确认容器是否正在运行,请执行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 检查容器启动状态
|
||||||
|
docker ps -a |grep redis
|
||||||
|
# 检查容器启动日志信息
|
||||||
|
docker logs redis
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.4 数据注入
|
||||||
|
|
||||||
|
测试数据注入
|
||||||
|
|
||||||
|
##### 2.4.1 Postgres数据注入
|
||||||
|
|
||||||
|
```SQL
|
||||||
|
INSERT INTO public."Topologic" VALUES (2, 1, '70c190f2-8a60-42a9-b143-ec5f87e0aa6b', '10f155cf-bd27-4557-85b2-d126b6e2657f', 1, NULL);
|
||||||
|
INSERT INTO public."Topologic" VALUES (3, 1, '70c190f2-8a60-42a9-b143-ec5f87e0aa6b', 'e32bc0be-67f4-4d79-a5da-eaa40a5bd77d', 1, NULL);
|
||||||
|
INSERT INTO public."Topologic" VALUES (4, 1, '70c190f2-8a60-42a9-b143-ec5f87e0aa6b', '70c190f2-8a75-42a9-b166-ec5f87e0aa6b', 1, NULL);
|
||||||
|
INSERT INTO public."Topologic" VALUES (5, 1, 'e32bc0be-67f4-4d79-a5da-eaa40a5bd77d', '70c200f2-8a75-42a9-c166-bf5f87e0aa6b', 1, NULL);
|
||||||
|
INSERT INTO public."Topologic" VALUES (1, 1, '00000000-0000-0000-0000-000000000000', '70c190f2-8a60-42a9-b143-ec5f87e0aa6b', 1, NULL);
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 2.4.2 Redis数据注入
|
||||||
|
|
||||||
|
Redis数据脚本
|
||||||
|
|
||||||
|
```Lua
|
||||||
|
redis.call('SADD', 'grid_keys', 'transformfeeder1_220', 'transformfeeder1_220_35', 'transformfeeder1_220_36')
|
||||||
|
redis.call('SADD', 'grid_transformfeeder1_220_zones_keys', 'I_A_rms', 'I_B_rms', 'I_C_rms')
|
||||||
|
redis.call('SADD', 'grid_transformfeeder1_220_35_zones_keys', 'I_A_rms', 'I_B_rms', 'I_C_rms')
|
||||||
|
redis.call('SADD', 'grid_transformfeeder1_220_36_zones_keys', 'I_A_rms', 'I_B_rms', 'I_C_rms')
|
||||||
|
|
||||||
|
local dict_key = 'search_suggestions_dict'
|
||||||
|
|
||||||
|
redis.call('FT.SUGADD', dict_key, 'transformfeeder1_220', 1)
|
||||||
|
redis.call('FT.SUGADD', dict_key, 'transformfeeder1_220_35', 1)
|
||||||
|
redis.call('FT.SUGADD', dict_key, 'transformfeeder1_220_36', 1)
|
||||||
|
redis.call('FT.SUGADD', dict_key, 'transformfeeder1_220.I_A_rms', 1)
|
||||||
|
redis.call('FT.SUGADD', dict_key, 'transformfeeder1_220.I_B_rms', 1)
|
||||||
|
redis.call('FT.SUGADD', dict_key, 'transformfeeder1_220.I_C_rms', 1)
|
||||||
|
redis.call('FT.SUGADD', dict_key, 'transformfeeder1_220_35.I_A_rms', 1)
|
||||||
|
redis.call('FT.SUGADD', dict_key, 'transformfeeder1_220_35.I_B_rms', 1)
|
||||||
|
redis.call('FT.SUGADD', dict_key, 'transformfeeder1_220_35.I_C_rms', 1)
|
||||||
|
redis.call('FT.SUGADD', dict_key, 'transformfeeder1_220_36.I_A_rms', 1)
|
||||||
|
redis.call('FT.SUGADD', dict_key, 'transformfeeder1_220_36.I_B_rms', 1)
|
||||||
|
redis.call('FT.SUGADD', dict_key, 'transformfeeder1_220_36.I_C_rms', 1)
|
||||||
|
|
||||||
|
return 'OK'
|
||||||
|
```
|
||||||
|
|
||||||
|
在Redis CLI 中导入命令
|
||||||
|
|
||||||
|
1. 使用 `EVAL "lua脚本" 0`即可成功导入数据
|
||||||
|
2. 使用 `SCRIPT LOAD "lua脚本"`加载脚本,然后使用 `EVAL SHA1值 0` 命令执行上一步存储命令返回的哈希值即可
|
||||||
|
|
||||||
|
### 3\. 启动 ModelRT 服务
|
||||||
|
|
||||||
|
#### 3.1 配置服务配置文件
|
||||||
|
|
||||||
|
以下表格为配置文件参数说明表
|
||||||
|
|
||||||
|
| 类别 | 参数名 | 作用描述 | 示例值 |
|
||||||
|
| :--- | :--- | :--- | :--- |
|
||||||
|
| **Postgres** | `host` | PostgreSQL 数据库服务器的 $\text{IP}$ 地址或域名。 | `"192.168.1.101"` |
|
||||||
|
| | `port` | PostgreSQL 数据库服务器的端口号。 | `5432` |
|
||||||
|
| | `database` | 连接的数据库名称。 | `"demo"` |
|
||||||
|
| | `user` | 连接数据库所使用的用户名。 | `"postgres"` |
|
||||||
|
| | `password` | 连接数据库所使用的密码。 | `"coslight"` |
|
||||||
|
| **Kafka** | `servers` | Kafka 集群的 $\text{Bootstrap Server}$ 地址列表(通常是 $\text{host:port}$ 形式,多个地址用逗号分隔)。 | `"localhost:9092"` |
|
||||||
|
| | `port` | Kafka 服务器的端口号。 | `9092` |
|
||||||
|
| | `group_id` | 消费者组 $\text{ID}$,用于标识和管理一组相关的消费者。 | `"modelRT"` |
|
||||||
|
| | `topic` | Kafka 消息的主题名称。 | `""` |
|
||||||
|
| | `auto_offset_reset` | 消费者首次启动或 $\text{Offset}$ 无效时,从哪个位置开始消费(如 `earliest` 或 `latest`)。 | `"earliest"` |
|
||||||
|
| | `enable_auto_commit` | 是否自动提交 $\text{Offset}$。设为 $\text{false}$ 通常用于手动控制 $\text{Offset}$ 提交。 | `"false"` |
|
||||||
|
| | `read_message_time_duration` | 读取消息时的超时或等待时间。 | `”0.5s"` |
|
||||||
|
| **Logger (Zap)** | `mode` | 日志模式,通常为 `development`(开发)或 `production`(生产)。影响日志格式。 | `"development"` |
|
||||||
|
| | `level` | 最低日志级别(如 $\text{debug, info, warn, error}$)。 | `"debug"` |
|
||||||
|
| | `filepath` | 日志文件的输出路径和名称格式(`%s` 会被替换为日期等)。 | `"/Users/douxu/Workspace/coslight/modelRT/modelRT-%s.log"` |
|
||||||
|
| | `maxsize` | 单个日志文件最大大小(单位:$\text{MB}$)。 | `1` |
|
||||||
|
| | `maxbackups` | 保留旧日志文件的最大个数。 | `5` |
|
||||||
|
| | `maxage` | 保留旧日志文件的最大天数。 | `30` |
|
||||||
|
| | `compress` | 是否压缩备份的日志文件。 | `false` |
|
||||||
|
| **Ants Pool** | `parse_concurrent_quantity` | 用于解析任务的协程池最大并发数量。 | `10` |
|
||||||
|
| | `rtd_receive_concurrent_quantity` | 用于实时数据接收任务的协程池最大并发数量。 | `10` |
|
||||||
|
| **Locker Redis** | `addr` | 分布式锁服务所使用的 $\text{Redis}$ 地址。 | `"127.0.0.1:6379"` |
|
||||||
|
| | `password` | $\text{Locker Redis}$ 的密码。 | `""` |
|
||||||
|
| | `db` | $\text{Locker Redis}$ 使用的数据库编号。 | `1` |
|
||||||
|
| | `poolsize` | $\text{Locker Redis}$ 连接池的最大连接数。 | `50` |
|
||||||
|
| | `timeout` | $\text{Locker Redis}$ 连接操作的超时时间(单位:毫秒)。 | `10` |
|
||||||
|
| **Storage Redis** | `addr` | 数据存储服务所使用的 $\text{Redis}$ 地址(例如 $\text{Redisearch}$)。 | `"127.0.0.1:6379"` |
|
||||||
|
| | `password` | $\text{Storage Redis}$ 的密码。 | `""` |
|
||||||
|
| | `db` | $\text{Storage Redis}$ 使用的数据库编号。 | `0` |
|
||||||
|
| | `poolsize` | $\text{Storage Redis}$ 连接池的最大连接数。 | `50` |
|
||||||
|
| | `timeout` | $\text{Storage Redis}$ 连接操作的超时时间(单位:毫秒)。 | `10` |
|
||||||
|
| **Base Config** | `grid_id` | 项目所操作的默认电网 $\text{ID}$。 | `1` |
|
||||||
|
| | `zone_id` | 项目所操作的默认区域 $\text{ID}$。 | `1` |
|
||||||
|
| | `station_id` | 项目所操作的默认变电站 $\text{ID}$。 | `1` |
|
||||||
|
| **Service Config** | `service_name` | 服务名称,用于日志、监控等标识。 | `"modelRT"` |
|
||||||
|
| | `secret_key` | 服务内部使用的秘钥,用于签名或认证。 | `"modelrt_key"` |
|
||||||
|
| **DataRT API** | `host` | 外部 $\text{DataRT}$ 服务的主机地址。 | `"http://127.0.0.1"` |
|
||||||
|
| | `port` | $\text{DataRT}$ 服务的端口号。 | `8888` |
|
||||||
|
| | `polling_api` | 轮询数据的 $\text{API}$ 路径。 | `"datart/getPointData"` |
|
||||||
|
| | `polling_api_method` | 调用该 $\text{API}$ 使用的 $\text{HTTP}$ 方法。 | `"GET"` |
|
||||||
|
|
||||||
|
#### 3.2 编译 ModelRT 服务
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build -o model-rt main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3 启动服务
|
||||||
|
|
||||||
|
使用编译好的二进制文件进行启动
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./model-rt
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.4 检测服务启动日志
|
||||||
|
|
||||||
|
在发现控制台输出如下信息`starting ModelRT server`
|
||||||
|
后即代表服务启动成功
|
||||||
|
|
||||||
|
### 4\. 后续操作(停止与清理)
|
||||||
|
|
||||||
|
#### 4.1 停止容器
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker stop postgres redis
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.2 删除容器(删除后数据将丢失)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker rm postgres redis
|
||||||
|
```
|
||||||
21
main.go
21
main.go
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -40,7 +41,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
modelRTConfigDir = flag.String("modelRT_config_dir", "./config", "config file dir of model runtime service")
|
modelRTConfigDir = flag.String("modelRT_config_dir", "./configs", "config file dir of model runtime service")
|
||||||
modelRTConfigName = flag.String("modelRT_config_name", "config", "config file name of model runtime service")
|
modelRTConfigName = flag.String("modelRT_config_name", "config", "config file name of model runtime service")
|
||||||
modelRTConfigType = flag.String("modelRT_config_type", "yaml", "config file type of model runtime service")
|
modelRTConfigType = flag.String("modelRT_config_type", "yaml", "config file type of model runtime service")
|
||||||
)
|
)
|
||||||
|
|
@ -59,6 +60,22 @@ func main() {
|
||||||
// init logger
|
// init logger
|
||||||
logger.InitLoggerInstance(modelRTConfig.LoggerConfig)
|
logger.InitLoggerInstance(modelRTConfig.LoggerConfig)
|
||||||
|
|
||||||
|
configPath := filepath.Join(*modelRTConfigDir, *modelRTConfigName+"."+*modelRTConfigType)
|
||||||
|
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
||||||
|
logger.Info(ctx, "configuration file not found,checking for example file")
|
||||||
|
|
||||||
|
exampleConfigPath := filepath.Join(*modelRTConfigDir, *modelRTConfigName+".example."+*modelRTConfigType)
|
||||||
|
if _, err := os.Stat(exampleConfigPath); err == nil {
|
||||||
|
if err := util.CopyFile(exampleConfigPath, configPath); err != nil {
|
||||||
|
logger.Error(ctx, "failed to copy example config file", "error", err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
logger.Info(ctx, "successfully copied example config to actual config file")
|
||||||
|
} else {
|
||||||
|
logger.Error(ctx, "No config file and no config example file found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
modelRTConfig = config.ReadAndInitConfig(*modelRTConfigDir, *modelRTConfigName, *modelRTConfigType)
|
modelRTConfig = config.ReadAndInitConfig(*modelRTConfigDir, *modelRTConfigName, *modelRTConfigType)
|
||||||
|
|
||||||
hostName, err := os.Hostname()
|
hostName, err := os.Hostname()
|
||||||
|
|
@ -196,7 +213,7 @@ func main() {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
logger.Info(ctx, "Starting ModelRT server...")
|
logger.Info(ctx, "starting ModelRT server")
|
||||||
err = server.ListenAndServe()
|
err = server.ListenAndServe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == http.ErrServerClosed {
|
if err == http.ErrServerClosed {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Package util provide some utility functions
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CopyFile define func of copies a file from src to dst.
|
||||||
|
// If the destination file exists, it will be overwritten.
|
||||||
|
func CopyFile(src, dst string) error {
|
||||||
|
sourceFile, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to open source file %s: %w", src, err)
|
||||||
|
}
|
||||||
|
defer sourceFile.Close()
|
||||||
|
|
||||||
|
destFile, err := os.Create(dst)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create destination file %s: %w", dst, err)
|
||||||
|
}
|
||||||
|
defer destFile.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(destFile, sourceFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to copy file contents from %s to %s: %w", src, dst, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = destFile.Sync()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to sync destination file %s: %w", dst, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue