fix: use persistent path for PV hostPath instead of /tmp/

BREAKING: PV hostPath prefix changed from /tmp/clawreef/ to /data/clawreef/

Problem:
- PV hostPath was hardcoded to /tmp/clawreef/user-{id}/instance-{id}
- /tmp/ is a volatile directory that may be cleaned by systemd-tmpfiles
  or cleared on node reboot (depending on OS configuration)
- This caused data loss when worker-02 was rebooted by the hypervisor

Fix:
- Add configurable hostPathPrefix to RuntimePVCConfig (default: /data/clawreef)
- Support K8S_PV_HOST_PATH_PREFIX environment variable override
- Update deployment manifests to use /data/clawmanager/ for MySQL and MinIO

Migration:
- Existing deployments should move data from /tmp/clawreef/ to /data/clawreef/
  and create a symlink for backward compatibility:
    mkdir -p /data/clawreef
    mv /tmp/clawreef/* /data/clawreef/
    rm -rf /tmp/clawreef && ln -s /data/clawreef /tmp/clawreef
This commit is contained in:
hippoley
2026-05-07 07:57:44 +08:00
parent 0d354455d2
commit 963a1c378e
5 changed files with 40 additions and 14 deletions
+5
View File
@@ -114,6 +114,11 @@ runtime:
# 保留策略: Retain | Delete | Recycle
reclaimPolicy: "Delete"
# HostPath 前缀(用于手动创建 PV 时的主机路径)
# 注意:不要使用 /tmp/ 等临时目录,节点重启可能导致数据丢失
# 环境变量覆盖: K8S_PV_HOST_PATH_PREFIX
hostPathPrefix: "/data/clawreef"
# 日志配置
logging:
# 日志级别: debug | info | warn | error
+13
View File
@@ -113,6 +113,7 @@ type RuntimePVCConfig struct {
VolumeMode string `yaml:"volumeMode"`
AllowVolumeExpansion bool `yaml:"allowVolumeExpansion"`
ReclaimPolicy string `yaml:"reclaimPolicy"`
HostPathPrefix string `yaml:"hostPathPrefix"`
}
// LoggingConfig holds logging configuration
@@ -190,6 +191,7 @@ func Load() (*Config, error) {
VolumeMode: "Filesystem",
AllowVolumeExpansion: true,
ReclaimPolicy: "Delete",
HostPathPrefix: getEnv("K8S_PV_HOST_PATH_PREFIX", "/data/clawreef"),
},
},
Logging: LoggingConfig{
@@ -302,6 +304,9 @@ func applyEnvOverrides(config *Config) {
if storageClass := os.Getenv("K8S_STORAGE_CLASS"); storageClass != "" {
config.Kubernetes.Common.StorageClass = storageClass
}
if hostPathPrefix := os.Getenv("K8S_PV_HOST_PATH_PREFIX"); hostPathPrefix != "" {
config.Kubernetes.Runtime.PVC.HostPathPrefix = hostPathPrefix
}
if endpoint := os.Getenv("OBJECT_STORAGE_ENDPOINT"); endpoint != "" {
config.ObjectStorage.Endpoint = endpoint
@@ -366,6 +371,14 @@ func (c *Config) GetStorageClass() string {
return c.Kubernetes.Common.StorageClass
}
// GetHostPathPrefix returns the host path prefix for PV creation
func (c *Config) GetHostPathPrefix() string {
if c.Kubernetes.Runtime.PVC.HostPathPrefix != "" {
return c.Kubernetes.Runtime.PVC.HostPathPrefix
}
return "/data/clawreef"
}
// GetMode returns the K8s connection mode
func (c *Config) GetMode() string {
return c.Kubernetes.Mode
+12 -10
View File
@@ -29,11 +29,12 @@ const (
// Client wraps the Kubernetes client
type Client struct {
Clientset *kubernetes.Clientset
Config *rest.Config
Namespace string
StorageClass string
Mode ConnectionMode
Clientset *kubernetes.Clientset
Config *rest.Config
Namespace string
StorageClass string
HostPathPrefix string
Mode ConnectionMode
}
var (
@@ -96,11 +97,12 @@ func Initialize(cfg *config.Config) error {
}
globalClient = &Client{
Clientset: clientset,
Config: restConfig,
Namespace: cfg.GetNamespace(),
StorageClass: cfg.GetStorageClass(),
Mode: detectedMode,
Clientset: clientset,
Config: restConfig,
Namespace: cfg.GetNamespace(),
StorageClass: cfg.GetStorageClass(),
HostPathPrefix: cfg.GetHostPathPrefix(),
Mode: detectedMode,
}
return nil
+6 -2
View File
@@ -162,8 +162,12 @@ func (s *PVCService) waitForPVCBinding(ctx context.Context, namespace, pvcName s
// createPVForPVC creates a PV manually to bind to the PVC
func (s *PVCService) createPVForPVC(ctx context.Context, namespace, pvcName string, userID, instanceID, storageSizeGB int, storageClass string) (*corev1.PersistentVolumeClaim, error) {
pvName := fmt.Sprintf("clawreef-pv-user-%d-instance-%d", userID, instanceID)
// Use /tmp path to comply with host_path provisioner requirements
hostPath := fmt.Sprintf("/tmp/clawreef/user-%d/instance-%d", userID, instanceID)
// Use configurable host path prefix for persistent storage
hostPathPrefix := "/data/clawreef"
if s.client != nil && s.client.HostPathPrefix != "" {
hostPathPrefix = s.client.HostPathPrefix
}
hostPath := fmt.Sprintf("%s/user-%d/instance-%d", hostPathPrefix, userID, instanceID)
fmt.Printf("Creating PV %s with hostPath %s for PVC %s\n", pvName, hostPath, pvcName)
+4 -2
View File
@@ -552,7 +552,7 @@ spec:
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /tmp/clawmanager/system/mysql
path: /data/clawmanager/system/mysql
type: DirectoryOrCreate
---
apiVersion: v1
@@ -582,7 +582,7 @@ spec:
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /tmp/clawmanager/system/minio
path: /data/clawmanager/system/minio
type: DirectoryOrCreate
---
apiVersion: v1
@@ -885,6 +885,8 @@ spec:
value: "clawmanager"
- name: K8S_STORAGE_CLASS
value: "manual"
- name: K8S_PV_HOST_PATH_PREFIX
value: "/data/clawreef"
- name: SKILL_SCANNER_ENABLED
value: "true"
- name: SKILL_SCANNER_BASE_URL