refactor: rename deploy/k8s to deploy/kubernetes; add SetEnvKeyReplacer for env var support in K8s
This commit is contained in:
1 parent
d581441fa8
commit
bbf06204cc
15 files changed
+226
-44
No files matched your search
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: devops
|
||||
labels:
|
||||
app.kubernetes.io/name: aiops
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
Reference in new issue
Block a user