# 项目部署指南 本项目依赖 `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\. 部署 RabbitMQ(Kubernetes) 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\. 部署 EventRT(Kubernetes) 所有资源部署在 `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 ``` --- ### 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 : 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 分服务清理 **仅停止(缩容至 0,PVC 数据与 Secret 保留)** 将所有 Deployment 和 StatefulSet 缩容至 0 副本,Pod 停止运行但持久卷数据不删除,之后可直接缩容回 1 恢复服务。 ```bash # 停止所有 Deployment(EventRT / RabbitMQ) kubectl scale deployment eventrt rabbitmq --replicas=0 # 停止 MongoDB StatefulSet(PVC 数据保留) 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 ```