eventRT/deploy/deploy.md

690 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 项目部署指南
本项目依赖 `MongoDB`(事件持久化存储)与 `RabbitMQ`mTLS 消息队列),并通过 `OpenTelemetry + Jaeger` 完成链路追踪。
## 前提条件
1. 已安装 `Docker``kubectl`
2. `Minikube` 集群已启动并可访问
3. 确保以下端口在宿主机上未被占用:`27017`MongoDB、`5671`RabbitMQ AMQP
---
### 1\. 部署 MongoDB 数据库
EventRT 支持两种 MongoDB 部署方式,根据场景二选一:**Docker**(本地开发 / Ubuntu 宿主机直跑)或 **K8s**Minikube 环境)。
#### 1.1 Docker 部署(本地开发)
使用官方 `mongo:7.0` 镜像,在 Ubuntu 宿主机(`192.168.1.101`)上以 Docker 容器运行。
##### 1.1.1 部署命令
```bash
docker run --name mongodb \
-e MONGO_INITDB_ROOT_USERNAME=coslight \
-e MONGO_INITDB_ROOT_PASSWORD=coslight@tj \
-p 27017:27017 \
-d mongo:7.0
```
##### 1.1.2 连接信息
| 参数 | 值 | 说明 |
| :--- | :--- | :--- |
| **容器名称** | `mongodb` | 容器名 |
| **镜像版本** | `mongo:7.0` | MongoDB 7.0 |
| **主机端口** | `27017` | 外部应用连接端口 |
| **用户名** | `coslight` | Root 管理员 |
| **密码** | `coslight@tj` | 启动时通过 `MONGO_INITDB_ROOT_PASSWORD` 设置 |
| **鉴权数据库** | `admin` | `auth_db` |
| **业务数据库** | `eventdb` | EventRT 事件存储库 |
##### 1.1.3 状态检查
```bash
# 检查容器启动状态
docker ps -a | grep mongodb
# 检查启动日志
docker logs mongodb
```
> **注意:** 密码当前以明文形式写在 `docker run` 命令中,生产环境应通过 Docker Secret 或环境变量文件(`--env-file`)传入,避免在 Shell 历史记录中留存明文密码。
##### 1.1.4 连接验证
```bash
# 快速检查 MongoDB 是否接受连接
docker exec -it mongodb mongosh \
-u coslight -p "coslight@tj" --authenticationDatabase admin \
--eval "db.adminCommand({ ping: 1 })"
# 列出所有数据库(确认服务正常)
docker exec -it mongodb mongosh \
-u coslight -p "coslight@tj" --authenticationDatabase admin \
--eval "show dbs"
```
##### 1.1.5 初始化 eventdb 数据库
MongoDB 启动后进入容器,为 `eventdb` 库授权:
```bash
docker exec -it mongodb mongosh \
-u coslight -p "coslight@tj" --authenticationDatabase admin
```
`mongosh` 中执行:
```javascript
// 切换到 eventdb若不存在则自动创建
use eventdb
// 授予 coslight 用户对 eventdb 的读写权限(根用户已有全库权限,此步可选)
db.createUser({
user: "coslight",
pwd: "coslight@tj",
roles: [{ role: "readWrite", db: "eventdb" }]
})
```
#### 1.2 K8s 部署Minikube
YAML 文件位于 `deploy/k8s/`(从 modelrt 仓库迁移而来,需确认文件已拷贝至本项目)。
```bash
kubectl apply -f deploy/k8s/mongodb-secret.yaml
kubectl apply -f deploy/k8s/mongodb-pvc.yaml
kubectl apply -f deploy/k8s/mongodb-statefulset.yaml
kubectl apply -f deploy/k8s/mongodb-service.yaml
```
| 参数 | 值 | 说明 |
| :--- | :--- | :--- |
| **镜像** | `mongo:7.0` | MongoDB 7.0 |
| **NodePort** | `30017` | 集群外访问端口 |
| **用户名** | `admin` | Root 管理员Secret `mongodb-secret` |
| **密码** | `coslight` | Secret `mongodb-secret` 中配置,生产环境请替换强密码 |
| **存储** | `2Gi` | PVC `mongodb-data` |
| **CPU** | `100m` 请求 / `500m` 上限 | StatefulSet `resources` 字段 |
| **内存** | `256Mi` 请求 / `512Mi` 上限 | StatefulSet `resources` 字段 |
> **注意:** 密码存储在 `mongodb-secret.yaml` 的 `stringData` 中,生产环境应替换为强密码,并避免将明文密码提交至版本库。
##### 1.2.1 等待 Pod 就绪
```bash
kubectl wait --for=condition=ready pod -l app=mongodb --timeout=120s
```
##### 1.2.2 连接验证
```bash
kubectl exec -it $(kubectl get pod -l app=mongodb -o jsonpath='{.items[0].metadata.name}') \
-- mongosh -u admin -p coslight --authenticationDatabase admin \
--eval "db.adminCommand({ ping: 1 })"
```
##### 1.2.3 初始化 eventdb 数据库
```bash
kubectl exec -it $(kubectl get pod -l app=mongodb -o jsonpath='{.items[0].metadata.name}') \
-- mongosh -u admin -p coslight --authenticationDatabase admin
```
`mongosh` 中执行:
```javascript
use eventdb
db.createUser({
user: "coslight",
pwd: "coslight@tj",
roles: [{ role: "readWrite", db: "eventdb" }]
})
```
##### 1.2.4 状态检查
```bash
kubectl get pods -l app=mongodb
kubectl logs -l app=mongodb --tail=30
```
---
### 2\. 部署 RabbitMQKubernetes
RabbitMQ 配置为仅允许 TLS 连接(`listeners.tcp = none`),所有客户端须持有由同一 CA 签发的证书。YAML 文件位于 `deploy/mq/`
#### 2.1 TLS 证书生成
##### 2.1.1 生成根 CA
```bash
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即 cakey.pem生成于 result/
```
##### 2.1.2 生成服务端证书
服务端证书需包含 SAN使其同时匹配集群内 DNS 和 Minikube IP。使用 `deploy/mq/server.conf`(已预置正确配置):
```bash
# 将 ca_certificate.pem 和 cakey.pem 放在当前目录
openssl genrsa -out server_key.pem 2048
openssl req -new -key server_key.pem \
-out server_cert.csr -config deploy/mq/server.conf
openssl x509 -req -in server_cert.csr \
-CA ca_certificate.pem -CAkey cakey.pem -CAcreateserial \
-out server_certificate.pem -days 730 -sha256 \
-extfile deploy/mq/server.conf -extensions v3_server
rm server_cert.csr
```
##### 2.1.3 生成 EventRT 客户端证书
CN 必须与 RabbitMQ 中注册的用户名一致(`eventrt-client`)。使用 `deploy/mq/eventrt.conf`
```bash
openssl genrsa -out eventrt_client_key.pem 2048
openssl req -new -key eventrt_client_key.pem \
-out eventrt_client.csr -config deploy/mq/eventrt.conf
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 deploy/mq/eventrt.conf
rm eventrt_client.csr
```
##### 2.1.4 生成 ModelRT 客户端证书
使用 `deploy/mq/modelrt.conf`CN 为 `modelrt-client`
```bash
openssl genrsa -out modelrt_client_key.pem 2048
openssl req -new -key modelrt_client_key.pem \
-out modelrt_client.csr -config deploy/mq/modelrt.conf
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 deploy/mq/modelrt.conf
rm modelrt_client.csr
```
##### 2.1.5 验证证书
```bash
# 验证服务端证书
openssl verify -CAfile ca_certificate.pem server_certificate.pem
# 验证客户端证书
openssl verify -CAfile ca_certificate.pem eventrt_client_cert.pem
openssl verify -CAfile ca_certificate.pem modelrt_client_cert.pem
# 确认 CN 和扩展clientAuth / serverAuth
openssl x509 -in server_certificate.pem -noout -subject -ext subjectAltName
openssl x509 -in eventrt_client_cert.pem -noout -subject -text | grep -A1 "Extended Key Usage"
openssl x509 -in modelrt_client_cert.pem -noout -subject
```
#### 2.2 部署 RabbitMQ
##### 2.2.1 创建证书 Secret
在证书文件所在目录执行:
```bash
sh deploy/mq/secert.sh
```
该脚本等价于:
```bash
kubectl create secret generic rabbitmq-certs \
--from-file=ca_certificate.pem=./certs/ca_certificate.pem \
--from-file=server_certificate.pem=./certs/server_certificate.pem \
--from-file=server_key.pem=./certs/server_key.pem
```
##### 2.2.2 部署
```bash
kubectl apply -f deploy/mq/rabbitmq-secret.yaml
kubectl apply -f deploy/mq/rabbitmq-users-config.yaml
kubectl apply -f deploy/mq/rabbitmq-config.yaml
kubectl apply -f deploy/mq/rabbitmq-deployment.yaml
kubectl apply -f deploy/mq/rabbitmq-service.yaml
```
##### 2.2.3 端口汇总
| 端口 | NodePort | 说明 |
| :--- | :--- | :--- |
| `5671` | `30671` | AMQP over TLS客户端连接 |
| `5672` | `30672` | AMQP 明文(内部备用,生产禁用) |
| `15671` | `31671` | Management UI over TLS |
| `15672` | `31672` | Management UI 明文(内部备用) |
##### 2.2.4 用户与权限说明
用户定义在 `rabbitmq-users-config.yaml``definitions.json` 中,启动时通过 `load_definitions` 自动加载:
| 用户 | 认证方式 | 权限 | 说明 |
| :--- | :--- | :--- | :--- |
| `coslight` | 密码 | administrator | 管理员,密码在 `rabbitmq-secret.yaml` |
| `eventrt-client` | X.509 证书CN | configure/read/write | EventRT 服务专用 |
| `modelrt-client` | X.509 证书CN | configure/read/write | ModelRT 服务专用 |
| `web-client` | X.509 证书CN | read/write | Web 客户端 |
> **注意:** 证书认证用户的 `password_hash` 留空RabbitMQ 通过 `ssl_cert_login_from = common_name` 将证书 CN 映射为用户名。
---
### 3\. 部署 EventRTKubernetes
所有资源部署在 `default` 命名空间YAML 文件位于 `deploy/k8s/`
#### 3.1 构建并推送镜像
镜像采用三阶段构建,最终基于 `scratch`
| 阶段 | 基础镜像 | 作用 |
| :--- | :--- | :--- |
| **builder** | `golang:1.26-alpine` | 编译 Go 二进制(`CGO_ENABLED=0``-trimpath -ldflags="-s -w"` |
| **certs** | `alpine:3.21` | 提取 CA 证书、时区数据及非 root 用户定义UID 默认 `1000` |
| **runtime** | `scratch` | 仅含可执行文件与运行时依赖,无 shell、无包管理器 |
**方式一:从源码构建并加载**
```bash
# 在项目根目录执行(默认运行用户 UID=1000
docker build -f deploy/dockerfile/eventrt.Dockerfile -t coslight/eventrt:latest .
# 自定义运行用户 UID
docker build -f deploy/dockerfile/eventrt.Dockerfile \
--build-arg USER_ID=2000 \
-t coslight/eventrt:latest .
# 加载到 Minikube无需私有仓库
minikube image load coslight/eventrt:latest
```
**方式二:直接加载已有本地镜像**
Ubuntu 宿主机上已存在构建好的镜像(如 `eventrt:v1`)时,无需重新构建,直接导入 Minikube
```bash
# 确认本地镜像存在
docker images eventrt:v1
# 加载到 Minikube
minikube image load eventrt:v1
# 验证镜像已进入 Minikube 缓存
minikube image ls | grep eventrt
```
> **注意:** `deploy/k8s/eventrt-deployment.yaml` 中的 `image` 字段需与加载的镜像名称一致,并将 `imagePullPolicy` 设为 `Never`,防止 Minikube 尝试从远端拉取。
#### 3.1.1 镜像冒烟测试
```bash
# 查看镜像大小scratch 镜像预期 ≤ 25 MB
docker images coslight/eventrt:latest
# 检查镜像元信息(确认 User、Cmd、架构
docker inspect coslight/eventrt:latest
# 验证二进制可执行(无 config 时程序报错退出属预期行为,说明镜像构建正常)
docker run --rm coslight/eventrt:latest
# 挂载示例配置做完整启动验证Ctrl+C 退出)
docker run --rm \
-v "$(pwd)/configs/config.example.yaml:/app/configs/config.yaml" \
-p 8081:8081 \
coslight/eventrt:latest
```
> **注意:** `scratch` 镜像不含 shell无法使用 `docker exec` 进入容器调试;如需排查问题,可临时将最终阶段改为 `alpine` 进行本地调试,确认后再切回 `scratch`。
#### 3.2 创建客户端证书 Secret
在 RabbitMQ TLS 证书生成完成后(见 2.1),进入证书文件所在目录执行:
```bash
sh deploy/k8s/eventrt-certs-secret.sh
```
该脚本等价于:
```bash
kubectl create secret generic eventrt-certs \
--from-file=ca_certificate.pem=./ca_certificate.pem \
--from-file=eventrt_client_cert.pem=./eventrt_client_cert.pem \
--from-file=eventrt_client_key.pem=./eventrt_client_key.pem
```
#### 3.3 部署
```bash
kubectl apply -f deploy/k8s/eventrt-secret.yaml
kubectl apply -f deploy/k8s/eventrt-configmap.yaml
kubectl apply -f deploy/k8s/eventrt-deployment.yaml
kubectl apply -f deploy/k8s/eventrt-service.yaml
```
等待 Pod 就绪:
```bash
kubectl wait --for=condition=ready pod -l app=eventrt --timeout=120s
```
#### 3.4 配置说明
| 配置项 | 方式 | 说明 |
| :--- | :--- | :--- |
| `mongodb.password` | Secret `eventrt-secret` | 不写入 ConfigMap通过环境变量 `MONGODB_PASSWORD` 注入 |
| `service.secret_key` | Secret `eventrt-secret` | 不写入 ConfigMap通过环境变量 `SERVICE_SECRET_KEY` 注入 |
| RabbitMQ 客户端证书 | Secret `eventrt-certs` | 挂载至 `/app/configs/certs/` |
| `config.yaml` 其余配置 | ConfigMap `eventrt-config` | `rabbitmq.host` 已设为 K8s Service 名 `rabbitmq-service` |
| `K8S_NAMESPACE` / `K8S_NODE_NAME` | Downward API | 注入至日志全局字段 |
#### 3.5 状态检查
```bash
# 查看 Pod 状态
kubectl get pods -l app=eventrt
# 查看启动日志
kubectl logs -l app=eventrt --tail=50
# 查看 Service
kubectl get svc eventrt-service
```
#### 3.6 端口汇总
| NodePort | 说明 |
| :--- | :--- |
| `30081` | EventRT HTTP API |
#### 3.7 清理
```bash
kubectl delete -f deploy/k8s/eventrt-service.yaml \
-f deploy/k8s/eventrt-deployment.yaml \
-f deploy/k8s/eventrt-configmap.yaml \
-f deploy/k8s/eventrt-secret.yaml
kubectl delete secret eventrt-certs
```
---
### 4\. Mac 本地访问SSH 隧道)
`EventRT` 在 Mac 本地运行时RabbitMQ 部署在 Ubuntu 宿主机(`192.168.1.101`)的 Minikube 中MongoDB 直接运行在宿主机上。需通过 SSH 本地端口转发建立访问隧道。
#### 4.1 网络拓扑
```text
Mac 本地端口 ──SSH隧道──▶ Ubuntu 宿主机 (192.168.1.101) ──▶ Minikube NodePort (192.168.49.2)
└──▶ MongoDB Docker (宿主机 27017)
```
#### 4.2 建立隧道
```bash
ssh -L 27017:127.0.0.1:27017 \
-L 5671:192.168.49.2:30671 \
-L 15671:192.168.49.2:31671 \
-L 4318:192.168.49.2:31318 \
-L 16686:192.168.49.2:31686 \
douxu@192.168.1.101
```
如需后台静默运行(不占用终端):
```bash
ssh -fN \
-L 27017:127.0.0.1:27017 \
-L 5671:192.168.49.2:30671 \
-L 15671:192.168.49.2:31671 \
-L 4318:192.168.49.2:31318 \
-L 16686:192.168.49.2:31686 \
douxu@192.168.1.101
```
#### 4.3 端口映射说明
| Mac 本地端口 | 目标 | 服务 | 说明 |
| :--- | :--- | :--- | :--- |
| `27017` | 宿主机 `127.0.0.1:27017` | MongoDB | EventRT 事件数据库 |
| `5671` | Minikube `192.168.49.2:30671` | RabbitMQ AMQP | 消息队列 mTLS 连接 |
| `15671` | Minikube `192.168.49.2:31671` | RabbitMQ Management | 管理界面 `http://localhost:15671` |
| `4318` | Minikube `192.168.49.2:31318` | OTLP HTTP | OTel Trace 上报Jaeger Collector |
| `16686` | Minikube `192.168.49.2:31686` | Jaeger UI | 链路追踪查询 `http://localhost:16686` |
> **注意:** 隧道建立后,本地 `config.yaml` 中所有服务地址填 `localhost:<本地端口>` 即可直接运行服务。
#### 4.4 关闭隧道
前台运行时直接 `Ctrl+C`;后台运行时查找并终止进程:
```bash
# 找到 ssh 隧道进程
ps aux | grep "ssh -fN"
# 终止(替换为实际 PID
kill <PID>
```
---
### 5\. 本地运行go run / 二进制)
#### 5.1 配置服务配置文件
`configs/config.example.yaml` 复制为 `configs/config.yaml` 并按以下说明调整:
##### 5.1.1 配置参数说明
| 类别 | 参数名 | 作用描述 | 示例值 |
| :--- | :--- | :--- | :--- |
| **MongoDB** | `host` | MongoDB 服务器地址 | `"localhost"` |
| | `port` | MongoDB 端口 | `27017` |
| | `user` | 连接用户名 | `"coslight"` |
| | `password` | 连接密码 | `"coslight@tj"` |
| | `database` | 业务数据库名 | `"eventdb"` |
| | `auth_db` | 鉴权数据库 | `"admin"` |
| | `timeout` | 连接超时(秒) | `10` |
| **RabbitMQ** | `host` | RabbitMQ 服务器地址 | `"localhost"` |
| | `port` | AMQP over TLS 端口 | `5671` |
| | `server_name` | TLS SNI / 证书 CN | `"rabbitmq-server"` |
| | `ca_cert_path` | CA 证书路径 | `"./configs/certs/ca_certificate.pem"` |
| | `client_cert_path` | 客户端证书路径 | `"./configs/certs/eventrt_client_cert.pem"` |
| | `client_key_path` | 客户端私钥路径 | `"./configs/certs/eventrt_client_key.pem"` |
| | `insecure_skip_verify` | 是否跳过证书校验(开发临时用) | `false` |
| **Logger (Zap)** | `mode` | 日志模式 `development` / `production` | `"development"` |
| | `level` | 最低日志级别 | `"debug"` |
| | `filepath` | 日志文件路径(空字符串输出到 stdout | `""` |
| | `maxsize` | 单文件最大大小MB | `1` |
| | `maxbackups` | 保留旧文件最大个数 | `5` |
| | `maxage` | 保留旧文件最大天数 | `30` |
| | `compress` | 是否压缩备份文件 | `false` |
| **Service** | `service_addr` | HTTP 监听地址 | `":8081"` |
| | `service_name` | 服务名(日志/监控标识) | `"eventRT"` |
| | `secret_key` | 内部签名密钥 | `"eventrt_key"` |
| | `deploy_env` | 部署环境 `development` / `production` | `"development"` |
| **OTel** | `endpoint` | OTLP HTTP 上报地址(不含协议前缀) | `"localhost:4318"` |
| | `insecure` | 是否不启用 TLS | `true` |
#### 5.2 编译 EventRT 服务
```bash
go build -o eventrt main.go
```
#### 5.3 启动服务
```bash
./eventrt
```
#### 5.4 检测服务启动日志
控制台输出 `starting EventRT server` 后即代表服务启动成功。
---
### 6\. 排查手册
#### 6.1 证书权限检查
确认客户端证书包含 `TLS Web Client Authentication`
```bash
openssl x509 -in configs/certs/eventrt_client_cert.pem -noout -text \
| grep -A1 "Extended Key Usage"
```
预期输出包含 `TLS Web Client Authentication`
#### 6.2 握手连通性验证
```bash
openssl s_client -connect localhost:5671 \
-cert configs/certs/eventrt_client_cert.pem \
-key configs/certs/eventrt_client_key.pem \
-CAfile configs/certs/ca_certificate.pem
```
预期结果:看到 `Verify return code: 0 (ok)`
#### 6.3 RabbitMQ 日志检查
连接成功后RabbitMQ 日志应出现:
```
connection <xxx>: user 'eventrt-client' authenticated and granted access to vhost '/'
```
查看 Pod 日志:
```bash
kubectl logs -l app=rabbitmq --tail=50 | grep eventrt-client
```
#### 6.4 MongoDB 连通性验证
```bash
mongosh "mongodb://coslight:coslight@tj@localhost:27017/eventdb?authSource=admin"
```
预期进入 `mongosh` 提示符,执行 `show collections` 无报错。
---
### 7\. 后续操作(停止与清理)
#### 7.1 本地 Docker 部署清理
适用于第 1 节使用 `docker run` 启动的 MongoDB 容器。
```bash
# 停止容器
docker stop mongodb
# 删除容器(容器内数据将同步丢失)
docker rm mongodb
```
#### 7.2 本地 go run 运行清理
适用于第 5 节以 `go run` 或编译后二进制方式在本地启动的 EventRT 服务。
前台运行时直接 `Ctrl+C` 终止;后台运行时查找并终止进程:
```bash
# 终止 go run 启动的进程
pkill -f "go run main.go"
# 或终止编译后的二进制进程
pkill eventrt
```
#### 7.3 K8s(Minikube) 部署清理
适用于第 1.2、2、3 节在 Minikube 中部署的所有资源。
##### 7.3.1 分服务清理
**仅停止(缩容至 0PVC 数据与 Secret 保留)**
将所有 Deployment 和 StatefulSet 缩容至 0 副本Pod 停止运行但持久卷数据不删除,之后可直接缩容回 1 恢复服务。
```bash
# 停止所有 DeploymentEventRT / RabbitMQ
kubectl scale deployment eventrt rabbitmq --replicas=0
# 停止 MongoDB StatefulSetPVC 数据保留)
kubectl scale statefulset mongodb --replicas=0
```
恢复时:
```bash
kubectl scale deployment eventrt rabbitmq --replicas=1
kubectl scale statefulset mongodb --replicas=1
```
---
**永久清理(删除所有资源,数据不可恢复)**
按部署顺序反向删除各服务资源:
```bash
# EventRT 应用
kubectl delete -f deploy/k8s/eventrt-service.yaml \
-f deploy/k8s/eventrt-deployment.yaml \
-f deploy/k8s/eventrt-configmap.yaml \
-f deploy/k8s/eventrt-secret.yaml
kubectl delete secret eventrt-certs
# MongoDB
kubectl delete -f deploy/k8s/mongodb-service.yaml \
-f deploy/k8s/mongodb-statefulset.yaml \
-f deploy/k8s/mongodb-pvc.yaml \
-f deploy/k8s/mongodb-secret.yaml
# RabbitMQ
kubectl delete -f deploy/mq/rabbitmq-service.yaml \
-f deploy/mq/rabbitmq-deployment.yaml \
-f deploy/mq/rabbitmq-users-config.yaml \
-f deploy/mq/rabbitmq-config.yaml \
-f deploy/mq/rabbitmq-secret.yaml
kubectl delete secret rabbitmq-certs
```
##### 7.3.2 一键清理
> **注意:** 此操作会删除 `deploy/k8s/` 和 `deploy/mq/` 下所有 YAML 对应的 K8s 资源,请确认后执行。
```bash
kubectl delete -f deploy/k8s/ -f deploy/mq/
kubectl delete secret eventrt-certs rabbitmq-certs
```