2025-10-17 17:10:10 +08:00
|
|
|
|
# 项目依赖服务部署指南
|
|
|
|
|
|
|
|
|
|
|
|
本项目依赖于 $\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
|
|
|
|
|
|
```
|
|
|
|
|
|
|
feat: add dedicated message-exchange for task lifecycle notifications
- add constants/message.go with MessageTask* categories and message-exchange /
message-queue / dead-letter routing constants
- add mq/publish_message.go with PushMessageToRabbitMQ (confirm mode,
dead-letter queue) separate from the existing event-exchange publisher
- add mq/emit.go with TryEmitMessage for non-blocking, OTel-traced dispatch
- add mq/event/task_event_gen.go with NewTaskSubmitted/Running/Completed/
Failed/CancelledMessage constructors
- wire TryEmitMessage into task worker and create/cancel handlers so all 5
lifecycle transitions are published (previously task.* routed to
event-exchange with no matching binding, causing silent drops)
- harden Dockerfile: scratch final image, pinned alpine:3.21 certs stage,
apk upgrade in builder, add -trimpath -mod=readonly go build flags
- add full K8s manifests under deploy/k8s/ for Redis, RabbitMQ (mTLS),
ModelRT (Downward API, scratch image, readOnlyRootFilesystem), Jaeger,
Loki, Promtail, Grafana
- expand deploy.md with async_task SQL schema, TLS cert generation steps,
K8s deployment procedures, and SSH tunnel configuration
2026-05-13 16:58:36 +08:00
|
|
|
|
#### 1.4 初始化异步任务表
|
|
|
|
|
|
|
|
|
|
|
|
$\text{PostgreSQL}$ 启动后执行以下建表语句,创建异步任务系统所需的两张表:
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
-- ==========================================
|
|
|
|
|
|
-- 表: async_task
|
|
|
|
|
|
-- 说明: 存储异步任务的生命周期跟踪信息
|
|
|
|
|
|
-- ==========================================
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS async_task (
|
|
|
|
|
|
task_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
|
|
task_type VARCHAR(50) NOT NULL,
|
|
|
|
|
|
status VARCHAR(20) NOT NULL,
|
|
|
|
|
|
params JSONB,
|
|
|
|
|
|
created_at BIGINT NOT NULL,
|
|
|
|
|
|
finished_at BIGINT,
|
|
|
|
|
|
started_at BIGINT,
|
|
|
|
|
|
execution_time BIGINT,
|
|
|
|
|
|
progress INTEGER,
|
|
|
|
|
|
retry_count INTEGER DEFAULT 0,
|
|
|
|
|
|
max_retry_count INTEGER DEFAULT 3,
|
|
|
|
|
|
next_retry_time BIGINT,
|
|
|
|
|
|
retry_delay INTEGER DEFAULT 5000,
|
|
|
|
|
|
priority INTEGER DEFAULT 5,
|
|
|
|
|
|
queue_name VARCHAR(100) DEFAULT 'default',
|
|
|
|
|
|
worker_id VARCHAR(50),
|
|
|
|
|
|
failure_reason TEXT,
|
|
|
|
|
|
stack_trace TEXT,
|
|
|
|
|
|
created_by VARCHAR(100)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_async_task_task_type ON async_task(task_type);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_async_task_status ON async_task(status);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_async_task_created_at ON async_task(created_at);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_async_task_finished_at ON async_task(finished_at);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_async_task_started_at ON async_task(started_at);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_async_task_next_retry_time ON async_task(next_retry_time);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_async_task_priority ON async_task(priority);
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_async_task_status_retry ON async_task(status, next_retry_time)
|
|
|
|
|
|
WHERE status = 'FAILED' AND next_retry_time IS NOT NULL;
|
|
|
|
|
|
|
|
|
|
|
|
-- ==========================================
|
|
|
|
|
|
-- 表: async_task_result
|
|
|
|
|
|
-- 说明: 存储异步任务的执行结果
|
|
|
|
|
|
-- ==========================================
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS async_task_result (
|
|
|
|
|
|
task_id UUID PRIMARY KEY,
|
|
|
|
|
|
result JSONB,
|
|
|
|
|
|
error_code INTEGER,
|
|
|
|
|
|
error_message TEXT,
|
|
|
|
|
|
error_detail JSONB,
|
|
|
|
|
|
execution_time BIGINT NOT NULL DEFAULT 0,
|
|
|
|
|
|
memory_usage BIGINT,
|
|
|
|
|
|
cpu_usage DOUBLE PRECISION,
|
|
|
|
|
|
retry_count INTEGER DEFAULT 0,
|
|
|
|
|
|
completed_at BIGINT NOT NULL
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
COMMENT ON TABLE async_task IS '异步任务生命周期跟踪表';
|
|
|
|
|
|
COMMENT ON TABLE async_task_result IS '异步任务执行结果表';
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2025-10-17 17:10:10 +08:00
|
|
|
|
### 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
|
2025-12-11 16:42:25 +08:00
|
|
|
|
insert into public.grid(id,tagname,name,description,op,ts) VALUES (1, 'grid1', '网格1', '测试网格1', -1,CURRENT_TIMESTAMP);
|
|
|
|
|
|
|
|
|
|
|
|
insert into public.zone(id,grid_id,tagname,name,description,op,ts) VALUES (1, 1,'zone1', '区域1_1', '测试区域1_1', -1,CURRENT_TIMESTAMP);
|
|
|
|
|
|
|
2026-01-04 17:12:00 +08:00
|
|
|
|
insert into public.station(id,zone_id,tagname,name,description,is_local,op,ts) VALUES (1, 1,'station1', '站1_1_1', '测试站1_1_1', true, -1,CURRENT_TIMESTAMP),
|
|
|
|
|
|
(2, 1, 'station2', '站1_1_2', '测试站1_1_2', false, -1, CURRENT_TIMESTAMP);
|
2025-12-11 16:42:25 +08:00
|
|
|
|
|
2025-11-19 17:44:45 +08:00
|
|
|
|
INSERT INTO public.topologic(flag, uuid_from, uuid_to, context, description, op, ts)
|
|
|
|
|
|
VALUES
|
|
|
|
|
|
(1, '00000000-0000-0000-0000-000000000000', '70c190f2-8a60-42a9-b143-ec5f87e0aa6b', '{}', '', 1, CURRENT_TIMESTAMP),
|
|
|
|
|
|
(1, '70c190f2-8a60-42a9-b143-ec5f87e0aa6b', '10f155cf-bd27-4557-85b2-d126b6e2657f', '{}', '', 1, CURRENT_TIMESTAMP),
|
|
|
|
|
|
(1, '70c190f2-8a60-42a9-b143-ec5f87e0aa6b', 'e32bc0be-67f4-4d79-a5da-eaa40a5bd77d', '{}', '', 1, CURRENT_TIMESTAMP),
|
|
|
|
|
|
(1, '70c190f2-8a60-42a9-b143-ec5f87e0aa6b', '70c190f2-8a75-42a9-b166-ec5f87e0aa6b', '{}', '', 1, CURRENT_TIMESTAMP),
|
|
|
|
|
|
(1, 'e32bc0be-67f4-4d79-a5da-eaa40a5bd77d', '70c200f2-8a75-42a9-c166-bf5f87e0aa6b', '{}', '', 1, CURRENT_TIMESTAMP),
|
|
|
|
|
|
(1, 'e32bc0be-67f4-4d79-a5da-eaa40a5bd77d', '968dd6e6-faec-4f78-b58a-d6e68426b09e', '{}', '', 1, CURRENT_TIMESTAMP),
|
|
|
|
|
|
(1, 'e32bc0be-67f4-4d79-a5da-eaa40a5bd77d', '968dd6e6-faec-4f78-b58a-d6e68426b08e', '{}', '', 1, CURRENT_TIMESTAMP);
|
|
|
|
|
|
|
|
|
|
|
|
INSERT INTO public.bay (bay_uuid, name, tag, type, unom, fla, capacity, description, in_service, state, grid, zone, station, business, context, from_uuids, to_uuids, dev_protect, dev_fault_record, dev_status, dev_dyn_sense, dev_instruct, dev_etc, components, op, ts)
|
|
|
|
|
|
VALUES (
|
|
|
|
|
|
'18e71a24-694a-43fa-93a7-c4d02a27d1bc',
|
|
|
|
|
|
'', '', '',
|
|
|
|
|
|
-1, -1, -1,
|
|
|
|
|
|
'',
|
|
|
|
|
|
false,
|
|
|
|
|
|
-1,
|
|
|
|
|
|
'', '', '',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'[]',
|
|
|
|
|
|
'[]',
|
|
|
|
|
|
'[]',
|
|
|
|
|
|
'[]',
|
|
|
|
|
|
'[]',
|
|
|
|
|
|
'[]',
|
|
|
|
|
|
'[]',
|
|
|
|
|
|
'[]',
|
|
|
|
|
|
ARRAY['968dd6e6-faec-4f78-b58a-d6e68426b09e', '968dd6e6-faec-4f78-b58a-d6e68426b08e']::uuid[],
|
|
|
|
|
|
-1,
|
|
|
|
|
|
CURRENT_TIMESTAMP
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2025-12-31 16:24:27 +08:00
|
|
|
|
INSERT INTO public.component (global_uuid, nspath, tag, name, model_name, description, grid, zone, station, station_id, type, in_service, state, status, connection, label, context, op, ts)
|
2025-11-19 17:44:45 +08:00
|
|
|
|
VALUES
|
|
|
|
|
|
(
|
|
|
|
|
|
'968dd6e6-faec-4f78-b58a-d6e68426b09e',
|
2026-01-14 17:32:01 +08:00
|
|
|
|
'ns1', 'tag1', 'component1', 'bus_1', '',
|
2025-12-31 16:24:27 +08:00
|
|
|
|
'grid1', 'zone1', 'station1', 1,
|
2025-11-19 17:44:45 +08:00
|
|
|
|
-1,
|
2026-04-28 17:41:28 +08:00
|
|
|
|
true,
|
2025-11-19 17:44:45 +08:00
|
|
|
|
-1, -1,
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
-1,
|
|
|
|
|
|
CURRENT_TIMESTAMP
|
|
|
|
|
|
),
|
|
|
|
|
|
(
|
|
|
|
|
|
'968dd6e6-faec-4f78-b58a-d6e68426b08e',
|
2026-01-14 17:32:01 +08:00
|
|
|
|
'ns2', 'tag2', 'component2', 'bus_1', '',
|
2025-12-31 16:24:27 +08:00
|
|
|
|
'grid1', 'zone1', 'station1', 1,
|
|
|
|
|
|
-1,
|
2026-04-28 17:41:28 +08:00
|
|
|
|
true,
|
2025-12-31 16:24:27 +08:00
|
|
|
|
-1, -1,
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
-1,
|
|
|
|
|
|
CURRENT_TIMESTAMP
|
|
|
|
|
|
),
|
|
|
|
|
|
(
|
|
|
|
|
|
'968dd6e6-faec-4f78-b58a-d6e88426b09e',
|
2026-01-14 17:32:01 +08:00
|
|
|
|
'ns3', 'tag3', 'component3', 'bus_1', '',
|
2025-12-31 16:24:27 +08:00
|
|
|
|
'grid1', 'zone1', 'station2', 2,
|
2025-11-19 17:44:45 +08:00
|
|
|
|
-1,
|
2026-04-28 17:41:28 +08:00
|
|
|
|
true,
|
2025-11-19 17:44:45 +08:00
|
|
|
|
-1, -1,
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
-1,
|
|
|
|
|
|
CURRENT_TIMESTAMP
|
2026-04-28 17:41:28 +08:00
|
|
|
|
),
|
|
|
|
|
|
(
|
|
|
|
|
|
'70c190f2-8a60-42a9-b143-ec5f87e0aa6b',
|
|
|
|
|
|
'ns4', 'tag4', 'component4', 'bus_1', '',
|
|
|
|
|
|
'grid1', 'zone1', 'station1', 1,
|
|
|
|
|
|
-1,
|
|
|
|
|
|
true,
|
|
|
|
|
|
-1, -1,
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
-1,
|
|
|
|
|
|
CURRENT_TIMESTAMP
|
|
|
|
|
|
),
|
|
|
|
|
|
(
|
|
|
|
|
|
'10f155cf-bd27-4557-85b2-d126b6e2657f',
|
|
|
|
|
|
'ns5', 'tag5', 'component5', 'bus_1', '',
|
|
|
|
|
|
'grid1', 'zone1', 'station1', 1,
|
|
|
|
|
|
-1,
|
|
|
|
|
|
true,
|
|
|
|
|
|
-1, -1,
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
-1,
|
|
|
|
|
|
CURRENT_TIMESTAMP
|
|
|
|
|
|
),
|
|
|
|
|
|
(
|
|
|
|
|
|
'e32bc0be-67f4-4d79-a5da-eaa40a5bd77d',
|
|
|
|
|
|
'ns6', 'tag6', 'component6', 'bus_1', '',
|
|
|
|
|
|
'grid1', 'zone1', 'station1', 1,
|
|
|
|
|
|
-1,
|
|
|
|
|
|
true,
|
|
|
|
|
|
-1, -1,
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
-1,
|
|
|
|
|
|
CURRENT_TIMESTAMP
|
|
|
|
|
|
),
|
|
|
|
|
|
(
|
|
|
|
|
|
'70c190f2-8a75-42a9-b166-ec5f87e0aa6b',
|
|
|
|
|
|
'ns7', 'tag7', 'component7', 'bus_1', '',
|
|
|
|
|
|
'grid1', 'zone1', 'station1', 1,
|
|
|
|
|
|
-1,
|
|
|
|
|
|
true,
|
|
|
|
|
|
-1, -1,
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
-1,
|
|
|
|
|
|
CURRENT_TIMESTAMP
|
|
|
|
|
|
),
|
|
|
|
|
|
(
|
|
|
|
|
|
'70c200f2-8a75-42a9-c166-bf5f87e0aa6b',
|
|
|
|
|
|
'ns8', 'tag8', 'component8', 'bus_1', '',
|
|
|
|
|
|
'grid1', 'zone1', 'station1', 1,
|
|
|
|
|
|
-1,
|
|
|
|
|
|
true,
|
|
|
|
|
|
-1, -1,
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
'{}',
|
|
|
|
|
|
-1,
|
|
|
|
|
|
CURRENT_TIMESTAMP
|
2025-11-19 17:44:45 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
2025-12-11 16:42:25 +08:00
|
|
|
|
INSERT INTO public.measurement (id, tag, name, type, size, data_source, event_plan, bay_uuid, component_uuid, op, ts)
|
|
|
|
|
|
VALUES
|
|
|
|
|
|
(3, 'I11_C_rms', '45母甲侧互连电流C相1', -1, 200, '{"type": 1, "io_address": {"device": "ssu001", "channel": "TM1", "station": "001"}}', '{"cause": {"up": 55.0, "down": 45.0}, "action": {"command": "warning", "parameters": ["I段母线甲侧互连电流C相1"]}, "enable": true}', '18e71a24-694a-43fa-93a7-c4d02a27d1bc', '968dd6e6-faec-4f78-b58a-d6e68426b09e', -1, CURRENT_TIMESTAMP),
|
|
|
|
|
|
(4, 'I11_B_rms', '45母甲侧互连电流B相1', -1, 300, '{"type": 1, "io_address": {"device": "ssu001", "channel": "TM2", "station": "001"}}', '{"cause": {"upup": 65, "downdown": 35}, "action": {"command": "warning", "parameters": ["I段母线甲侧互连电流B相1"]}, "enable": true}', '18e71a24-694a-43fa-93a7-c4d02a27d1bc', '968dd6e6-faec-4f78-b58a-d6e68426b09e', -1, CURRENT_TIMESTAMP),
|
|
|
|
|
|
(5, 'I11_A_rms', '45母甲侧互连电流A相1', -1, 300, '{"type": 1, "io_address": {"device": "ssu001", "channel": "TM3", "station": "001"}}', '{"cause": {"up": 55, "down": 45, "upup": 65, "downdown": 35}, "action": {"command": "warning", "parameters": ["I段母线甲侧互连电流A相1"]}, "enable": true}', '18e71a24-694a-43fa-93a7-c4d02a27d1bc', '968dd6e6-faec-4f78-b58a-d6e68426b09e', -1, CURRENT_TIMESTAMP);
|
2025-12-22 17:38:15 +08:00
|
|
|
|
|
|
|
|
|
|
INSERT INTO public.project_manager (id, name, tag, meta_model, group_name, link_type, check_state, is_public, op, ts
|
|
|
|
|
|
) VALUES
|
|
|
|
|
|
(1, 'component', 'component', '', 'component', 0,
|
|
|
|
|
|
'{"checkState": [{"name": "global_uuid", "type": "UUID", "checked": 1, "isVisible": 1, "defaultValue": "", "lengthPrecision": -1}, {"name": "nspath", "type": "VARCHAR(32)", "checked": 1, "isVisible": 1, "defaultValue": "", "lengthPrecision": 32}, {"name": "tag", "type": "VARCHAR(32)", "checked": 1, "isVisible": 1, "defaultValue": "null", "lengthPrecision": 32}, {"name": "name", "type": "VARCHAR(64)", "checked": 1, "isVisible": 1, "defaultValue": "null", "lengthPrecision": 64}, {"name": "description", "type": "VARCHAR(512)", "checked": 1, "isVisible": 1, "defaultValue": "", "lengthPrecision": 512}, {"name": "station", "type": "VARCHAR(64)", "checked": 1, "isVisible": 1, "defaultValue": "null", "lengthPrecision": 64}, {"name": "zone", "type": "VARCHAR(64)", "checked": 1, "isVisible": 1, "defaultValue": "null", "lengthPrecision": 64}, {"name": "grid", "type": "VARCHAR(64)", "checked": 1, "isVisible": 1, "defaultValue": "null", "lengthPrecision": 64}, {"name": "type", "type": "INTEGER", "checked": 1, "isVisible": 0, "defaultValue": "0", "lengthPrecision": -1}, {"name": "in_service", "type": "SMALLINT", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "state", "type": "INTEGER", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "connection", "type": "JSONB", "checked": 1, "isVisible": 1, "defaultValue": "{}", "lengthPrecision": -1}, {"name": "label", "type": "JSONB", "checked": 1, "isVisible": 1, "defaultValue": "{}", "lengthPrecision": -1}, {"name": "context", "type": "JSONB", "checked": 1, "isVisible": 0, "defaultValue": "{}", "lengthPrecision": -1}, {"name": "op", "type": "INTEGER", "checked": 1, "isVisible": 0, "defaultValue": "-1", "lengthPrecision": -1}, {"name": "ts", "type": "TIMESTAMP", "checked": 1, "isVisible": 0, "defaultValue": "null", "lengthPrecision": -1}, {"name": "model_name", "type": "VARCHAR(64)", "checked": 1, "isVisible": 0, "defaultValue": "null", "lengthPrecision": 64}, {"name": "status", "type": "SMALLINT", "checked": 1, "isVisible": 0, "defaultValue": "null", "lengthPrecision": -1}]}', TRUE, -1, CURRENT_TIMESTAMP
|
|
|
|
|
|
),
|
|
|
|
|
|
(2, 'bus_bus_1_base_extend', 'bus_1', 'bus', 'base_extend', 0,
|
|
|
|
|
|
'{"checkState": [{"name": "bus_num", "type": "INTEGER", "checked": 1, "isVisible": 0, "defaultValue": "1", "lengthPrecision": -1}, {"name": "unom_kv", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "null", "lengthPrecision": -1}]}', FALSE, -1, CURRENT_TIMESTAMP
|
|
|
|
|
|
),
|
|
|
|
|
|
(3, 'bus_bus_1_model', 'bus_1', 'bus', 'model', 0,
|
|
|
|
|
|
'{"checkState": [{"name": "ui_percent", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "100", "lengthPrecision": -1}, {"name": "ui_kv", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "35", "lengthPrecision": -1}, {"name": "ui_pa", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "stability_rated_current", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "1000", "lengthPrecision": -1}, {"name": "stability_dynamic_steady_current", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "40", "lengthPrecision": -1}, {"name": "load_adjustment_min", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "100", "lengthPrecision": -1}, {"name": "load_adjustment_max", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "100", "lengthPrecision": -1}, {"name": "bus_type", "type": "VARCHAR(10)", "checked": 1, "isVisible": 1, "defaultValue": "PQ母线", "lengthPrecision": 10}, {"name": "csc_s3_max", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "csc_s3_min", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "csc_i3_max", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "csc_i3_min", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "csc_z3s_max", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0.05", "lengthPrecision": -1}, {"name": "csc_z3s_min", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0.1", "lengthPrecision": -1}, {"name": "csc_s1_max", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "csc_s1_min", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "csc_i1_max", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "csc_i1_min", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "csc_z1s_max", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0.05", "lengthPrecision": -1}, {"name": "csc_z1s_min", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0.1", "lengthPrecision": -1}, {"name": "csc_base_voltage", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "37", "lengthPrecision": -1}, {"name": "csc_base_capacity", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "100", "lengthPrecision": -1}]}', FALSE, -1, CURRENT_TIMESTAMP
|
|
|
|
|
|
),
|
|
|
|
|
|
(4, 'bus_bus_1_stable', 'bus_1', 'bus', 'stable', 0,
|
|
|
|
|
|
'{"checkState": [{"name": "uvpw_threshold_percent", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "95", "lengthPrecision": -1}, {"name": "uvpw_runtime", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "10", "lengthPrecision": -1}, {"name": "uvw_threshold_percent", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "90", "lengthPrecision": -1}, {"name": "uvw_runtime", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "10", "lengthPrecision": -1}, {"name": "ovpw_threshold_percent", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "105", "lengthPrecision": -1}, {"name": "ovpw_runtime", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "60", "lengthPrecision": -1}, {"name": "ovw_threshold_percent", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "110", "lengthPrecision": -1}, {"name": "ovw_runtime", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "10", "lengthPrecision": -1}, {"name": "umargin_pmax", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "umargin_qmax", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "0", "lengthPrecision": -1}, {"name": "umargin_ulim", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "90", "lengthPrecision": -1}, {"name": "umargin_plim_percent", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "15", "lengthPrecision": -1}, {"name": "umargin_qlim_percent", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "15", "lengthPrecision": -1}, {"name": "umargin_ulim_percent", "type": "DOUBLE PRECISION", "checked": 1, "isVisible": 1, "defaultValue": "15", "lengthPrecision": -1}]}', FALSE, -1, CURRENT_TIMESTAMP);
|
|
|
|
|
|
|
|
|
|
|
|
INSERT INTO public.bus_bus_1_stable (id, global_uuid, attribute_group, uvpw_threshold_percent, uvpw_runtime, uvw_threshold_percent, uvw_runtime, ovpw_threshold_percent, ovpw_runtime, ovw_threshold_percent, ovw_runtime,
|
|
|
|
|
|
umargin_pmax, umargin_qmax, umargin_ulim, umargin_plim_percent, umargin_qlim_percent, umargin_ulim_percent
|
|
|
|
|
|
) VALUES (
|
|
|
|
|
|
1,
|
2025-12-23 14:52:39 +08:00
|
|
|
|
'968dd6e6-faec-4f78-b58a-d6e68426b08e',
|
2025-12-22 17:38:15 +08:00
|
|
|
|
'stable',
|
|
|
|
|
|
95,
|
|
|
|
|
|
10,
|
|
|
|
|
|
90,
|
|
|
|
|
|
10,
|
|
|
|
|
|
105,
|
|
|
|
|
|
60,
|
|
|
|
|
|
110,
|
|
|
|
|
|
10,
|
|
|
|
|
|
0,
|
|
|
|
|
|
0,
|
|
|
|
|
|
90,
|
|
|
|
|
|
15,
|
|
|
|
|
|
15,
|
|
|
|
|
|
15
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
INSERT INTO public.bus_bus_1_model (id, global_uuid, attribute_group,
|
|
|
|
|
|
ui_percent, ui_kv, ui_pa, stability_rated_current, stability_dynamic_steady_current, load_adjustment_min, load_adjustment_max, bus_type, csc_s3_max, csc_s3_min, csc_i3_max, csc_i3_min, csc_z3s_max, csc_z3s_min, csc_s1_max, csc_s1_min, csc_i1_max, csc_i1_min, csc_z1s_max, csc_z1s_min, csc_base_voltage, csc_base_capacity
|
|
|
|
|
|
) VALUES (
|
|
|
|
|
|
1,
|
2025-12-23 14:52:39 +08:00
|
|
|
|
'968dd6e6-faec-4f78-b58a-d6e68426b08e',
|
2025-12-22 17:38:15 +08:00
|
|
|
|
'model',
|
|
|
|
|
|
100,
|
|
|
|
|
|
35,
|
|
|
|
|
|
0,
|
|
|
|
|
|
1000,
|
|
|
|
|
|
40,
|
|
|
|
|
|
100,
|
|
|
|
|
|
100,
|
|
|
|
|
|
'PQ母线',
|
|
|
|
|
|
0,
|
|
|
|
|
|
0,
|
|
|
|
|
|
0,
|
|
|
|
|
|
0,
|
|
|
|
|
|
0.05,
|
|
|
|
|
|
0.1,
|
|
|
|
|
|
0,
|
|
|
|
|
|
0,
|
|
|
|
|
|
0,
|
|
|
|
|
|
0,
|
|
|
|
|
|
0.05,
|
|
|
|
|
|
0.1,
|
|
|
|
|
|
37,
|
|
|
|
|
|
100
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
INSERT INTO public.bus_bus_1_base_extend (id, global_uuid, attribute_group,
|
|
|
|
|
|
bus_num, unom_kv
|
|
|
|
|
|
) VALUES (
|
|
|
|
|
|
1,
|
2025-12-23 14:52:39 +08:00
|
|
|
|
'968dd6e6-faec-4f78-b58a-d6e68426b08e',
|
2025-12-22 17:38:15 +08:00
|
|
|
|
'base_extend',
|
|
|
|
|
|
1,
|
|
|
|
|
|
NULL
|
|
|
|
|
|
);
|
2025-10-17 17:10:10 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
##### 2.4.2 Redis数据注入
|
|
|
|
|
|
|
|
|
|
|
|
Redis数据脚本
|
|
|
|
|
|
|
2025-12-05 16:36:11 +08:00
|
|
|
|
```shell
|
|
|
|
|
|
deploy/redis-test-data/measurments-recommend/measurement_injection.go
|
2025-10-17 17:10:10 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2025-12-05 16:36:11 +08:00
|
|
|
|
运行脚本向 Reids 导入数据
|
2025-10-17 17:10:10 +08:00
|
|
|
|
|
2025-12-05 16:36:11 +08:00
|
|
|
|
```shell
|
|
|
|
|
|
go run deploy/redis-test-data/measurments-recommend/measurement_injection.go
|
|
|
|
|
|
```
|
2025-10-17 17:10:10 +08:00
|
|
|
|
|
|
|
|
|
|
### 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`
|
|
|
|
|
|
后即代表服务启动成功
|
|
|
|
|
|
|
feat: add dedicated message-exchange for task lifecycle notifications
- add constants/message.go with MessageTask* categories and message-exchange /
message-queue / dead-letter routing constants
- add mq/publish_message.go with PushMessageToRabbitMQ (confirm mode,
dead-letter queue) separate from the existing event-exchange publisher
- add mq/emit.go with TryEmitMessage for non-blocking, OTel-traced dispatch
- add mq/event/task_event_gen.go with NewTaskSubmitted/Running/Completed/
Failed/CancelledMessage constructors
- wire TryEmitMessage into task worker and create/cancel handlers so all 5
lifecycle transitions are published (previously task.* routed to
event-exchange with no matching binding, causing silent drops)
- harden Dockerfile: scratch final image, pinned alpine:3.21 certs stage,
apk upgrade in builder, add -trimpath -mod=readonly go build flags
- add full K8s manifests under deploy/k8s/ for Redis, RabbitMQ (mTLS),
ModelRT (Downward API, scratch image, readOnlyRootFilesystem), Jaeger,
Loki, Promtail, Grafana
- expand deploy.md with async_task SQL schema, TLS cert generation steps,
K8s deployment procedures, and SSH tunnel configuration
2026-05-13 16:58:36 +08:00
|
|
|
|
### 4\. 部署基础依赖(Kubernetes)
|
|
|
|
|
|
|
|
|
|
|
|
Redis 和 RabbitMQ 部署在 Minikube 中,YAML 文件位于 `deploy/k8s/`。RabbitMQ 启用双向 TLS(mTLS),客户端以 X.509 证书的 CN 字段作为用户名进行认证。
|
|
|
|
|
|
|
|
|
|
|
|
#### 4.1 部署 Redis
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl apply -f deploy/k8s/redis-deployment.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/redis-service.yaml
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
| 参数 | 值 | 说明 |
|
|
|
|
|
|
| :--- | :--- | :--- |
|
|
|
|
|
|
| **镜像** | `redis/redis-stack-server:latest` | 内置 Redisearch 模块 |
|
|
|
|
|
|
| **NodePort** | `30001` | 集群外访问端口 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 4.2 RabbitMQ TLS 证书生成
|
|
|
|
|
|
|
|
|
|
|
|
RabbitMQ 配置为仅允许 TLS 连接(`listeners.tcp = none`),所有客户端须持有由同一 CA 签发的证书。
|
|
|
|
|
|
|
|
|
|
|
|
##### 4.2.1 生成根 CA
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 克隆 tls-gen 工具
|
|
|
|
|
|
git clone https://github.com/rabbitmq/tls-gen.git
|
|
|
|
|
|
cd tls-gen/basic
|
|
|
|
|
|
|
|
|
|
|
|
# 生成根 CA(结果在 result/ 目录)
|
|
|
|
|
|
make CN=rabbitmq-server
|
|
|
|
|
|
# ca_certificate.pem 和 ca_key.pem 生成于 result/
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
##### 4.2.2 生成服务器证书
|
|
|
|
|
|
|
|
|
|
|
|
服务器证书需包含 SAN(Subject Alternative Name),使其同时匹配集群内 DNS 和 Minikube IP。
|
|
|
|
|
|
|
|
|
|
|
|
创建 `server.cnf`:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
[req]
|
|
|
|
|
|
distinguished_name = req_distinguished_name
|
|
|
|
|
|
prompt = no
|
|
|
|
|
|
|
|
|
|
|
|
[req_distinguished_name]
|
|
|
|
|
|
C = CN
|
|
|
|
|
|
ST = Beijing
|
|
|
|
|
|
L = Beijing
|
|
|
|
|
|
O = coslight
|
|
|
|
|
|
CN = rabbitmq-server
|
|
|
|
|
|
|
|
|
|
|
|
[v3_server]
|
|
|
|
|
|
keyUsage = critical, digitalSignature, keyEncipherment
|
|
|
|
|
|
extendedKeyUsage = serverAuth, clientAuth
|
|
|
|
|
|
subjectAltName = @alt_names
|
|
|
|
|
|
|
|
|
|
|
|
[alt_names]
|
|
|
|
|
|
DNS.1 = rabbitmq-server
|
|
|
|
|
|
DNS.2 = rabbitmq-service.default.svc.cluster.local
|
|
|
|
|
|
DNS.3 = localhost
|
|
|
|
|
|
IP.1 = 192.168.49.2
|
|
|
|
|
|
IP.2 = 127.0.0.1
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
生成证书:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 将 ca_certificate.pem 和 ca_key.pem(即 cakey.pem)放在当前目录
|
|
|
|
|
|
openssl genrsa -out server_key.pem 2048
|
|
|
|
|
|
|
|
|
|
|
|
openssl req -new -key server_key.pem -out server_cert.csr -config server.cnf
|
|
|
|
|
|
|
|
|
|
|
|
openssl x509 -req -in server_cert.csr \
|
|
|
|
|
|
-CA ca_certificate.pem -CAkey cakey.pem -CAcreateserial \
|
|
|
|
|
|
-out server_certificate.pem -days 730 -sha256 \
|
|
|
|
|
|
-extfile server.cnf -extensions v3_server
|
|
|
|
|
|
|
|
|
|
|
|
rm server_cert.csr
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
##### 4.2.3 生成 ModelRT 客户端证书
|
|
|
|
|
|
|
|
|
|
|
|
CN 必须与 RabbitMQ 中注册的用户名一致(`modelrt-client`)。
|
|
|
|
|
|
|
|
|
|
|
|
创建 `modelrt.cnf`:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
[req]
|
|
|
|
|
|
distinguished_name = req_distinguished_name
|
|
|
|
|
|
prompt = no
|
|
|
|
|
|
|
|
|
|
|
|
[req_distinguished_name]
|
|
|
|
|
|
C = CN
|
|
|
|
|
|
ST = Beijing
|
|
|
|
|
|
L = Beijing
|
|
|
|
|
|
O = coslight
|
|
|
|
|
|
CN = modelrt-client
|
|
|
|
|
|
|
|
|
|
|
|
[v3_client]
|
|
|
|
|
|
keyUsage = critical, digitalSignature, keyEncipherment
|
|
|
|
|
|
extendedKeyUsage = clientAuth
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
生成证书:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
openssl genrsa -out modelrt_client_key.pem 2048
|
|
|
|
|
|
|
|
|
|
|
|
openssl req -new -key modelrt_client_key.pem \
|
|
|
|
|
|
-out modelrt_client.csr -config modelrt.cnf
|
|
|
|
|
|
|
|
|
|
|
|
openssl x509 -req -in modelrt_client.csr \
|
|
|
|
|
|
-CA ca_certificate.pem -CAkey cakey.pem -CAcreateserial \
|
|
|
|
|
|
-out modelrt_client_cert.pem -days 365 \
|
|
|
|
|
|
-extensions v3_client -extfile modelrt.cnf
|
|
|
|
|
|
|
|
|
|
|
|
rm modelrt_client.csr
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
##### 4.2.4 生成 EventRT 客户端证书
|
|
|
|
|
|
|
|
|
|
|
|
创建 `eventrt.cnf`(CN 改为 `eventrt-client`):
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
[req]
|
|
|
|
|
|
distinguished_name = req_distinguished_name
|
|
|
|
|
|
prompt = no
|
|
|
|
|
|
|
|
|
|
|
|
[req_distinguished_name]
|
|
|
|
|
|
C = CN
|
|
|
|
|
|
ST = Beijing
|
|
|
|
|
|
L = Beijing
|
|
|
|
|
|
O = coslight
|
|
|
|
|
|
CN = eventrt-client
|
|
|
|
|
|
|
|
|
|
|
|
[v3_client]
|
|
|
|
|
|
keyUsage = critical, digitalSignature, keyEncipherment
|
|
|
|
|
|
extendedKeyUsage = clientAuth
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
生成证书:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
openssl genrsa -out eventrt_client_key.pem 2048
|
|
|
|
|
|
|
|
|
|
|
|
openssl req -new -key eventrt_client_key.pem \
|
|
|
|
|
|
-out eventrt_client.csr -config eventrt.cnf
|
|
|
|
|
|
|
|
|
|
|
|
openssl x509 -req -in eventrt_client.csr \
|
|
|
|
|
|
-CA ca_certificate.pem -CAkey cakey.pem -CAcreateserial \
|
|
|
|
|
|
-out eventrt_client_cert.pem -days 365 \
|
|
|
|
|
|
-extensions v3_client -extfile eventrt.cnf
|
|
|
|
|
|
|
|
|
|
|
|
rm eventrt_client.csr
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
##### 4.2.5 验证证书
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 验证服务器证书
|
|
|
|
|
|
openssl verify -CAfile ca_certificate.pem server_certificate.pem
|
|
|
|
|
|
|
|
|
|
|
|
# 验证客户端证书
|
|
|
|
|
|
openssl verify -CAfile ca_certificate.pem modelrt_client_cert.pem
|
|
|
|
|
|
openssl verify -CAfile ca_certificate.pem eventrt_client_cert.pem
|
|
|
|
|
|
|
|
|
|
|
|
# 查看证书详情(确认 CN 和 SAN)
|
|
|
|
|
|
openssl x509 -in server_certificate.pem -noout -subject -ext subjectAltName
|
|
|
|
|
|
openssl x509 -in modelrt_client_cert.pem -noout -subject
|
|
|
|
|
|
openssl x509 -in eventrt_client_cert.pem -noout -subject
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 4.3 部署 RabbitMQ
|
|
|
|
|
|
|
|
|
|
|
|
##### 4.3.1 创建证书 Secret
|
|
|
|
|
|
|
|
|
|
|
|
将服务器端三个证书文件打包为 K8s Secret(在证书文件所在目录执行):
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl create secret generic rabbitmq-certs \
|
|
|
|
|
|
--from-file=ca_certificate.pem=./ca_certificate.pem \
|
|
|
|
|
|
--from-file=server_certificate.pem=./server_certificate.pem \
|
|
|
|
|
|
--from-file=server_key.pem=./server_key.pem
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
##### 4.3.2 部署
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl apply -f deploy/k8s/rabbitmq-secret.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/rabbitmq-config.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/rabbitmq-users-config.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/rabbitmq-deployment.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/rabbitmq-service.yaml
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
##### 4.3.3 端口汇总
|
|
|
|
|
|
|
|
|
|
|
|
| 端口 | NodePort | 说明 |
|
|
|
|
|
|
| :--- | :--- | :--- |
|
|
|
|
|
|
| `5671` | `30671` | AMQP over TLS(客户端连接) |
|
|
|
|
|
|
| `5672` | `30672` | AMQP 明文(内部备用,生产禁用) |
|
|
|
|
|
|
| `15671` | `31671` | Management UI over TLS |
|
|
|
|
|
|
| `15672` | `31672` | Management UI 明文(内部备用) |
|
|
|
|
|
|
|
|
|
|
|
|
##### 4.3.4 用户与权限说明
|
|
|
|
|
|
|
|
|
|
|
|
用户定义在 `rabbitmq-users-config.yaml` 的 `definitions.json` 中,通过 `load_definitions` 启动时自动加载:
|
|
|
|
|
|
|
|
|
|
|
|
| 用户 | 认证方式 | 权限 | 说明 |
|
|
|
|
|
|
| :--- | :--- | :--- | :--- |
|
|
|
|
|
|
| `coslight` | 密码 | administrator | 管理员,密码在 rabbitmq-secret.yaml |
|
|
|
|
|
|
| `modelrt-client` | X.509 证书(CN) | configure/read/write | ModelRT 服务专用 |
|
|
|
|
|
|
| `eventrt-client` | X.509 证书(CN) | configure/read/write | EventRT 服务专用 |
|
|
|
|
|
|
| `web-client` | X.509 证书(CN) | read/write | Web 客户端 |
|
|
|
|
|
|
|
|
|
|
|
|
> **注意:** 证书认证用户的 `password_hash` 留空;RabbitMQ 通过 `ssl_cert_login_from = common_name` 将证书 CN 映射为用户名。
|
|
|
|
|
|
|
|
|
|
|
|
### 5\. 部署 ModelRT(Kubernetes)
|
|
|
|
|
|
|
|
|
|
|
|
所有资源部署在 `default` 命名空间,YAML 文件位于 `deploy/k8s/`。
|
|
|
|
|
|
|
|
|
|
|
|
#### 5.1 构建并推送镜像
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 在项目根目录执行
|
|
|
|
|
|
docker build -f deploy/dockerfile/modelrt.Dockerfile -t coslight/modelrt:latest .
|
|
|
|
|
|
|
|
|
|
|
|
# 推送到镜像仓库(或直接加载到 Minikube)
|
|
|
|
|
|
minikube image load coslight/modelrt:latest
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 5.2 创建客户端证书 Secret
|
|
|
|
|
|
|
|
|
|
|
|
在 RabbitMQ TLS 证书生成完成后(见 4.2),进入证书文件所在目录执行:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
sh deploy/k8s/modelrt-certs-secret.sh
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
该脚本等价于:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl create secret generic modelrt-certs \
|
|
|
|
|
|
--from-file=ca_certificate.pem=./ca_certificate.pem \
|
|
|
|
|
|
--from-file=modelrt_client_cert.pem=./modelrt_client_cert.pem \
|
|
|
|
|
|
--from-file=modelrt_client_key.pem=./modelrt_client_key.pem
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 5.3 部署
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl apply -f deploy/k8s/modelrt-secret.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/modelrt-configmap.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/modelrt-deployment.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/modelrt-service.yaml
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 5.4 配置说明
|
|
|
|
|
|
|
|
|
|
|
|
| 配置项 | 方式 | 说明 |
|
|
|
|
|
|
| :--- | :--- | :--- |
|
|
|
|
|
|
| `postgres.password` | Secret `modelrt-secret` | 不写入 ConfigMap |
|
|
|
|
|
|
| `service.secret_key` | Secret `modelrt-secret` | 不写入 ConfigMap |
|
|
|
|
|
|
| RabbitMQ 客户端证书 | Secret `modelrt-certs` | 挂载至 `/app/configs/certs/` |
|
|
|
|
|
|
| `config.yaml` 其余配置 | ConfigMap `modelrt-config` | 所有 host 已替换为 K8s service 名 |
|
|
|
|
|
|
| `K8S_NAMESPACE` / `K8S_NODE_NAME` | Downward API | 注入至日志全局字段 |
|
|
|
|
|
|
|
|
|
|
|
|
> **注意:** `modelrt-configmap.yaml` 中 `postgres.password` 和 `service.secret_key` 留空,实际值由容器启动时的环境变量 `POSTGRES_PASSWORD` / `SERVICE_SECRET_KEY` 注入,应用需读取这两个环境变量覆盖 config 中的空值。若应用当前仅读取文件配置,可直接将值填入 `modelrt-secret.yaml` 并在 ConfigMap 中引用,或在 ConfigMap 中直接填写。
|
|
|
|
|
|
|
|
|
|
|
|
#### 5.5 状态检查
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 查看 Pod 状态
|
|
|
|
|
|
kubectl get pods -l app=modelrt
|
|
|
|
|
|
|
|
|
|
|
|
# 查看启动日志
|
|
|
|
|
|
kubectl logs -l app=modelrt --tail=50
|
|
|
|
|
|
|
|
|
|
|
|
# 查看 Service
|
|
|
|
|
|
kubectl get svc modelrt-service
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 5.6 端口汇总
|
|
|
|
|
|
|
|
|
|
|
|
| NodePort | 说明 |
|
|
|
|
|
|
| :--- | :--- |
|
|
|
|
|
|
| `30080` | ModelRT HTTP API,SSH 隧道本地端口 `8080` |
|
|
|
|
|
|
|
|
|
|
|
|
#### 5.7 清理
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl delete -f deploy/k8s/modelrt-service.yaml \
|
|
|
|
|
|
-f deploy/k8s/modelrt-deployment.yaml \
|
|
|
|
|
|
-f deploy/k8s/modelrt-configmap.yaml \
|
|
|
|
|
|
-f deploy/k8s/modelrt-secret.yaml
|
|
|
|
|
|
kubectl delete secret modelrt-certs
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 6\. 部署可观测性栈(Kubernetes)
|
|
|
|
|
|
|
|
|
|
|
|
在 $\text{Kubernetes}$ 集群中部署 $\text{Jaeger}$(链路追踪)+ $\text{Loki + Promtail + Grafana}$(日志可视化)。所有资源部署在 `default` 命名空间,$\text{YAML}$ 文件位于 `deploy/k8s/`。
|
|
|
|
|
|
|
|
|
|
|
|
#### 6.1 部署 Jaeger
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl apply -f deploy/k8s/jaeger-deployment.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/jaeger-service.yaml
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 6.2 部署 Loki
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl apply -f deploy/k8s/loki-configmap.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/loki-pvc.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/loki-deployment.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/loki-service.yaml
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 6.3 部署 Promtail
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl apply -f deploy/k8s/promtail-rbac.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/promtail-configmap.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/promtail-daemonset.yaml
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 6.4 部署 Grafana
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl apply -f deploy/k8s/grafana-configmap.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/grafana-deployment.yaml
|
|
|
|
|
|
kubectl apply -f deploy/k8s/grafana-service.yaml
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 6.5 一键部署
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl apply -f deploy/k8s/jaeger-deployment.yaml \
|
|
|
|
|
|
-f deploy/k8s/jaeger-service.yaml \
|
|
|
|
|
|
-f deploy/k8s/loki-configmap.yaml \
|
|
|
|
|
|
-f deploy/k8s/loki-pvc.yaml \
|
|
|
|
|
|
-f deploy/k8s/loki-deployment.yaml \
|
|
|
|
|
|
-f deploy/k8s/loki-service.yaml \
|
|
|
|
|
|
-f deploy/k8s/promtail-rbac.yaml \
|
|
|
|
|
|
-f deploy/k8s/promtail-configmap.yaml \
|
|
|
|
|
|
-f deploy/k8s/promtail-daemonset.yaml \
|
|
|
|
|
|
-f deploy/k8s/grafana-configmap.yaml \
|
|
|
|
|
|
-f deploy/k8s/grafana-deployment.yaml \
|
|
|
|
|
|
-f deploy/k8s/grafana-service.yaml
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 6.6 状态检查
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 查看所有 Pod 状态
|
|
|
|
|
|
kubectl get pods
|
|
|
|
|
|
|
|
|
|
|
|
# 查看所有 Service 及 NodePort
|
|
|
|
|
|
kubectl get svc
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 6.7 端口汇总
|
|
|
|
|
|
|
|
|
|
|
|
| 服务 | NodePort | 访问地址 | 说明 |
|
|
|
|
|
|
| :--- | :--- | :--- | :--- |
|
|
|
|
|
|
| **Jaeger UI** | `31686` | `http://<NodeIP>:31686` | 链路追踪查询界面 |
|
|
|
|
|
|
| **Loki** | `31100` | `http://<NodeIP>:31100` | 日志 HTTP API |
|
|
|
|
|
|
| **Grafana** | `31000` | `http://<NodeIP>:31000` | 可视化界面,账号 `admin / coslight` |
|
|
|
|
|
|
| **OTLP gRPC** | `31317` | `<NodeIP>:31317` | ModelRT OTel 上报地址(gRPC) |
|
|
|
|
|
|
| **OTLP HTTP** | `31318` | `http://<NodeIP>:31318` | ModelRT OTel 上报地址(HTTP) |
|
|
|
|
|
|
|
|
|
|
|
|
#### 6.8 清理
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl delete -f deploy/k8s/
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 7\. Mac 本地访问(SSH 隧道)
|
|
|
|
|
|
|
|
|
|
|
|
$\text{ModelRT / EventRT}$ 在 $\text{Mac}$ 本地运行时,依赖的 $\text{RabbitMQ}$、$\text{Redis}$、$\text{Jaeger}$、$\text{Loki}$、$\text{Grafana}$ 均部署在 $\text{Ubuntu}$ 宿主机(`192.168.1.101`)上的 $\text{Minikube}$(`192.168.49.2`)中。由于 $\text{Minikube}$ 网络不直接对外暴露,需通过 $\text{SSH}$ 本地端口转发建立访问隧道。
|
|
|
|
|
|
|
|
|
|
|
|
#### 7.1 网络拓扑
|
|
|
|
|
|
|
|
|
|
|
|
``` text
|
|
|
|
|
|
Mac 本地端口 ──SSH隧道──▶ Ubuntu 宿主机 (192.168.1.101) ──▶ Minikube NodePort (192.168.49.2)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 7.2 建立隧道
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
ssh -L 5671:192.168.49.2:30671 \
|
|
|
|
|
|
-L 15671:192.168.49.2:31671 \
|
|
|
|
|
|
-L 6379:192.168.49.2:30001 \
|
|
|
|
|
|
-L 4318:192.168.49.2:31318 \
|
|
|
|
|
|
-L 16686:192.168.49.2:31686 \
|
|
|
|
|
|
-L 3100:192.168.49.2:31100 \
|
|
|
|
|
|
-L 3000:192.168.49.2:31000 \
|
|
|
|
|
|
douxu@192.168.1.101
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
如需后台静默运行(不占用终端):
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
ssh -fN \
|
|
|
|
|
|
-L 5671:192.168.49.2:30671 \
|
|
|
|
|
|
-L 15671:192.168.49.2:31671 \
|
|
|
|
|
|
-L 6379:192.168.49.2:30001 \
|
|
|
|
|
|
-L 4318:192.168.49.2:31318 \
|
|
|
|
|
|
-L 16686:192.168.49.2:31686 \
|
|
|
|
|
|
-L 3100:192.168.49.2:31100 \
|
|
|
|
|
|
-L 3000:192.168.49.2:31000 \
|
|
|
|
|
|
douxu@192.168.1.101
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 7.3 端口映射说明
|
|
|
|
|
|
|
|
|
|
|
|
| Mac 本地端口 | Minikube NodePort | 服务 | 说明 |
|
|
|
|
|
|
| :--- | :--- | :--- | :--- |
|
|
|
|
|
|
| `5671` | `30671` | RabbitMQ AMQP | ModelRT / EventRT 消息队列连接 |
|
|
|
|
|
|
| `15671` | `31671` | RabbitMQ Management | RabbitMQ 管理界面 `http://localhost:15671` |
|
|
|
|
|
|
| `6379` | `30001` | Redis | 分布式锁 / 数据存储 |
|
|
|
|
|
|
| `4318` | `31318` | OTLP HTTP | OTel Trace 上报(Jaeger Collector) |
|
|
|
|
|
|
| `16686` | `31686` | Jaeger UI | 链路追踪查询 `http://localhost:16686` |
|
|
|
|
|
|
| `3100` | `31100` | Loki | 日志查询 API |
|
|
|
|
|
|
| `3000` | `31000` | Grafana | 可视化界面 `http://localhost:3000` |
|
|
|
|
|
|
|
|
|
|
|
|
> **注意:** 隧道建立后,本地配置文件中所有服务地址均填 `localhost:<本地端口>`,无需修改即可在 $\text{Mac}$ 上直接运行服务。
|
|
|
|
|
|
|
|
|
|
|
|
#### 7.4 关闭隧道
|
|
|
|
|
|
|
|
|
|
|
|
前台运行时直接 `Ctrl+C`;后台运行时查找并终止进程:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 找到 ssh 隧道进程
|
|
|
|
|
|
ps aux | grep "ssh -fN"
|
|
|
|
|
|
# 终止(替换为实际 PID)
|
|
|
|
|
|
kill <PID>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 8\. 后续操作(停止与清理)
|
2025-10-17 17:10:10 +08:00
|
|
|
|
|
feat: add dedicated message-exchange for task lifecycle notifications
- add constants/message.go with MessageTask* categories and message-exchange /
message-queue / dead-letter routing constants
- add mq/publish_message.go with PushMessageToRabbitMQ (confirm mode,
dead-letter queue) separate from the existing event-exchange publisher
- add mq/emit.go with TryEmitMessage for non-blocking, OTel-traced dispatch
- add mq/event/task_event_gen.go with NewTaskSubmitted/Running/Completed/
Failed/CancelledMessage constructors
- wire TryEmitMessage into task worker and create/cancel handlers so all 5
lifecycle transitions are published (previously task.* routed to
event-exchange with no matching binding, causing silent drops)
- harden Dockerfile: scratch final image, pinned alpine:3.21 certs stage,
apk upgrade in builder, add -trimpath -mod=readonly go build flags
- add full K8s manifests under deploy/k8s/ for Redis, RabbitMQ (mTLS),
ModelRT (Downward API, scratch image, readOnlyRootFilesystem), Jaeger,
Loki, Promtail, Grafana
- expand deploy.md with async_task SQL schema, TLS cert generation steps,
K8s deployment procedures, and SSH tunnel configuration
2026-05-13 16:58:36 +08:00
|
|
|
|
#### 8.1 停止容器
|
2025-10-17 17:10:10 +08:00
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker stop postgres redis
|
|
|
|
|
|
```
|
|
|
|
|
|
|
feat: add dedicated message-exchange for task lifecycle notifications
- add constants/message.go with MessageTask* categories and message-exchange /
message-queue / dead-letter routing constants
- add mq/publish_message.go with PushMessageToRabbitMQ (confirm mode,
dead-letter queue) separate from the existing event-exchange publisher
- add mq/emit.go with TryEmitMessage for non-blocking, OTel-traced dispatch
- add mq/event/task_event_gen.go with NewTaskSubmitted/Running/Completed/
Failed/CancelledMessage constructors
- wire TryEmitMessage into task worker and create/cancel handlers so all 5
lifecycle transitions are published (previously task.* routed to
event-exchange with no matching binding, causing silent drops)
- harden Dockerfile: scratch final image, pinned alpine:3.21 certs stage,
apk upgrade in builder, add -trimpath -mod=readonly go build flags
- add full K8s manifests under deploy/k8s/ for Redis, RabbitMQ (mTLS),
ModelRT (Downward API, scratch image, readOnlyRootFilesystem), Jaeger,
Loki, Promtail, Grafana
- expand deploy.md with async_task SQL schema, TLS cert generation steps,
K8s deployment procedures, and SSH tunnel configuration
2026-05-13 16:58:36 +08:00
|
|
|
|
#### 8.2 删除容器(删除后数据将丢失)
|
2025-10-17 17:10:10 +08:00
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker rm postgres redis
|
|
|
|
|
|
```
|