refactor: rename deploy/k8s to deploy/kubernetes; add SetEnvKeyReplacer for env var support in K8s

This commit is contained in:
attacker committed 2026-06-24 04:02:26 +00:00
1 parent d581441fa8
commit bbf06204cc
15 files changed
+226 -44

No files matched your search

+151
View File
@@ -0,0 +1,151 @@
# AIOps Kubernetes 部署
AIOps 平台在 Kubernetes 上的部署清单(Go/Gin 后端 + go:embed 前端 + MySQL 8.0 + Redis 7)。
**单容器架构**:前端通过 `go:embed` 嵌入后端二进制,一个容器同时服务 API + WebSocket + SPA 静态资源,端口统一 8080。
所有资源部署在 **`devops`** 命名空间。
## 目录结构
| 文件 | 说明 |
|------|------|
| `namespace.yaml` | `devops` 命名空间 |
| `secret.yaml` | MySQL/JWT 密码(Secret) |
| `configmap.yaml` | 后端 `config.yaml`(ConfigMap) |
| `mysql.yaml` | MySQL 8.0 StatefulSet + Headless Service + 10Gi 持久卷 |
| `redis.yaml` | Redis 7 StatefulSet + Headless Service + 2Gi 持久卷 |
| `deployment.yaml` | AIOps Deployment(embed 单端口 8080)+ NodePort Service (30080) |
| `ingress.yaml` | Ingress:所有流量 → aiops:8080(含 WebSocket 支持) |
## 架构
```
NodePort:30080 / Ingress
│
▼
┌─── aiops (Deployment) ───┐
│ 单端口 8080: │
│ • API (/api/*) │
│ • WebSocket (/ws/*) │
│ • 前端 SPA (go:embed) │
└───────────┬───────────────┘
│
┌──────────────┼──────────────┐
▼ ▼
MySQL 8.0 Redis 7
(StatefulSet) (StatefulSet)
mysql:3306 redis:6379
10Gi PV 2Gi PV
```
## 快速部署
### 方式一:run.sh 一键部署(推荐)
```bash
# 构建镜像 + 部署全部资源
./run.sh k8s deploy
# 查看状态
./run.sh k8s status
# 查看日志
./run.sh k8s logs
# 更新(重新构建镜像 + 滚动更新)
./run.sh k8s upgrade
# 清理
./run.sh k8s delete
```
### 方式二:手动 kubectl
```bash
cd deploy/kubernetes
# 1. 全量部署(文件按序: namespace → secret → configmap → mysql → redis → deployment)
kubectl apply -f namespace.yaml
kubectl apply -f secret.yaml
kubectl apply -f configmap.yaml
kubectl apply -f mysql.yaml
kubectl apply -f redis.yaml
# 2. 等待数据库就绪
kubectl -n devops rollout status statefulset/mysql
kubectl -n devops rollout status statefulset/redis
# 3. 构建镜像(在本地)
cd ../..
docker build -f Dockerfile.embed -t aiops:embed .
# 4. 部署应用
kubectl apply -f deployment.yaml
kubectl -n devops rollout status deployment/aiops
# 5. Ingress(按需修改 host)
kubectl apply -f ingress.yaml
```
## 访问
```bash
# NodePort 方式
curl http://<NODE_IP>:30080/health
# 或配置 Ingress host
echo "<INGRESS_IP> aiops.local" | sudo tee -a /etc/hosts
# 浏览器: http://aiops.local
```
## 常用运维命令
```bash
# 查看所有资源
kubectl -n devops get all,pvc,configmap,secret
# 查看应用日志
kubectl -n devops logs -f deployment/aiops
# 进入应用容器
kubectl -n devops exec -it deployment/aiops -- bash
# 进入 MySQL
kubectl -n devops exec -it mysql-0 -- mysql -uaiops -paiops_pass_2026 aiops
# 滚动更新(重新构建镜像后)
kubectl -n devops rollout restart deployment/aiops
# 查看 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` | `aiops-jwt-secret-key-2026` |
| Redis | 无密码 | db `0` |
> ⚠️ 生产环境请修改 `secret.yaml` 和 `configmap.yaml` 中的默认密码。
## 资源限额
| 组件 | CPU 请求/上限 | 内存请求/上限 |
|------|---------------|---------------|
| aiops | 100m / 1 | 256Mi / 1Gi |
| mysql | 250m / 1 | 512Mi / 2Gi |
| redis | 50m / 250m | 128Mi / 256Mi |
## 清理
```bash
./run.sh k8s delete
# 或手动(持久卷需单独删)
kubectl delete -f deploy/kubernetes/
kubectl -n devops delete pvc --all
```
+36
View File
@@ -0,0 +1,36 @@
# config.yaml — 由 ConfigMap 挂载到 /app/config.yaml
# 注意:环境变量优先级高于此文件 (viper AutomaticEnv)
# 部署时通过 Deployment env 设置 DATABASE_HOST / REDIS_HOST 等覆盖以下值
# 此文件仅作为 fallback 默认值
apiVersion: v1
kind: ConfigMap
metadata:
name: aiops-config
namespace: devops
data:
config.yaml: |
mode: release
port: "8080"
log_level: info
database:
driver: mysql
host: 10.10.10.75
port: 3306
user: root
password: aiops_root_2026
dbname: aiops
charset: utf8mb4
max_conn: 100
max_idle: 10
redis:
driver: redis
host: 10.10.10.75
port: 6379
password: ""
db: 0
jwt:
secret: "aiops-jwt-secret-key-2026"
expire_hour: 24
+157
View File
@@ -0,0 +1,157 @@
# deployment.yaml — AIOps 应用 (embed 前端嵌入后端, 单容器单端口)
# ----------------------------------------------------------------------------
# - 镜像 aiops:embed(前端通过 go:embed 内嵌进同一二进制)
# - 单端口 8080 = API + WebSocket + 前端 SPA 静态资源
# - 配置优先级: 环境变量 > config.yaml > 默认值 (viper AutomaticEnv)
# - 环境变量命名: 配置键 database.host → DATABASE_HOST (全大写, 点变下划线)
# - Service: NodePort 30080 → 8080
#
# 部署: kubectl apply -f deployment.yaml
# ----------------------------------------------------------------------------
apiVersion: apps/v1
kind: Deployment
metadata:
name: aiops
namespace: devops
labels:
app.kubernetes.io/name: aiops
app.kubernetes.io/component: app
spec:
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app.kubernetes.io/name: aiops
app.kubernetes.io/component: app
template:
metadata:
labels:
app.kubernetes.io/name: aiops
app.kubernetes.io/component: app
spec:
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
containers:
- name: aiops
image: aiops-aiops:latest
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
# ── 运行时环境变量 ──
# viper AutomaticEnv() 自动将 config.yaml 的键映射为环境变量:
# database.host → DATABASE_HOST
# database.port → DATABASE_PORT
# 依此类推
# 优先级: 环境变量 > config.yaml > 代码默认值
env:
# ── 基础配置 ──
- name: TZ
value: Asia/Shanghai
- name: MODE
value: "release"
- name: PORT
value: "8080"
- name: LOG_LEVEL
value: "info"
# ── 数据库 (MySQL) ──
- name: DATABASE_DRIVER
value: "mysql"
- name: DATABASE_HOST
value: "10.10.10.75"
- name: DATABASE_PORT
value: "3306"
- name: DATABASE_USER
value: "root"
- name: DATABASE_PASSWORD
value: "aiops_root_2026"
- name: DATABASE_DBNAME
value: "aiops"
- name: DATABASE_CHARSET
value: "utf8mb4"
- name: DATABASE_MAX_CONN
value: "100"
- name: DATABASE_MAX_IDLE
value: "10"
# ── 缓存 (Redis) ──
- name: REDIS_DRIVER
value: "redis"
- name: REDIS_HOST
value: "10.10.10.75"
- name: REDIS_PORT
value: "6379"
- name: REDIS_PASSWORD
value: ""
- name: REDIS_DB
value: "0"
# ── JWT 认证 ──
- name: JWT_SECRET
value: "aiops-jwt-secret-key-2026"
- name: JWT_EXPIRE_HOUR
value: "24"
volumeMounts:
- name: config
mountPath: /app/config.yaml
subPath: config.yaml
readOnly: true
- name: uploads
mountPath: /app/uploads
- name: data
mountPath: /app/data
readinessProbe:
httpGet:
path: /version
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
livenessProbe:
httpGet:
path: /version
port: 8080
initialDelaySeconds: 15
periodSeconds: 30
timeoutSeconds: 5
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
volumes:
- name: config
configMap:
name: aiops-config
- name: uploads
emptyDir: {}
- name: data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: aiops
namespace: devops
labels:
app.kubernetes.io/name: aiops
spec:
type: NodePort
selector:
app.kubernetes.io/name: aiops
app.kubernetes.io/component: app
ports:
- name: http
port: 8080
targetPort: 8080
nodePort: 30080
protocol: TCP
+39
View File
@@ -0,0 +1,39 @@
# ingress.yaml — Ingress 入口路由 (nginx-ingress)
# ----------------------------------------------------------------------------
# 路由规则 (embed 模式: 所有流量 → aiops:8080):
# /api/* -> aiops:8080 (后端 API)
# /ws/* -> aiops:8080 (WebSocket 长连接)
# / -> aiops:8080 (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:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
spec:
ingressClassName: nginx
rules:
- host: aiops.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: aiops
port:
number: 8080
+58
View File
@@ -0,0 +1,58 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
namespace: devops
labels:
app.kubernetes.io/name: mysql
spec:
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
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "aiops_root_2026"
- name: MYSQL_DATABASE
value: aiops
- name: TZ
value: Asia/Shanghai
args:
- --default-authentication-plugin=mysql_native_password
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
readinessProbe:
exec:
command: ["sh", "-c", "mysqladmin ping -h 127.0.0.1 -uroot -paiops_root_2026"]
initialDelaySeconds: 20
periodSeconds: 10
timeoutSeconds: 5
volumes:
- name: mysql-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: devops
spec:
selector:
app.kubernetes.io/name: mysql
ports:
- port: 3306
targetPort: 3306
+6
View File
@@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: devops
labels:
app.kubernetes.io/name: aiops
+150
View File
@@ -0,0 +1,150 @@
# quick-deploy.yaml — AIOps 快速部署 (ConfigMap + Deployment, 含 Service)
# 部署: kubectl apply -f quick-deploy.yaml
# 注意: 此文件自包含, 不依赖其他 YAML
---
apiVersion: v1
kind: ConfigMap
metadata:
name: aiops-config
namespace: devops
data:
config.yaml: |
mode: release
port: "8080"
log_level: info
database:
driver: mysql
host: 10.10.10.75
port: 3306
user: root
password: aiops_root_2026
dbname: aiops
charset: utf8mb4
max_conn: 100
max_idle: 10
redis:
driver: redis
host: 10.10.10.75
port: 6379
password: ""
db: 0
jwt:
secret: "aiops-jwt-secret-key-2026"
expire_hour: 24
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: aiops
namespace: devops
labels:
app.kubernetes.io/name: aiops
app.kubernetes.io/component: app
spec:
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app.kubernetes.io/name: aiops
app.kubernetes.io/component: app
template:
metadata:
labels:
app.kubernetes.io/name: aiops
app.kubernetes.io/component: app
spec:
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
containers:
- name: aiops
image: aiops:embed
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
# ── 环境变量 (优先级高于 config.yaml) ──
env:
- name: TZ
value: Asia/Shanghai
- name: MODE
value: "release"
- name: PORT
value: "8080"
- name: LOG_LEVEL
value: "info"
- name: DATABASE_DRIVER
value: "mysql"
- name: DATABASE_HOST
value: "10.10.10.75"
- name: DATABASE_PORT
value: "3306"
- name: DATABASE_USER
value: "root"
- name: DATABASE_PASSWORD
value: "aiops_root_2026"
- name: DATABASE_DBNAME
value: "aiops"
- name: DATABASE_CHARSET
value: "utf8mb4"
- name: DATABASE_MAX_CONN
value: "100"
- name: DATABASE_MAX_IDLE
value: "10"
- name: REDIS_DRIVER
value: "redis"
- name: REDIS_HOST
value: "10.10.10.75"
- name: REDIS_PORT
value: "6379"
- name: REDIS_PASSWORD
value: ""
- name: REDIS_DB
value: "0"
- name: JWT_SECRET
value: "aiops-jwt-secret-key-2026"
- name: JWT_EXPIRE_HOUR
value: "24"
volumeMounts:
- name: config
mountPath: /app/config.yaml
subPath: config.yaml
readOnly: true
- name: uploads
mountPath: /app/uploads
- name: data
mountPath: /app/data
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
volumes:
- name: config
configMap:
name: aiops-config
- name: uploads
emptyDir: {}
- name: data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: aiops
namespace: devops
spec:
type: NodePort
selector:
app.kubernetes.io/name: aiops
ports:
- port: 8080
targetPort: 8080
nodePort: 30080
+40
View File
@@ -0,0 +1,40 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: devops
labels:
app.kubernetes.io/name: redis
spec:
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
ports:
- containerPort: 6379
readinessProbe:
exec:
command: ["redis-cli", "ping"]
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: devops
spec:
selector:
app.kubernetes.io/name: redis
ports:
- port: 6379
targetPort: 6379
+10
View File
@@ -0,0 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: aiops-secret
namespace: devops
type: Opaque
stringData:
mysql-root-password: "aiops_root_2026"
mysql-password: "aiops_pass_2026"
jwt-secret: "aiops-jwt-secret-key-2026"