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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user