From 674221a0cb4c767a73c7086e109ce4a4be0adb99 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 2 Aug 2026 10:21:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20MySQL=E7=BA=B3=E5=85=A5K8s=E6=B8=85?= =?UTF-8?q?=E5=8D=95=E5=B9=B6=E5=BC=80=E6=94=BENodePort?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 38 +++++++++++++++- dev/deployment-lpt-ai.yaml | 7 +++ dev/lpt-logs-storage.yaml | 41 +++++++++++++++++ dev/mysql-backup-cronjob.yaml | 43 ++++++++++++++++++ dev/mysql-deployment.yaml | 71 +++++++++++++++++++++++++++++ dev/mysql-service.yaml | 16 +++++++ dev/mysql-storage.yaml | 83 ++++++++++++++++++++++++++++++++++ prod/deployment-lpt-ai.yaml | 7 +++ prod/lpt-logs-storage.yaml | 41 +++++++++++++++++ prod/mysql-backup-cronjob.yaml | 43 ++++++++++++++++++ prod/mysql-deployment.yaml | 71 +++++++++++++++++++++++++++++ prod/mysql-service.yaml | 16 +++++++ prod/mysql-storage.yaml | 83 ++++++++++++++++++++++++++++++++++ 13 files changed, 558 insertions(+), 2 deletions(-) create mode 100644 dev/lpt-logs-storage.yaml create mode 100644 dev/mysql-backup-cronjob.yaml create mode 100644 dev/mysql-deployment.yaml create mode 100644 dev/mysql-service.yaml create mode 100644 dev/mysql-storage.yaml create mode 100644 prod/lpt-logs-storage.yaml create mode 100644 prod/mysql-backup-cronjob.yaml create mode 100644 prod/mysql-deployment.yaml create mode 100644 prod/mysql-service.yaml create mode 100644 prod/mysql-storage.yaml diff --git a/README.md b/README.md index f265723..de73e66 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,12 @@ Kubernetes 部署清单,按环境隔离。 │ ├── service-lpt-fe.yaml │ ├── service-lpt-be.yaml │ ├── service-lpt-ai.yaml -│ └── configmap.yaml +│ ├── configmap.yaml +│ ├── mysql-deployment.yaml +│ ├── mysql-service.yaml +│ ├── mysql-storage.yaml +│ ├── mysql-backup-cronjob.yaml +│ └── lpt-logs-storage.yaml ├── prod/ │ ├── deployment-lpt-fe.yaml │ ├── deployment-lpt-be.yaml @@ -20,7 +25,12 @@ Kubernetes 部署清单,按环境隔离。 │ ├── service-lpt-fe.yaml │ ├── service-lpt-be.yaml │ ├── service-lpt-ai.yaml -│ └── configmap.yaml +│ ├── configmap.yaml +│ ├── mysql-deployment.yaml +│ ├── mysql-service.yaml +│ ├── mysql-storage.yaml +│ ├── mysql-backup-cronjob.yaml +│ └── lpt-logs-storage.yaml └── README.md ``` @@ -65,6 +75,29 @@ kubectl apply -f dev/ kubectl apply -f prod/ ``` +`kubectl apply -f dev/` / `prod/` 会同时创建 MySQL 的 Service、PV/PVC、Deployment 和每日备份 CronJob。 + +## 数据库(MySQL) + +MySQL 与业务服务一起由清单管理,每个 namespace 一个 `mysql` Deployment 和 NodePort Service(端口 3306),数据通过 hostPath PV/PVC 持久化。 + +| 项目 | dev | prod | +|------|-----|------| +| 镜像 | `mysql:9` | `mysql:8.0` | +| 数据目录 | `/vol1/lpt/mysql/dev/data` | `/vol1/lpt/mysql/prod/data` | +| 备份目录 | `/vol1/lpt/backup/dev` | `/vol1/lpt/backup/prod` | +| 日志目录 | `/vol1/lpt/logs/dev` | `/vol1/lpt/logs/prod` | +| 数据库 | `learning_progress_tracker` | `lpt_prod` | + +- LPT 数据统一放在 `/vol1/lpt` 下:MySQL 数据、备份、lpt-ai 日志(挂载到容器 `/app/data`,持久化 `logs.json`)。 +- PV 使用 hostPath 并绑定节点 `cw8505fnos`;新环境需要同步修改 `mysql-storage.yaml` / `lpt-logs-storage.yaml` 中的路径和节点名。 +- dev 使用 `mysql:9`;若 Docker Hub 不可达,可先在本机 containerd 打标签:`ctr -n k8s.io images tag docker.io/library/mysql:latest docker.io/library/mysql:9`。 +- root 密码来自 Secret `lpt-secrets.mysql-root-password`,应用当前以 root 连接数据库。 +- 表结构由 lpt-be 启动时的 Flyway 自动迁移,不需要手工建表。 +- 每日 03:00 通过 `mysql-backup` CronJob 执行 mysqldump,备份保留 14 天。 +- 历史数据已从 `/vol1/1000/mysql`、`/vol1/1000/mysql-my/LPT/prod/data` 迁移到 `/vol1/lpt`,旧目录保留未删除;更换节点前先 dump 备份,再恢复到新路径。 +- 局域网维护:MySQL Service 已开放 NodePort,dev 为 `30306`,prod 为 `30307`;不需要对外访问时可改回 ClusterIP。 + ## 日常更新 ```bash @@ -97,6 +130,7 @@ sudo docker exec traefik cat /etc/traefik/dynamic/k8s-lpt.yml | lpt-fe | 30080 | 30180 | | lpt-be (api) | 30082 | 30182 | | lpt-ai | ClusterIP | ClusterIP | +| mysql | 30306 | 30307 | ## 验证 ```bash diff --git a/dev/deployment-lpt-ai.yaml b/dev/deployment-lpt-ai.yaml index 4c705ca..9d95903 100644 --- a/dev/deployment-lpt-ai.yaml +++ b/dev/deployment-lpt-ai.yaml @@ -77,3 +77,10 @@ spec: periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 3 + volumeMounts: + - name: lpt-logs + mountPath: /app/data + volumes: + - name: lpt-logs + persistentVolumeClaim: + claimName: lpt-logs diff --git a/dev/lpt-logs-storage.yaml b/dev/lpt-logs-storage.yaml new file mode 100644 index 0000000..c57917e --- /dev/null +++ b/dev/lpt-logs-storage.yaml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: lpt-dev-logs + labels: + app: lpt + environment: dev +spec: + capacity: + storage: 5Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: "" + claimRef: + namespace: lpt-dev + name: lpt-logs + hostPath: + path: /vol1/lpt/logs/dev + type: DirectoryOrCreate + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - cw8505fnos +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: lpt-logs + namespace: lpt-dev +spec: + accessModes: + - ReadWriteOnce + storageClassName: "" + resources: + requests: + storage: 5Gi diff --git a/dev/mysql-backup-cronjob.yaml b/dev/mysql-backup-cronjob.yaml new file mode 100644 index 0000000..7f86b76 --- /dev/null +++ b/dev/mysql-backup-cronjob.yaml @@ -0,0 +1,43 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: mysql-backup + namespace: lpt-dev +spec: + schedule: "0 3 * * *" + concurrencyPolicy: Forbid + successfulJobsHistoryLimit: 7 + failedJobsHistoryLimit: 3 + jobTemplate: + spec: + backoffLimit: 2 + template: + spec: + restartPolicy: OnFailure + containers: + - name: mysqldump + image: mysql:9 + imagePullPolicy: IfNotPresent + command: + - /bin/sh + - -ec + - | + set -euo pipefail + TS=$(date +%Y%m%d-%H%M%S) + mysqldump --host=mysql --port=3306 --user=root --password="$MYSQL_ROOT_PASSWORD" \ + --all-databases --single-transaction --routines --events --triggers \ + > "/backup/lpt-dev-${TS}.sql" + find /backup -type f -name 'lpt-dev-*.sql' -mtime +14 -delete + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: lpt-secrets + key: mysql-root-password + volumeMounts: + - name: backup + mountPath: /backup + volumes: + - name: backup + persistentVolumeClaim: + claimName: mysql-backup diff --git a/dev/mysql-deployment.yaml b/dev/mysql-deployment.yaml new file mode 100644 index 0000000..33a543a --- /dev/null +++ b/dev/mysql-deployment.yaml @@ -0,0 +1,71 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mysql + namespace: lpt-dev + labels: + app: mysql +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: mysql + template: + metadata: + labels: + app: mysql + spec: + terminationGracePeriodSeconds: 30 + containers: + - name: mysql + image: mysql:9 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3306 + protocol: TCP + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: lpt-secrets + key: mysql-root-password + - name: MYSQL_DATABASE + value: learning_progress_tracker + resources: + requests: + cpu: 250m + memory: 512Mi + limits: + cpu: "1" + memory: 1Gi + volumeMounts: + - name: mysql-data + mountPath: /var/lib/mysql + livenessProbe: + exec: + command: + - mysqladmin + - ping + - -h + - localhost + initialDelaySeconds: 120 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 10 + readinessProbe: + exec: + command: + - mysqladmin + - ping + - -h + - localhost + initialDelaySeconds: 60 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 10 + volumes: + - name: mysql-data + persistentVolumeClaim: + claimName: mysql-data diff --git a/dev/mysql-service.yaml b/dev/mysql-service.yaml new file mode 100644 index 0000000..afc883f --- /dev/null +++ b/dev/mysql-service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: mysql + namespace: lpt-dev + labels: + app: mysql +spec: + type: NodePort + selector: + app: mysql + ports: + - port: 3306 + targetPort: 3306 + protocol: TCP + nodePort: 30306 diff --git a/dev/mysql-storage.yaml b/dev/mysql-storage.yaml new file mode 100644 index 0000000..02f0555 --- /dev/null +++ b/dev/mysql-storage.yaml @@ -0,0 +1,83 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: mysql-dev-data + labels: + app: mysql + environment: dev +spec: + capacity: + storage: 10Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: "" + claimRef: + namespace: lpt-dev + name: mysql-data + hostPath: + path: /vol1/lpt/mysql/dev/data + type: Directory + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - cw8505fnos +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mysql-data + namespace: lpt-dev +spec: + accessModes: + - ReadWriteOnce + storageClassName: "" + resources: + requests: + storage: 10Gi +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: mysql-dev-backup + labels: + app: mysql + environment: dev +spec: + capacity: + storage: 10Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: "" + claimRef: + namespace: lpt-dev + name: mysql-backup + hostPath: + path: /vol1/lpt/backup/dev + type: DirectoryOrCreate + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - cw8505fnos +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mysql-backup + namespace: lpt-dev +spec: + accessModes: + - ReadWriteOnce + storageClassName: "" + resources: + requests: + storage: 10Gi diff --git a/prod/deployment-lpt-ai.yaml b/prod/deployment-lpt-ai.yaml index c42dfad..dd4f912 100644 --- a/prod/deployment-lpt-ai.yaml +++ b/prod/deployment-lpt-ai.yaml @@ -77,3 +77,10 @@ spec: periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 3 + volumeMounts: + - name: lpt-logs + mountPath: /app/data + volumes: + - name: lpt-logs + persistentVolumeClaim: + claimName: lpt-logs diff --git a/prod/lpt-logs-storage.yaml b/prod/lpt-logs-storage.yaml new file mode 100644 index 0000000..830ab00 --- /dev/null +++ b/prod/lpt-logs-storage.yaml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: lpt-prod-logs + labels: + app: lpt + environment: prod +spec: + capacity: + storage: 5Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: "" + claimRef: + namespace: lpt-prod + name: lpt-logs + hostPath: + path: /vol1/lpt/logs/prod + type: DirectoryOrCreate + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - cw8505fnos +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: lpt-logs + namespace: lpt-prod +spec: + accessModes: + - ReadWriteOnce + storageClassName: "" + resources: + requests: + storage: 5Gi diff --git a/prod/mysql-backup-cronjob.yaml b/prod/mysql-backup-cronjob.yaml new file mode 100644 index 0000000..15cf014 --- /dev/null +++ b/prod/mysql-backup-cronjob.yaml @@ -0,0 +1,43 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: mysql-backup + namespace: lpt-prod +spec: + schedule: "0 3 * * *" + concurrencyPolicy: Forbid + successfulJobsHistoryLimit: 7 + failedJobsHistoryLimit: 3 + jobTemplate: + spec: + backoffLimit: 2 + template: + spec: + restartPolicy: OnFailure + containers: + - name: mysqldump + image: mysql:8.0 + imagePullPolicy: IfNotPresent + command: + - /bin/sh + - -ec + - | + set -euo pipefail + TS=$(date +%Y%m%d-%H%M%S) + mysqldump --host=mysql --port=3306 --user=root --password="$MYSQL_ROOT_PASSWORD" \ + --all-databases --single-transaction --routines --events --triggers \ + > "/backup/lpt-prod-${TS}.sql" + find /backup -type f -name 'lpt-prod-*.sql' -mtime +14 -delete + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: lpt-secrets + key: mysql-root-password + volumeMounts: + - name: backup + mountPath: /backup + volumes: + - name: backup + persistentVolumeClaim: + claimName: mysql-backup diff --git a/prod/mysql-deployment.yaml b/prod/mysql-deployment.yaml new file mode 100644 index 0000000..4c19d40 --- /dev/null +++ b/prod/mysql-deployment.yaml @@ -0,0 +1,71 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mysql + namespace: lpt-prod + labels: + app: mysql +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: mysql + template: + metadata: + labels: + app: mysql + spec: + terminationGracePeriodSeconds: 30 + containers: + - name: mysql + image: mysql:8.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3306 + protocol: TCP + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: lpt-secrets + key: mysql-root-password + - name: MYSQL_DATABASE + value: lpt_prod + resources: + requests: + cpu: 250m + memory: 512Mi + limits: + cpu: "1" + memory: 1Gi + volumeMounts: + - name: mysql-data + mountPath: /var/lib/mysql + livenessProbe: + exec: + command: + - mysqladmin + - ping + - -h + - localhost + initialDelaySeconds: 120 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 10 + readinessProbe: + exec: + command: + - mysqladmin + - ping + - -h + - localhost + initialDelaySeconds: 60 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 10 + volumes: + - name: mysql-data + persistentVolumeClaim: + claimName: mysql-data diff --git a/prod/mysql-service.yaml b/prod/mysql-service.yaml new file mode 100644 index 0000000..f1a2c67 --- /dev/null +++ b/prod/mysql-service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: mysql + namespace: lpt-prod + labels: + app: mysql +spec: + type: NodePort + selector: + app: mysql + ports: + - port: 3306 + targetPort: 3306 + protocol: TCP + nodePort: 30307 diff --git a/prod/mysql-storage.yaml b/prod/mysql-storage.yaml new file mode 100644 index 0000000..0e2db76 --- /dev/null +++ b/prod/mysql-storage.yaml @@ -0,0 +1,83 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: mysql-prod-data + labels: + app: mysql + environment: prod +spec: + capacity: + storage: 10Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: "" + claimRef: + namespace: lpt-prod + name: mysql-data + hostPath: + path: /vol1/lpt/mysql/prod/data + type: Directory + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - cw8505fnos +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mysql-data + namespace: lpt-prod +spec: + accessModes: + - ReadWriteOnce + storageClassName: "" + resources: + requests: + storage: 10Gi +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: mysql-prod-backup + labels: + app: mysql + environment: prod +spec: + capacity: + storage: 10Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: "" + claimRef: + namespace: lpt-prod + name: mysql-backup + hostPath: + path: /vol1/lpt/backup/prod + type: DirectoryOrCreate + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - cw8505fnos +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mysql-backup + namespace: lpt-prod +spec: + accessModes: + - ReadWriteOnce + storageClassName: "" + resources: + requests: + storage: 10Gi