feat: 三种部署方式 — embed单容器 + 二进制部署 + K8s
新增三种部署方式(原有 docker-compose 不受影响): 1. Docker embed 单容器 (docker-compose.embed.yml): - go:embed 前端嵌入后端二进制 - 不需要 nginx 容器,3容器→2容器 - 镜像仅 54.8MB (vs 原来 1.16GB) - 用法: make docker-embed 2. 二进制部署 (deploy/binary/): - make build-binary 生成单二进制 - install.sh 自动创建 systemd 服务 - 适合无 Docker 环境 - 用法: scp aiops + install.sh, bash install.sh install 3. Kubernetes 部署 (deploy/k8s/): - devops 命名空间全套 yaml - MySQL StatefulSet + Redis StatefulSet + Backend Deployment - ConfigMap + Secret + Ingress - 用法: kubectl apply -f deploy/k8s/ 核心改动: - backend/cmd/embed.go: go:embed 前端 + SPA fallback 路由 - backend/Dockerfile.embed: 四阶段构建 (前端→后端embed→agent→runtime) - Makefile: build-binary + docker-embed 目标 - deploy/README.md: 四种部署方式对比文档
This commit is contained in:
1 parent
24f955832e
commit
4631b02f13
15 files changed
+1218
-3
No files matched your search
@@ -0,0 +1,107 @@
|
||||
# AIOps 三种部署方式
|
||||
|
||||
## 部署方式对比
|
||||
|
||||
| 方式 | 适用场景 | 优点 | 缺点 |
|
||||
|------|---------|------|------|
|
||||
| **Docker Compose(双容器)** | 生产环境 | 前后端分离,nginx 高性能 | 需要 4 个容器 |
|
||||
| **Docker Compose(embed 单容器)** | 快速部署 | 1 个容器搞定,无需 nginx | 静态文件性能稍弱 |
|
||||
| **二进制部署** | 无 Docker 环境 | 一个文件 + systemd | 需要自行管理 MySQL/Redis |
|
||||
| **Kubernetes** | K8s 集群 | 标准化编排,弹性伸缩 | 需要 K8s 集群 |
|
||||
|
||||
---
|
||||
|
||||
## 方式一:Docker Compose(双容器,当前默认)
|
||||
|
||||
```bash
|
||||
# 开发机(75)
|
||||
cd /srv/aiops
|
||||
make docker-up # 构建并启动
|
||||
|
||||
# 生产机(150)
|
||||
cd /srv/aiops && git pull
|
||||
make docker-up
|
||||
```
|
||||
|
||||
架构:nginx(:80) → backend(:8080) + MySQL + Redis
|
||||
|
||||
---
|
||||
|
||||
## 方式二:Docker Compose embed 单容器
|
||||
|
||||
前端通过 Go `//go:embed` 嵌入后端二进制,不需要 nginx 容器。
|
||||
|
||||
```bash
|
||||
cd /srv/aiops
|
||||
docker-compose -f docker-compose.embed.yml up -d --build
|
||||
# 或
|
||||
make docker-embed
|
||||
```
|
||||
|
||||
架构:aiops-app(:80→:8080) + MySQL + Redis(3 个容器)
|
||||
|
||||
---
|
||||
|
||||
## 方式三:二进制部署(无 Docker)
|
||||
|
||||
### 在开发机构建
|
||||
|
||||
```bash
|
||||
cd /srv/aiops
|
||||
make build-binary
|
||||
# 生成 ./aiops 单二进制(~30MB,前端已嵌入)
|
||||
```
|
||||
|
||||
### 在目标服务器部署
|
||||
|
||||
```bash
|
||||
# 传两个文件到目标服务器
|
||||
scp aiops deploy/binary/install.sh root@<target>:/tmp/
|
||||
|
||||
# 安装(自动创建 systemd 服务 + 默认配置)
|
||||
ssh root@<target>
|
||||
cd /tmp && bash install.sh install
|
||||
|
||||
# 修改数据库配置
|
||||
vim /opt/aiops/config.yaml
|
||||
|
||||
# 启动
|
||||
systemctl start aiops
|
||||
```
|
||||
|
||||
### 管理
|
||||
|
||||
```bash
|
||||
systemctl start aiops # 启动
|
||||
systemctl stop aiops # 停止
|
||||
systemctl restart aiops # 重启
|
||||
systemctl status aiops # 状态
|
||||
journalctl -u aiops -f # 日志
|
||||
```
|
||||
|
||||
架构:aiops 二进制 + systemd(端口 8080 同时服务 API 和前端)
|
||||
|
||||
> 前提:目标服务器需已安装 MySQL 8.0 + Redis 7
|
||||
|
||||
---
|
||||
|
||||
## 方式四:Kubernetes 部署
|
||||
|
||||
```bash
|
||||
cd /srv/aiops
|
||||
kubectl apply -f deploy/k8s/
|
||||
```
|
||||
|
||||
详见 [deploy/k8s/README.md](../k8s/README.md)
|
||||
|
||||
---
|
||||
|
||||
## 快速选择
|
||||
|
||||
| 环境 | 推荐方式 |
|
||||
|------|---------|
|
||||
| 开发测试(75) | 方式一 docker-compose |
|
||||
| 生产环境(150) | 方式一 docker-compose |
|
||||
| 客户现场快速演示 | 方式二 embed 单容器 |
|
||||
| 内网无 Docker 服务器 | 方式三 二进制部署 |
|
||||
| K8s 集群 | 方式四 Kubernetes |
|
||||
Executable
+165
@@ -0,0 +1,165 @@
|
||||
#!/bin/bash
|
||||
# ============================================================
|
||||
# AIOps 二进制部署脚本(embed 模式)
|
||||
# 一个二进制 = 前端 + 后端,无需 Docker/Nginx
|
||||
# 署名 Logan.Li
|
||||
# ============================================================
|
||||
set -e
|
||||
|
||||
# 颜色
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
# 默认路径
|
||||
INSTALL_DIR="/opt/aiops"
|
||||
CONFIG_FILE="$INSTALL_DIR/config.yaml"
|
||||
SERVICE_FILE="/etc/systemd/system/aiops.service"
|
||||
BINARY_NAME="aiops"
|
||||
PID_FILE="/var/run/aiops.pid"
|
||||
|
||||
# ============================================================
|
||||
# 命令处理
|
||||
# ============================================================
|
||||
case "$1" in
|
||||
install)
|
||||
info "AIOps 二进制安装"
|
||||
echo ""
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
error "请使用 root 或 sudo 执行"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查二进制
|
||||
if [ ! -f "./${BINARY_NAME}" ]; then
|
||||
error "当前目录找不到 ./${BINARY_NAME} 二进制文件"
|
||||
echo " 请先在开发机执行: make build-binary"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 创建安装目录
|
||||
mkdir -p "$INSTALL_DIR/logs" "$INSTALL_DIR/uploads"
|
||||
|
||||
# 复制二进制
|
||||
cp "./${BINARY_NAME}" "$INSTALL_DIR/"
|
||||
chmod +x "$INSTALL_DIR/${BINARY_NAME}"
|
||||
info "二进制已安装到 $INSTALL_DIR/${BINARY_NAME}"
|
||||
|
||||
# 生成默认配置(如果不存在)
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
cat > "$CONFIG_FILE" << 'EOF'
|
||||
mode: release
|
||||
port: "8080"
|
||||
log_level: info
|
||||
|
||||
database:
|
||||
driver: mysql
|
||||
host: 127.0.0.1
|
||||
port: 3306
|
||||
user: aiops
|
||||
password: aiops_pass_2026
|
||||
dbname: aiops
|
||||
charset: utf8mb4
|
||||
max_conn: 100
|
||||
max_idle: 10
|
||||
|
||||
redis:
|
||||
driver: redis
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
password: ""
|
||||
db: 0
|
||||
|
||||
jwt:
|
||||
secret: ezops-aiops-jwt-secret-2026
|
||||
expire_hour: 24
|
||||
EOF
|
||||
info "默认配置已生成: $CONFIG_FILE"
|
||||
warn "请根据实际环境修改数据库/Redis 配置"
|
||||
fi
|
||||
|
||||
# 创建 systemd 服务
|
||||
cat > "$SERVICE_FILE" << EOF
|
||||
[Unit]
|
||||
Description=AIOps Platform (Embed Mode)
|
||||
After=network-online.target mysql.service redis.service
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=${INSTALL_DIR}
|
||||
ExecStart=${INSTALL_DIR}/${BINARY_NAME}
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
LimitNOFILE=65536
|
||||
Environment=GIN_MODE=release
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable aiops
|
||||
info "systemd 服务已创建并启用开机自启"
|
||||
|
||||
echo ""
|
||||
info "安装完成!"
|
||||
echo ""
|
||||
echo " 启动: systemctl start aiops"
|
||||
echo " 状态: systemctl status aiops"
|
||||
echo " 日志: journalctl -u aiops -f"
|
||||
echo " 配置: vim $CONFIG_FILE"
|
||||
echo " 访问: http://<IP>:8080"
|
||||
echo ""
|
||||
;;
|
||||
|
||||
start)
|
||||
systemctl start aiops
|
||||
info "AIOps 已启动"
|
||||
;;
|
||||
|
||||
stop)
|
||||
systemctl stop aiops
|
||||
info "AIOps 已停止"
|
||||
;;
|
||||
|
||||
restart)
|
||||
systemctl restart aiops
|
||||
info "AIOps 已重启"
|
||||
;;
|
||||
|
||||
status)
|
||||
systemctl status aiops --no-pager
|
||||
;;
|
||||
|
||||
uninstall)
|
||||
warn "即将卸载 AIOps(保留数据/配置)"
|
||||
systemctl stop aiops 2>/dev/null
|
||||
systemctl disable aiops
|
||||
rm -f "$SERVICE_FILE"
|
||||
rm -f "$INSTALL_DIR/${BINARY_NAME}"
|
||||
systemctl daemon-reload
|
||||
info "已卸载(配置/日志/数据保留在 $INSTALL_DIR)"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "AIOps 二进制部署工具"
|
||||
echo ""
|
||||
echo "用法: $0 {install|start|stop|restart|status|uninstall}"
|
||||
echo ""
|
||||
echo " install - 安装二进制 + 生成配置 + 创建 systemd 服务"
|
||||
echo " start - 启动服务"
|
||||
echo " stop - 停止服务"
|
||||
echo " restart - 重启服务"
|
||||
echo " status - 查看服务状态"
|
||||
echo " uninstall - 卸载二进制(保留数据)"
|
||||
echo ""
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,158 @@
|
||||
# AIOps Kubernetes 部署
|
||||
|
||||
AIOps 平台在 Kubernetes 上的部署清单(Go/Gin 后端 + go:embed 前端 + MySQL 8.0 + Redis 7)。
|
||||
|
||||
所有资源部署在 **`devops`** 命名空间。
|
||||
|
||||
## 目录结构
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `namespace.yaml` | `devops` 命名空间 |
|
||||
| `configmap.yaml` | 后端 `config.yaml`(ConfigMap)+ MySQL/JWT 密码(Secret) |
|
||||
| `mysql.yaml` | MySQL 8.0 StatefulSet + Headless/ClusterIP Service + 8Gi 持久卷 |
|
||||
| `redis.yaml` | Redis 7 StatefulSet + Headless/ClusterIP Service + 2Gi 持久卷 |
|
||||
| `backend.yaml` | 后端 Deployment(端口 8080=API/WS,80=embed 前端)+ ClusterIP Service |
|
||||
| `ingress.yaml` | Ingress:`/api`、`/ws` → 8080;`/` → 80 |
|
||||
|
||||
## 架构与端口
|
||||
|
||||
```
|
||||
┌──────────────── Ingress (nginx) ────────────────┐
|
||||
/api, /ws ──▶│ │──▶ aiops-backend:8080 (API + WebSocket)
|
||||
/ ──▶│ │──▶ aiops-backend:80 (go:embed 前端)
|
||||
└──────────────────────────────────────────────────┘
|
||||
│
|
||||
┌──────────────┴──────────────┐
|
||||
▼ ▼
|
||||
aiops-backend aiops-backend
|
||||
│ (DB_HOST=mysql) │ (REDIS_HOST=redis)
|
||||
▼ ▼
|
||||
MySQL 8.0 (StatefulSet) Redis 7 (StatefulSet)
|
||||
aiops / aiops_pass_2026 无密码, db 0
|
||||
数据库 aiops, 8Gi PV 2Gi PV
|
||||
```
|
||||
|
||||
- **8080**:API + WebSocket
|
||||
- **80**:前端(go:embed 嵌入后端二进制,由后端进程提供静态资源)
|
||||
- 配置文件 `config.yaml` 中 DB/Redis 连接均以环境变量 `${VAR}` 占位,由 Deployment 的 `env` 注入;密码走 Secret。
|
||||
|
||||
## 前置条件
|
||||
|
||||
1. 一个可用的 Kubernetes 集群(≥ 1.22)。
|
||||
2. 已安装 **nginx Ingress Controller**。
|
||||
3. 集群具备可用的 **StorageClass**(MySQL/Redis 的 `volumeClaimTemplates` 依赖动态卷供应)。
|
||||
- minikube / kind 自带默认 StorageClass(如 `standard`)。
|
||||
- 如需指定,取消各 StatefulSet 中 `storageClassName` 的注释。
|
||||
4. 后端镜像 `aiops-backend:latest` 已构建并推送到集群可访问的镜像仓库(或本地 `kind load docker-image` / `minikube image load`)。
|
||||
|
||||
## 部署步骤
|
||||
|
||||
按顺序 apply(资源间存在依赖:Secret → 数据库 → 后端 → Ingress):
|
||||
|
||||
```bash
|
||||
cd deploy/k8s
|
||||
|
||||
# 1. 命名空间(必须最先)
|
||||
kubectl apply -f namespace.yaml
|
||||
|
||||
# 2. 配置 + 密码(ConfigMap / Secret)
|
||||
kubectl apply -f configmap.yaml
|
||||
|
||||
# 3. MySQL(启动后自动建库 aiops 与用户 aiops)
|
||||
kubectl apply -f mysql.yaml
|
||||
|
||||
# 4. Redis
|
||||
kubectl apply -f redis.yaml
|
||||
|
||||
# 5. 等待数据库就绪
|
||||
kubectl -n devops rollout status statefulset/mysql
|
||||
kubectl -n devops rollout status statefulset/redis
|
||||
|
||||
# 6. 后端
|
||||
kubectl apply -f backend.yaml
|
||||
kubectl -n devops rollout status deployment/aiops-backend
|
||||
|
||||
# 7. Ingress(部署前修改 host 与 ingressClassName)
|
||||
kubectl apply -f ingress.yaml
|
||||
```
|
||||
|
||||
一键全量部署(文件名按字典序,namespace 会最先应用):
|
||||
|
||||
```bash
|
||||
kubectl apply -f deploy/k8s/
|
||||
```
|
||||
|
||||
## 访问
|
||||
|
||||
- 将 Ingress 中的 `host`(默认 `aiops.local`)解析到 Ingress Controller 的入口 IP:
|
||||
```bash
|
||||
echo "<INGRESS_IP> aiops.local" | sudo tee -a /etc/hosts
|
||||
```
|
||||
- 浏览器打开 `http://aiops.local` 即前端;API 在 `http://aiops.local/api`。
|
||||
|
||||
## 常用运维命令
|
||||
|
||||
```bash
|
||||
# 查看所有资源
|
||||
kubectl -n devops get all,configmap,secret,ingress,pvc
|
||||
|
||||
# 查看后端日志
|
||||
kubectl -n devops logs -f deployment/aiops-backend
|
||||
|
||||
# 进入 MySQL
|
||||
kubectl -n devops exec -it mysql-0 -- mysql -uaiops -paiops_pass_2026 aiops
|
||||
|
||||
# 进入 Redis
|
||||
kubectl -n devops exec -it redis-0 -- redis-cli
|
||||
|
||||
# 进入后端容器
|
||||
kubectl -n devops exec -it deployment/aiops-backend -- sh
|
||||
|
||||
# 查看 PVC 绑定状态
|
||||
kubectl -n devops get pvc
|
||||
```
|
||||
|
||||
## 配置与密码
|
||||
|
||||
| 项目 | 来源 | 值 |
|
||||
|------|------|----|
|
||||
| MySQL 业务账号 | Secret `aiops-secret` | 用户 `aiops` / 密码 `aiops_pass_2026` / 库 `aiops` |
|
||||
| MySQL root | Secret `aiops-secret` | `aiops_root_2026` |
|
||||
| JWT | Secret `aiops-secret` | `jwt-secret`(生产请替换为强随机值) |
|
||||
| Redis | 无密码 | db `0` |
|
||||
|
||||
> ⚠️ 生产环境请勿使用仓库内默认密码。修改 `configmap.yaml` 中 Secret 的值后重新 apply,
|
||||
> 或使用 `kubectl create secret` 覆盖。
|
||||
|
||||
## 资源限额
|
||||
|
||||
| 组件 | CPU 请求/上限 | 内存请求/上限 |
|
||||
|------|---------------|---------------|
|
||||
| backend | 100m / 500m | 512Mi / 1Gi |
|
||||
| mysql | 250m / 1 | 1Gi / 2Gi |
|
||||
| redis | 50m / 250m | 128Mi / 256Mi |
|
||||
|
||||
## 关于配置的环境变量占位
|
||||
|
||||
`config.yaml`(位于 ConfigMap)中 DB/Redis 的 `host/port/user/password/dbname`、JWT `secret`
|
||||
均写成 `${ENV_VAR}` 占位形式,实际值在 `backend.yaml` 的 `env` 段注入:
|
||||
非敏感的 host/port/user/dbname 直接给值(指向 K8s Service),密码则 `valueFrom` 引用 Secret。
|
||||
|
||||
后端基于 viper 读取配置。若 `${VAR}` 占位需要由环境变量直接替换嵌套键
|
||||
(如 `DB_PASSWORD` → `database.password`),建议在程序启动时设置键名映射:
|
||||
|
||||
```go
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
```
|
||||
|
||||
否则可改为在 `config.yaml` 中直接写明连接串、密码仅由 Secret 注入。两种方式均可,
|
||||
当前清单采用「环境变量占位 + Secret」的标准 K8s 模式。
|
||||
|
||||
## 清理
|
||||
|
||||
```bash
|
||||
kubectl delete -f deploy/k8s/
|
||||
# 持久卷需单独删除(PVC 由 StatefulSet 保护,删除 STS 后 PVC 仍保留)
|
||||
kubectl -n devops delete pvc --all
|
||||
```
|
||||
@@ -0,0 +1,116 @@
|
||||
# backend.yaml — AIOps 后端 (Deployment + Service)
|
||||
# ----------------------------------------------------------------------------
|
||||
# - 镜像 aiops-backend:latest(前端通过 go:embed 内嵌进同一二进制)
|
||||
# - 暴露两个端口:
|
||||
# 8080 = API + WebSocket
|
||||
# 80 = go:embed 前端 (SPA 静态资源)
|
||||
# - 配置: ConfigMap aiops-config 挂载到 /app/configs/config.yaml
|
||||
# - 密码: Secret aiops-secret 以环境变量注入(DB_PASSWORD / JWT_SECRET)
|
||||
# - Service: ClusterIP,对外暴露 80 与 8080
|
||||
#
|
||||
# 部署: kubectl apply -f backend.yaml
|
||||
# ----------------------------------------------------------------------------
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: aiops-backend
|
||||
namespace: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: aiops
|
||||
app.kubernetes.io/component: backend
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: aiops
|
||||
app.kubernetes.io/component: backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: aiops
|
||||
app.kubernetes.io/component: backend
|
||||
spec:
|
||||
containers:
|
||||
- name: aiops-backend
|
||||
image: aiops-backend:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
env:
|
||||
# ---- 数据库连接参数(对应 config.yaml 的 ${DB_*} 占位)----
|
||||
- {name: DB_HOST, value: mysql}
|
||||
- {name: DB_PORT, value: "3306"}
|
||||
- {name: DB_USER, value: aiops}
|
||||
- {name: DB_NAME, value: aiops}
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: aiops-secret
|
||||
key: database-password
|
||||
# ---- Redis 连接参数(本环境无密码)----
|
||||
- {name: REDIS_HOST, value: redis}
|
||||
- {name: REDIS_PORT, value: "6379"}
|
||||
- {name: REDIS_PASSWORD, value: ""}
|
||||
# ---- JWT ----
|
||||
- name: JWT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: aiops-secret
|
||||
key: jwt-secret
|
||||
- {name: TZ, value: Asia/Shanghai}
|
||||
ports:
|
||||
- {name: api, containerPort: 8080} # API + WebSocket
|
||||
- {name: web, containerPort: 80} # go:embed 前端
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: api
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: api
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /app/configs
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: aiops-config
|
||||
---
|
||||
# Service — 对内暴露 80 (前端) 与 8080 (API)
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: aiops-backend
|
||||
namespace: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: aiops
|
||||
app.kubernetes.io/component: backend
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app.kubernetes.io/name: aiops
|
||||
app.kubernetes.io/component: backend
|
||||
ports:
|
||||
- {name: api, port: 8080, targetPort: 8080}
|
||||
- {name: web, port: 80, targetPort: 80}
|
||||
@@ -0,0 +1,78 @@
|
||||
# configmap.yaml — 后端配置 (ConfigMap) + 敏感信息 (Secret)
|
||||
# ----------------------------------------------------------------------------
|
||||
# ConfigMap aiops-config:
|
||||
# - 内含 config.yaml,DB/Redis 连接信息以环境变量占位(${VAR})。
|
||||
# - 后端 Deployment 将其挂载到 /app/configs/config.yaml(viper 搜索路径 ./configs)。
|
||||
#
|
||||
# Secret aiops-secret:
|
||||
# - 存放 MySQL 密码与 JWT 密钥(明文敏感信息不放 ConfigMap)。
|
||||
# - 由 backend Deployment / mysql StatefulSet 以环境变量注入。
|
||||
#
|
||||
# 部署: kubectl apply -f configmap.yaml
|
||||
# ----------------------------------------------------------------------------
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: aiops-config
|
||||
namespace: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: aiops
|
||||
app.kubernetes.io/component: backend
|
||||
data:
|
||||
config.yaml: |
|
||||
# AIOps 后端配置
|
||||
# DB/Redis 连接通过环境变量注入(见 backend Deployment 的 env 段)。
|
||||
# 敏感字段 (password / jwt) 由 Secret aiops-secret 提供。
|
||||
# 注意: viper.AutomaticEnv 默认不替换嵌套键中的点(.),如需 DATABASE_HOST ->
|
||||
# database.host 生效,请在 backend 启动时设置:
|
||||
# viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
mode: release
|
||||
port: "8080"
|
||||
log_level: info
|
||||
|
||||
# ---- 数据库 (MySQL) ----
|
||||
database:
|
||||
driver: mysql
|
||||
host: "${DB_HOST}" # -> mysql (k8s Service)
|
||||
port: 3306
|
||||
user: "${DB_USER}" # -> aiops
|
||||
password: "${DB_PASSWORD}" # <- Secret aiops-secret (database-password)
|
||||
dbname: "${DB_NAME}" # -> aiops
|
||||
charset: utf8mb4
|
||||
max_conn: 100
|
||||
max_idle: 10
|
||||
|
||||
# ---- Redis ----
|
||||
redis:
|
||||
driver: redis # redka(内嵌) / redis(外部)
|
||||
host: "${REDIS_HOST}" # -> redis (k8s Service)
|
||||
port: 6379
|
||||
password: "${REDIS_PASSWORD}" # 本环境 Redis 无密码,留空
|
||||
db: 0
|
||||
|
||||
# ---- JWT ----
|
||||
jwt:
|
||||
secret: "${JWT_SECRET}" # <- Secret aiops-secret (jwt-secret)
|
||||
expire_hour: 24
|
||||
|
||||
# ---- WebSocket ----
|
||||
websocket:
|
||||
read_buffer_size: 1024
|
||||
write_buffer_size: 1024
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: aiops-secret
|
||||
namespace: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: aiops
|
||||
type: Opaque
|
||||
stringData:
|
||||
# MySQL 业务账号密码
|
||||
database-password: "aiops_pass_2026"
|
||||
# MySQL root 密码(StatefulSet 初始化用)
|
||||
mysql-root-password: "aiops_root_2026"
|
||||
# JWT 签名密钥(生产请替换为强随机值)
|
||||
jwt-secret: "aiops-jwt-secret-change-in-production-2026"
|
||||
@@ -0,0 +1,59 @@
|
||||
# ingress.yaml — Ingress 入口路由 (nginx-ingress)
|
||||
# ----------------------------------------------------------------------------
|
||||
# 路由规则:
|
||||
# /api/* -> aiops-backend:8080 (后端 API)
|
||||
# /ws/* -> aiops-backend:8080 (WebSocket 长连接)
|
||||
# / -> aiops-backend:80 (go:embed 前端 SPA)
|
||||
#
|
||||
# 前提: 集群已安装 nginx Ingress Controller。
|
||||
# 部署前请修改 host (aiops.local) 与 ingressClassName 为实际值。
|
||||
# 部署: kubectl apply -f ingress.yaml
|
||||
# ----------------------------------------------------------------------------
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: aiops-ingress
|
||||
namespace: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: aiops
|
||||
annotations:
|
||||
# WebSocket 长连接支持(/ws)
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||
# 文件上传大小(与后端 upload.max_size 配合)
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
|
||||
# 显式转发 WebSocket 升级头
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
spec:
|
||||
ingressClassName: nginx # 按集群实际 IngressClass 调整
|
||||
rules:
|
||||
- host: aiops.local # TODO: 修改为实际访问域名
|
||||
http:
|
||||
paths:
|
||||
# ---- API ----
|
||||
- path: /api
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: aiops-backend
|
||||
port:
|
||||
number: 8080
|
||||
# ---- WebSocket ----
|
||||
- path: /ws
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: aiops-backend
|
||||
port:
|
||||
number: 8080
|
||||
# ---- 前端 (go:embed, 默认兜底) ----
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: aiops-backend
|
||||
port:
|
||||
number: 80
|
||||
@@ -0,0 +1,136 @@
|
||||
# mysql.yaml — MySQL 8.0 数据库 (StatefulSet + Service + 持久化卷)
|
||||
# ----------------------------------------------------------------------------
|
||||
# 组件:
|
||||
# - mysql-headless (Headless Service): 为 StatefulSet 提供稳定网络标识 mysql-0
|
||||
# - mysql (ClusterIP Service): 供后端以 mysql:3306 连接
|
||||
# - mysql (StatefulSet): 单实例 MySQL 8.0
|
||||
# 账号: 用户 aiops / 密码 aiops_pass_2026 / 数据库 aiops (密码来自 aiops-secret)
|
||||
# 持久化: volumeClaimTemplates 8Gi (依赖集群 StorageClass 动态供应)
|
||||
#
|
||||
# 部署: kubectl apply -f mysql.yaml
|
||||
# ----------------------------------------------------------------------------
|
||||
---
|
||||
# Headless Service — StatefulSet 稳定标识
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: mysql-headless
|
||||
namespace: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: mysql
|
||||
app.kubernetes.io/component: database
|
||||
spec:
|
||||
clusterIP: None
|
||||
selector:
|
||||
app.kubernetes.io/name: mysql
|
||||
ports:
|
||||
- name: mysql
|
||||
port: 3306
|
||||
targetPort: 3306
|
||||
---
|
||||
# ClusterIP Service — 供应用连接
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: mysql
|
||||
namespace: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: mysql
|
||||
app.kubernetes.io/component: database
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app.kubernetes.io/name: mysql
|
||||
ports:
|
||||
- name: mysql
|
||||
port: 3306
|
||||
targetPort: 3306
|
||||
---
|
||||
# StatefulSet
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: mysql
|
||||
namespace: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: mysql
|
||||
app.kubernetes.io/component: database
|
||||
spec:
|
||||
serviceName: mysql-headless
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: mysql
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: mysql
|
||||
spec:
|
||||
containers:
|
||||
- name: mysql
|
||||
image: mysql:8.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
env:
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: aiops-secret
|
||||
key: mysql-root-password
|
||||
- name: MYSQL_DATABASE
|
||||
value: aiops
|
||||
- name: MYSQL_USER
|
||||
value: aiops
|
||||
- name: MYSQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: aiops-secret
|
||||
key: database-password
|
||||
- name: TZ
|
||||
value: Asia/Shanghai
|
||||
args:
|
||||
# 字符集
|
||||
- --character-set-server=utf8mb4
|
||||
- --collation-server=utf8mb4_unicode_ci
|
||||
# 兼容旧客户端认证方式(8.0 默认 caching_sha2_password)
|
||||
- --default-authentication-plugin=mysql_native_password
|
||||
ports:
|
||||
- name: mysql
|
||||
containerPort: 3306
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- 'mysqladmin ping -h 127.0.0.1 -uroot -p"$MYSQL_ROOT_PASSWORD"'
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- 'mysqladmin ping -h 127.0.0.1 -uroot -p"$MYSQL_ROOT_PASSWORD"'
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
resources:
|
||||
requests:
|
||||
cpu: 250m
|
||||
memory: 1Gi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 2Gi
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/lib/mysql
|
||||
# ---- 持久化卷 (8Gi) ----
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 8Gi
|
||||
# storageClassName: standard # 按集群实际 StorageClass 调整,留空使用默认
|
||||
@@ -0,0 +1,12 @@
|
||||
# namespace.yaml — 创建 devops 命名空间
|
||||
# 所有 AIOps 资源(MySQL / Redis / 后端 / Ingress)统一部署在该命名空间下。
|
||||
# 必须最先 apply,其它资源依赖该命名空间存在。
|
||||
# 部署: kubectl apply -f namespace.yaml
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: aiops
|
||||
app.kubernetes.io/part-of: aiops
|
||||
@@ -0,0 +1,111 @@
|
||||
# redis.yaml — Redis 7 缓存 (StatefulSet + Service + 持久化卷)
|
||||
# ----------------------------------------------------------------------------
|
||||
# 组件:
|
||||
# - redis-headless (Headless Service): StatefulSet 稳定标识 redis-0
|
||||
# - redis (ClusterIP Service): 供后端以 redis:6379 连接
|
||||
# - redis (StatefulSet): 单实例 Redis 7,无密码,db 0
|
||||
# 持久化: volumeClaimTemplates 2Gi + AOF/RDB 落盘
|
||||
#
|
||||
# 部署: kubectl apply -f redis.yaml
|
||||
# ----------------------------------------------------------------------------
|
||||
---
|
||||
# Headless Service — StatefulSet 稳定标识
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis-headless
|
||||
namespace: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: redis
|
||||
app.kubernetes.io/component: cache
|
||||
spec:
|
||||
clusterIP: None
|
||||
selector:
|
||||
app.kubernetes.io/name: redis
|
||||
ports:
|
||||
- name: redis
|
||||
port: 6379
|
||||
targetPort: 6379
|
||||
---
|
||||
# ClusterIP Service — 供应用连接
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis
|
||||
namespace: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: redis
|
||||
app.kubernetes.io/component: cache
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app.kubernetes.io/name: redis
|
||||
ports:
|
||||
- name: redis
|
||||
port: 6379
|
||||
targetPort: 6379
|
||||
---
|
||||
# StatefulSet
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: redis
|
||||
namespace: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: redis
|
||||
app.kubernetes.io/component: cache
|
||||
spec:
|
||||
serviceName: redis-headless
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: redis
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: ["redis-server"]
|
||||
args:
|
||||
- --appendonly yes # 开启 AOF
|
||||
- --save 60 1000 # RDB: 60s 内 1000 次变更快照
|
||||
- --databases 1 # 仅使用 db 0
|
||||
- --maxmemory 256mb
|
||||
- --maxmemory-policy allkeys-lru
|
||||
ports:
|
||||
- name: redis
|
||||
containerPort: 6379
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["redis-cli", "ping"]
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["redis-cli", "ping"]
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 250m
|
||||
memory: 256Mi
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
# ---- 持久化卷 (2Gi) ----
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
# storageClassName: standard # 按集群实际 StorageClass 调整
|
||||
Reference in new issue
Block a user