diff --git a/CLAUDE.md b/CLAUDE.md index 1f6e66d..35b1907 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -73,7 +73,7 @@ ./run.sh k8s delete # 清理资源(保留 PVC) ``` -**K8s 部署文件** (`deploy/k8s/`): namespace.yaml / secret.yaml / configmap.yaml / mysql.yaml / redis.yaml / deployment.yaml / ingress.yaml +**K8s 部署文件** (`deploy/kubernetes/`): namespace.yaml / secret.yaml / configmap.yaml / mysql.yaml / redis.yaml / deployment.yaml / ingress.yaml / quick-deploy.yaml > ⚠️ 健康检查用 `/version`(无 DB 依赖),不用 `/health`(启动早期可能不响应)。 @@ -200,7 +200,7 @@ aiops/ │ ├── task/ # 远程任务执行器 │ └── reporter/ # HTTP 上报 │ -├── deploy/k8s/ # K8s 部署清单 (devops 命名空间) +├── deploy/kubernetes/ # K8s 部署清单 (devops 命名空间) ├── Dockerfile.embed # 4 阶段 Embed 镜像 (前端→后端→Agent→Runtime) ├── docker-compose.yml # 4 容器部署 (mysql+redis+backend+frontend) ├── run.sh # 统一入口脚本 diff --git a/README.md b/README.md index 7356901..2522b5a 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ aiops/ │ ├── task/ # 远程任务执行 │ └── reporter/ # HTTP 上报 │ -├── deploy/k8s/ # Kubernetes 部署清单 +├── deploy/kubernetes/ # Kubernetes 部署清单 │ ├── namespace.yaml # devops 命名空间 │ ├── secret.yaml # 密钥 │ ├── configmap.yaml # 配置 diff --git a/backend/cmd/main.go b/backend/cmd/main.go index 9e601d1..f7b89d9 100644 --- a/backend/cmd/main.go +++ b/backend/cmd/main.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "os/signal" + "strings" "syscall" "time" @@ -245,6 +246,7 @@ func loadConfig() *config.Config { } // 环境变量覆盖 // Logan.Li + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) viper.AutomaticEnv() // CLI flags 覆盖(最高优先级)// Logan.Li diff --git a/deploy/README.md b/deploy/README.md index 663d45d..d16d968 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -89,10 +89,10 @@ journalctl -u aiops -f # 日志 ```bash cd /srv/aiops -kubectl apply -f deploy/k8s/ +kubectl apply -f deploy/kubernetes/ ``` -详见 [deploy/k8s/README.md](../k8s/README.md) +详见 [deploy/kubernetes/README.md](../kubernetes/README.md) --- diff --git a/deploy/k8s/configmap.yaml b/deploy/k8s/configmap.yaml deleted file mode 100644 index 2c20764..0000000 --- a/deploy/k8s/configmap.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: aiops-config - namespace: devops -data: - config.yaml: | - mode: release - port: "8080" - log_level: info - - database: - driver: mysql - host: mysql - port: 3306 - user: aiops - password: aiops_pass_2026 - dbname: aiops - charset: utf8mb4 - max_conn: 100 - max_idle: 10 - - redis: - driver: redis - host: redis - port: 6379 - password: "" - db: 0 - - jwt: - secret: "aiops-jwt-secret-key-2026" - expire_hour: 24 diff --git a/deploy/k8s/README.md b/deploy/kubernetes/README.md similarity index 98% rename from deploy/k8s/README.md rename to deploy/kubernetes/README.md index af87348..9b63758 100644 --- a/deploy/k8s/README.md +++ b/deploy/kubernetes/README.md @@ -63,7 +63,7 @@ AIOps 平台在 Kubernetes 上的部署清单(Go/Gin 后端 + go:embed 前端 ### 方式二:手动 kubectl ```bash -cd deploy/k8s +cd deploy/kubernetes # 1. 全量部署(文件按序: namespace → secret → configmap → mysql → redis → deployment) kubectl apply -f namespace.yaml @@ -146,6 +146,6 @@ kubectl -n devops get pvc ./run.sh k8s delete # 或手动(持久卷需单独删) -kubectl delete -f deploy/k8s/ +kubectl delete -f deploy/kubernetes/ kubectl -n devops delete pvc --all ``` diff --git a/deploy/k8s/quick-deploy.yaml b/deploy/kubernetes/configmap.yaml similarity index 56% rename from deploy/k8s/quick-deploy.yaml rename to deploy/kubernetes/configmap.yaml index 4e53f7c..b4195a9 100644 --- a/deploy/k8s/quick-deploy.yaml +++ b/deploy/kubernetes/configmap.yaml @@ -1,3 +1,7 @@ +# config.yaml — 由 ConfigMap 挂载到 /app/config.yaml +# 注意:环境变量优先级高于此文件 (viper AutomaticEnv) +# 部署时通过 Deployment env 设置 DATABASE_HOST / REDIS_HOST 等覆盖以下值 +# 此文件仅作为 fallback 默认值 apiVersion: v1 kind: ConfigMap metadata: @@ -8,20 +12,25 @@ data: mode: release port: "8080" log_level: info + database: driver: mysql - host: 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: redis + host: 10.10.10.75 port: 6379 password: "" db: 0 + jwt: secret: "aiops-jwt-secret-key-2026" expire_hour: 24 diff --git a/deploy/k8s/deployment.yaml b/deploy/kubernetes/deployment.yaml similarity index 58% rename from deploy/k8s/deployment.yaml rename to deploy/kubernetes/deployment.yaml index 360e95a..cc4ece3 100644 --- a/deploy/k8s/deployment.yaml +++ b/deploy/kubernetes/deployment.yaml @@ -2,12 +2,12 @@ # ---------------------------------------------------------------------------- # - 镜像 aiops:embed(前端通过 go:embed 内嵌进同一二进制) # - 单端口 8080 = API + WebSocket + 前端 SPA 静态资源 -# - 配置: ConfigMap aiops-config 挂载到 /app/config.yaml +# - 配置优先级: 环境变量 > config.yaml > 默认值 (viper AutomaticEnv) +# - 环境变量命名: 配置键 database.host → DATABASE_HOST (全大写, 点变下划线) # - Service: NodePort 30080 → 8080 # # 部署: kubectl apply -f deployment.yaml # ---------------------------------------------------------------------------- ---- apiVersion: apps/v1 kind: Deployment metadata: @@ -42,9 +42,61 @@ spec: 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 @@ -54,6 +106,7 @@ spec: mountPath: /app/uploads - name: data mountPath: /app/data + readinessProbe: httpGet: path: /version diff --git a/deploy/k8s/ingress.yaml b/deploy/kubernetes/ingress.yaml similarity index 100% rename from deploy/k8s/ingress.yaml rename to deploy/kubernetes/ingress.yaml diff --git a/deploy/k8s/mysql.yaml b/deploy/kubernetes/mysql.yaml similarity index 100% rename from deploy/k8s/mysql.yaml rename to deploy/kubernetes/mysql.yaml diff --git a/deploy/k8s/namespace.yaml b/deploy/kubernetes/namespace.yaml similarity index 100% rename from deploy/k8s/namespace.yaml rename to deploy/kubernetes/namespace.yaml diff --git a/deploy/kubernetes/quick-deploy.yaml b/deploy/kubernetes/quick-deploy.yaml new file mode 100644 index 0000000..ce22cb7 --- /dev/null +++ b/deploy/kubernetes/quick-deploy.yaml @@ -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 diff --git a/deploy/k8s/redis.yaml b/deploy/kubernetes/redis.yaml similarity index 100% rename from deploy/k8s/redis.yaml rename to deploy/kubernetes/redis.yaml diff --git a/deploy/k8s/secret.yaml b/deploy/kubernetes/secret.yaml similarity index 100% rename from deploy/k8s/secret.yaml rename to deploy/kubernetes/secret.yaml diff --git a/run.sh b/run.sh index 9d855bb..3320bcb 100755 --- a/run.sh +++ b/run.sh @@ -550,7 +550,7 @@ cmd_binary() { # Kubernetes 部署 (embed 单容器模式) # ============================================================ K8S_NAMESPACE="devops" -K8S_MANIFEST_DIR="$SCRIPT_DIR/deploy/k8s" +K8S_MANIFEST_DIR="$SCRIPT_DIR/deploy/kubernetes" K8S_IMAGE="aiops:embed" K8S_NODE_PORT=30080