From ed6bed5e14a192a76ef92f419ddfdad32648df7a Mon Sep 17 00:00:00 2001 From: Jon Date: Thu, 19 Mar 2026 17:02:18 +0800 Subject: [PATCH] feat: add opensandbox-server and volume-manager to docker-compose, migrate to named volumes - Add opensandbox-server service with TOML config (runtime, egress, docker security settings) - Add volume-manager service for PVC/volume lifecycle management - Rename sandbox container to fastgpt-code-sandbox for consistency - Migrate all bind mounts (pg, mongo, redis, minio, aiproxy_pg) to Docker named volumes - Add healthcheck for fastgpt-code-sandbox service - Bump opensandbox-egress version from v1.0.1 to v1.0.3 - Update port comments to include opensandbox-server:8090 and volume-manager:3004 --- deploy/args.json | 2 +- deploy/dev/docker-compose.cn.yml | 102 ++++++++++++++++++++-- deploy/dev/docker-compose.yml | 102 ++++++++++++++++++++-- deploy/k8s/volume-manager.yaml | 111 ++++++++++++++++++++++++ deploy/templates/docker-compose.dev.yml | 102 ++++++++++++++++++++-- projects/app/.env.template | 16 +++- projects/volume-manager/README.md | 46 +++++++++- 7 files changed, 451 insertions(+), 30 deletions(-) create mode 100644 deploy/k8s/volume-manager.yaml diff --git a/deploy/args.json b/deploy/args.json index 47fddd72ab..e6ff58f95c 100644 --- a/deploy/args.json +++ b/deploy/args.json @@ -17,7 +17,7 @@ "seekdb": "1.0.1.0-100000392025122619", "opensandbox-server": "v0.1.7", "opensandbox-execd": "v1.0.7", - "opensandbox-egress": "v1.0.1" + "opensandbox-egress": "v1.0.3" }, "images": { "cn": { diff --git a/deploy/dev/docker-compose.cn.yml b/deploy/dev/docker-compose.cn.yml index 5630f64c83..6ad805ea15 100644 --- a/deploy/dev/docker-compose.cn.yml +++ b/deploy/dev/docker-compose.cn.yml @@ -5,10 +5,41 @@ # - pg: 5432 # - mongo: 27017 # - redis: 6379 -# - fastgpt-sandbox: 3002 +# - fastgpt-code-sandbox: 3002 # - fastgpt-plugin: 3003 +# - opensandbox-server: 8090 +# - volume-manager: 3004 # - aiproxy: 3010 # - 使用 pgvector 作为默认的向量库 +# - 配置 opensandbox-config 的 network_mode 为 docker 网络,如 dev_fastgpt +# - 配置 opensandbox-config 的 host_ip 为宿主机 LAN IP,如 192.168.1.100 + +configs: + opensandbox-config: + content: | + [server] + host = "0.0.0.0" + port = 8090 + log_level = "INFO" + + [runtime] + type = "docker" + execd_image = "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/execd:v1.0.7" + + [egress] + image = "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/egress:v1.0.3" + + [docker] + network_mode = "bridge" + # When server runs in a container, set host_ip to the host's IP or hostname so bridge-mode endpoints are reachable (e.g. host.docker.internal or the host LAN IP). + # It's required when server deployed with docker container under host. + host_ip = "host.docker.internal" + drop_capabilities = ["AUDIT_WRITE", "MKNOD", "NET_ADMIN", "NET_RAW", "SYS_ADMIN", "SYS_MODULE", "SYS_PTRACE", "SYS_TIME", "SYS_TTY_CONFIG"] + no_new_privileges = true + pids_limit = 512 + + [ingress] + mode = "direct" services: # Vector DB @@ -26,7 +57,7 @@ services: - POSTGRES_PASSWORD=password - POSTGRES_DB=postgres volumes: - - ./pg/data:/var/lib/postgresql/data + - fastgpt-pg_data:/var/lib/postgresql/data healthcheck: test: ['CMD', 'pg_isready', '-U', 'username', '-d', 'postgres'] interval: 5s @@ -47,7 +78,7 @@ services: - MONGO_INITDB_ROOT_USERNAME=myusername - MONGO_INITDB_ROOT_PASSWORD=mypassword volumes: - - ./mongo/data:/data/db + - fastgpt-mongo_data:/data/db healthcheck: test: [ @@ -113,9 +144,9 @@ services: retries: 3 start_period: 30s volumes: - - ./redis/data:/data + - fastgpt-redis_data:/data fastgpt-minio: - image: registry.cn-hangzhou.aliyuncs.com/fastgpt/minio:RELEASE.2025-09-07T16-13-09Z + image: registry.cn-hangzhou.aliyuncs.com/fastgpt/minio:RELEASE.2025-09-07T16-13-09Z # cpu 不支持 AVX 时候使用 -cpuv1 container_name: fastgpt-minio restart: always networks: @@ -127,15 +158,15 @@ services: - MINIO_ROOT_USER=minioadmin - MINIO_ROOT_PASSWORD=minioadmin volumes: - - ./fastgpt-minio:/data + - fastgpt-minio_data:/data command: server /data --console-address ":9001" healthcheck: test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live'] interval: 30s timeout: 20s retries: 3 - sandbox: - container_name: sandbox + fastgpt-code-sandbox: + container_name: fastgpt-code-sandbox image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.14.8 ports: - 3002:3000 @@ -178,6 +209,11 @@ services: depends_on: fastgpt-minio: condition: service_healthy + healthcheck: + test: ['CMD', 'curl', '-f', 'http://localhost:3000/health'] + interval: 30s + timeout: 20s + retries: 3 # AI Proxy aiproxy: image: registry.cn-hangzhou.aliyuncs.com/labring/aiproxy:v0.3.5 @@ -214,7 +250,7 @@ services: restart: unless-stopped container_name: aiproxy_pg volumes: - - ./aiproxy_pg:/var/lib/postgresql/data + - fastgpt-aiproxy_pg_data:/var/lib/postgresql/data networks: - aiproxy environment: @@ -227,6 +263,54 @@ services: interval: 5s timeout: 5s retries: 10 + opensandbox-server: + image: sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/server:v0.1.7 + container_name: opensandbox-server + restart: always + networks: + - fastgpt + ports: + - '8090:8090' + volumes: + - /var/run/docker.sock:/var/run/docker.sock + configs: + - source: opensandbox-config + target: /etc/opensandbox/config.toml + environment: + - SANDBOX_CONFIG_PATH=/etc/opensandbox/config.toml + healthcheck: + test: ['CMD', 'curl', '-f', 'http://localhost:8090/health'] + interval: 10s + timeout: 5s + retries: 5 + volume-manager: + image: fastgpt-volume-manager:latest + container_name: volume-manager + restart: always + networks: + - fastgpt + ports: + - 3004:3001 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + - VM_RUNTIME=docker + - VM_AUTH_TOKEN=changeme + - VM_VOLUME_NAME_PREFIX=fastgpt-session + - VM_LOG_LEVEL=info + healthcheck: + test: + ['CMD', 'bun', '-e', "fetch('http://localhost:3001/health').then((res) => { if (!res.ok) throw new Error(String(res.status)); })"] + interval: 10s + timeout: 5s + retries: 5 networks: fastgpt: aiproxy: + +volumes: + fastgpt-pg_data: + fastgpt-mongo_data: + fastgpt-redis_data: + fastgpt-minio_data: + fastgpt-aiproxy_pg_data: diff --git a/deploy/dev/docker-compose.yml b/deploy/dev/docker-compose.yml index 372912cdf3..62c332d3f0 100644 --- a/deploy/dev/docker-compose.yml +++ b/deploy/dev/docker-compose.yml @@ -5,10 +5,41 @@ # - pg: 5432 # - mongo: 27017 # - redis: 6379 -# - fastgpt-sandbox: 3002 +# - fastgpt-code-sandbox: 3002 # - fastgpt-plugin: 3003 +# - opensandbox-server: 8090 +# - volume-manager: 3004 # - aiproxy: 3010 # - 使用 pgvector 作为默认的向量库 +# - 配置 opensandbox-config 的 network_mode 为 docker 网络,如 dev_fastgpt +# - 配置 opensandbox-config 的 host_ip 为宿主机 LAN IP,如 192.168.1.100 + +configs: + opensandbox-config: + content: | + [server] + host = "0.0.0.0" + port = 8090 + log_level = "INFO" + + [runtime] + type = "docker" + execd_image = "opensandbox/execd:v1.0.7" + + [egress] + image = "opensandbox/egress:v1.0.3" + + [docker] + network_mode = "bridge" + # When server runs in a container, set host_ip to the host's IP or hostname so bridge-mode endpoints are reachable (e.g. host.docker.internal or the host LAN IP). + # It's required when server deployed with docker container under host. + host_ip = "host.docker.internal" + drop_capabilities = ["AUDIT_WRITE", "MKNOD", "NET_ADMIN", "NET_RAW", "SYS_ADMIN", "SYS_MODULE", "SYS_PTRACE", "SYS_TIME", "SYS_TTY_CONFIG"] + no_new_privileges = true + pids_limit = 512 + + [ingress] + mode = "direct" services: # Vector DB @@ -26,7 +57,7 @@ services: - POSTGRES_PASSWORD=password - POSTGRES_DB=postgres volumes: - - ./pg/data:/var/lib/postgresql/data + - fastgpt-pg_data:/var/lib/postgresql/data healthcheck: test: ['CMD', 'pg_isready', '-U', 'username', '-d', 'postgres'] interval: 5s @@ -47,7 +78,7 @@ services: - MONGO_INITDB_ROOT_USERNAME=myusername - MONGO_INITDB_ROOT_PASSWORD=mypassword volumes: - - ./mongo/data:/data/db + - fastgpt-mongo_data:/data/db healthcheck: test: [ @@ -113,9 +144,9 @@ services: retries: 3 start_period: 30s volumes: - - ./redis/data:/data + - fastgpt-redis_data:/data fastgpt-minio: - image: minio/minio:RELEASE.2025-09-07T16-13-09Z + image: minio/minio:RELEASE.2025-09-07T16-13-09Z # cpu 不支持 AVX 时候使用 -cpuv1 container_name: fastgpt-minio restart: always networks: @@ -127,15 +158,15 @@ services: - MINIO_ROOT_USER=minioadmin - MINIO_ROOT_PASSWORD=minioadmin volumes: - - ./fastgpt-minio:/data + - fastgpt-minio_data:/data command: server /data --console-address ":9001" healthcheck: test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live'] interval: 30s timeout: 20s retries: 3 - sandbox: - container_name: sandbox + fastgpt-code-sandbox: + container_name: fastgpt-code-sandbox image: ghcr.io/labring/fastgpt-sandbox:v4.14.8 ports: - 3002:3000 @@ -178,6 +209,11 @@ services: depends_on: fastgpt-minio: condition: service_healthy + healthcheck: + test: ['CMD', 'curl', '-f', 'http://localhost:3000/health'] + interval: 30s + timeout: 20s + retries: 3 # AI Proxy aiproxy: image: ghcr.io/labring/aiproxy:v0.3.5 @@ -214,7 +250,7 @@ services: restart: unless-stopped container_name: aiproxy_pg volumes: - - ./aiproxy_pg:/var/lib/postgresql/data + - fastgpt-aiproxy_pg_data:/var/lib/postgresql/data networks: - aiproxy environment: @@ -227,6 +263,54 @@ services: interval: 5s timeout: 5s retries: 10 + opensandbox-server: + image: opensandbox/server:v0.1.7 + container_name: opensandbox-server + restart: always + networks: + - fastgpt + ports: + - '8090:8090' + volumes: + - /var/run/docker.sock:/var/run/docker.sock + configs: + - source: opensandbox-config + target: /etc/opensandbox/config.toml + environment: + - SANDBOX_CONFIG_PATH=/etc/opensandbox/config.toml + healthcheck: + test: ['CMD', 'curl', '-f', 'http://localhost:8090/health'] + interval: 10s + timeout: 5s + retries: 5 + volume-manager: + image: fastgpt-volume-manager:latest + container_name: volume-manager + restart: always + networks: + - fastgpt + ports: + - 3004:3001 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + - VM_RUNTIME=docker + - VM_AUTH_TOKEN=changeme + - VM_VOLUME_NAME_PREFIX=fastgpt-session + - VM_LOG_LEVEL=info + healthcheck: + test: + ['CMD', 'bun', '-e', "fetch('http://localhost:3001/health').then((res) => { if (!res.ok) throw new Error(String(res.status)); })"] + interval: 10s + timeout: 5s + retries: 5 networks: fastgpt: aiproxy: + +volumes: + fastgpt-pg_data: + fastgpt-mongo_data: + fastgpt-redis_data: + fastgpt-minio_data: + fastgpt-aiproxy_pg_data: diff --git a/deploy/k8s/volume-manager.yaml b/deploy/k8s/volume-manager.yaml new file mode 100644 index 0000000000..afb91da67f --- /dev/null +++ b/deploy/k8s/volume-manager.yaml @@ -0,0 +1,111 @@ +apiVersion: v1 +kind: Secret +metadata: + name: volume-manager-secret + namespace: opensandbox +type: Opaque +stringData: + auth-token: changeme +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: fastgpt-local +provisioner: rancher.io/local-path +reclaimPolicy: Delete +volumeBindingMode: WaitForFirstConsumer +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: volume-manager + namespace: opensandbox +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: volume-manager + namespace: opensandbox +rules: + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "create", "delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: volume-manager + namespace: opensandbox +subjects: + - kind: ServiceAccount + name: volume-manager + namespace: opensandbox +roleRef: + kind: Role + name: volume-manager + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: volume-manager + namespace: opensandbox + labels: + app: volume-manager +spec: + replicas: 1 + selector: + matchLabels: + app: volume-manager + template: + metadata: + labels: + app: volume-manager + spec: + serviceAccountName: volume-manager + containers: + - name: volume-manager + image: fastgpt-volume-manager:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3001 + env: + - name: VM_RUNTIME + value: kubernetes + - name: VM_K8S_NAMESPACE + value: opensandbox + - name: VM_K8S_PVC_STORAGE_CLASS + value: fastgpt-local + - name: VM_LOG_LEVEL + value: info + - name: VM_AUTH_TOKEN + valueFrom: + secretKeyRef: + name: volume-manager-secret + key: auth-token + readinessProbe: + httpGet: + path: /health + port: 3001 + initialDelaySeconds: 3 + periodSeconds: 10 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: volume-manager + namespace: opensandbox +spec: + selector: + app: volume-manager + ports: + - port: 3001 + targetPort: 3001 + type: ClusterIP diff --git a/deploy/templates/docker-compose.dev.yml b/deploy/templates/docker-compose.dev.yml index 07e39c8dab..c0ca5e66c9 100644 --- a/deploy/templates/docker-compose.dev.yml +++ b/deploy/templates/docker-compose.dev.yml @@ -5,10 +5,41 @@ # - pg: 5432 # - mongo: 27017 # - redis: 6379 -# - fastgpt-sandbox: 3002 +# - fastgpt-code-sandbox: 3002 # - fastgpt-plugin: 3003 +# - opensandbox-server: 8090 +# - volume-manager: 3004 # - aiproxy: 3010 # - 使用 pgvector 作为默认的向量库 +# - 配置 opensandbox-config 的 network_mode 为 docker 网络,如 dev_fastgpt +# - 配置 opensandbox-config 的 host_ip 为宿主机 LAN IP,如 192.168.1.100 + +configs: + opensandbox-config: + content: | + [server] + host = "0.0.0.0" + port = 8090 + log_level = "INFO" + + [runtime] + type = "docker" + execd_image = "${{opensandbox-execd.image}}:${{opensandbox-execd.tag}}" + + [egress] + image = "${{opensandbox-egress.image}}:${{opensandbox-egress.tag}}" + + [docker] + network_mode = "bridge" + # When server runs in a container, set host_ip to the host's IP or hostname so bridge-mode endpoints are reachable (e.g. host.docker.internal or the host LAN IP). + # It's required when server deployed with docker container under host. + host_ip = "host.docker.internal" + drop_capabilities = ["AUDIT_WRITE", "MKNOD", "NET_ADMIN", "NET_RAW", "SYS_ADMIN", "SYS_MODULE", "SYS_PTRACE", "SYS_TIME", "SYS_TTY_CONFIG"] + no_new_privileges = true + pids_limit = 512 + + [ingress] + mode = "direct" services: # Vector DB @@ -26,7 +57,7 @@ services: - POSTGRES_PASSWORD=password - POSTGRES_DB=postgres volumes: - - ./pg/data:/var/lib/postgresql/data + - fastgpt-pg_data:/var/lib/postgresql/data healthcheck: test: ['CMD', 'pg_isready', '-U', 'username', '-d', 'postgres'] interval: 5s @@ -47,7 +78,7 @@ services: - MONGO_INITDB_ROOT_USERNAME=myusername - MONGO_INITDB_ROOT_PASSWORD=mypassword volumes: - - ./mongo/data:/data/db + - fastgpt-mongo_data:/data/db healthcheck: test: [ @@ -113,9 +144,9 @@ services: retries: 3 start_period: 30s volumes: - - ./redis/data:/data + - fastgpt-redis_data:/data fastgpt-minio: - image: ${{minio.image}}:${{minio.tag}} + image: ${{minio.image}}:${{minio.tag}} # cpu 不支持 AVX 时候使用 -cpuv1 container_name: fastgpt-minio restart: always networks: @@ -127,15 +158,15 @@ services: - MINIO_ROOT_USER=minioadmin - MINIO_ROOT_PASSWORD=minioadmin volumes: - - ./fastgpt-minio:/data + - fastgpt-minio_data:/data command: server /data --console-address ":9001" healthcheck: test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live'] interval: 30s timeout: 20s retries: 3 - sandbox: - container_name: sandbox + fastgpt-code-sandbox: + container_name: fastgpt-code-sandbox image: ${{fastgpt-sandbox.image}}:${{fastgpt-sandbox.tag}} ports: - 3002:3000 @@ -178,6 +209,11 @@ services: depends_on: fastgpt-minio: condition: service_healthy + healthcheck: + test: ['CMD', 'curl', '-f', 'http://localhost:3000/health'] + interval: 30s + timeout: 20s + retries: 3 # AI Proxy aiproxy: image: ${{aiproxy.image}}:${{aiproxy.tag}} @@ -214,7 +250,7 @@ services: restart: unless-stopped container_name: aiproxy_pg volumes: - - ./aiproxy_pg:/var/lib/postgresql/data + - fastgpt-aiproxy_pg_data:/var/lib/postgresql/data networks: - aiproxy environment: @@ -227,6 +263,54 @@ services: interval: 5s timeout: 5s retries: 10 + opensandbox-server: + image: ${{opensandbox-server.image}}:${{opensandbox-server.tag}} + container_name: opensandbox-server + restart: always + networks: + - fastgpt + ports: + - '8090:8090' + volumes: + - /var/run/docker.sock:/var/run/docker.sock + configs: + - source: opensandbox-config + target: /etc/opensandbox/config.toml + environment: + - SANDBOX_CONFIG_PATH=/etc/opensandbox/config.toml + healthcheck: + test: ['CMD', 'curl', '-f', 'http://localhost:8090/health'] + interval: 10s + timeout: 5s + retries: 5 + volume-manager: + image: fastgpt-volume-manager:latest + container_name: volume-manager + restart: always + networks: + - fastgpt + ports: + - 3004:3001 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + - VM_RUNTIME=docker + - VM_AUTH_TOKEN=changeme + - VM_VOLUME_NAME_PREFIX=fastgpt-session + - VM_LOG_LEVEL=info + healthcheck: + test: + ['CMD', 'bun', '-e', "fetch('http://localhost:3001/health').then((res) => { if (!res.ok) throw new Error(String(res.status)); })"] + interval: 10s + timeout: 5s + retries: 5 networks: fastgpt: aiproxy: + +volumes: + fastgpt-pg_data: + fastgpt-mongo_data: + fastgpt-redis_data: + fastgpt-minio_data: + fastgpt-aiproxy_pg_data: diff --git a/projects/app/.env.template b/projects/app/.env.template index f3cc229721..567e2e44b3 100644 --- a/projects/app/.env.template +++ b/projects/app/.env.template @@ -35,11 +35,25 @@ CODE_SANDBOX_TOKEN= AIPROXY_API_ENDPOINT=https://localhost:3010 AIPROXY_API_TOKEN=aiproxy -# Agent sandbox +# Agent sandbox(opensandbox | sealos) AGENT_SANDBOX_PROVIDER= +# OpenSandbox 配置 +AGENT_SANDBOX_BASE_URL= +AGENT_SANDBOX_RUNTIME=docker +AGENT_SANDBOX_DEFAULT_IMAGE= +AGENT_SANDBOX_DEFAULT_IMAGE_TAG=latest +AGENT_SANDBOX_WORK_DIRECTORY=/home/sandbox/workspace +AGENT_SANDBOX_ENTRYPOINT=/home/sandbox/entrypoint.sh +AGENT_SANDBOX_USE_SERVER_PROXY=false +# Sealos 配置 AGENT_SANDBOX_SEALOS_BASEURL= AGENT_SANDBOX_SEALOS_TOKEN= +# Volume manager +VOLUME_MANAGER_URL= +VOLUME_MANAGER_TOKEN= +VOLUME_MANAGER_MOUNT_PATH=/home/sandbox/workspace + # 辅助生成模型(暂时只能指定一个,需保证系统中已激活该模型) HELPER_BOT_MODEL=qwen-max diff --git a/projects/volume-manager/README.md b/projects/volume-manager/README.md index b140eb7f7f..d8f00574c1 100644 --- a/projects/volume-manager/README.md +++ b/projects/volume-manager/README.md @@ -68,10 +68,54 @@ DELETE /v1/volumes/:sessionId | `VM_VOLUME_NAME_PREFIX` | | `fastgpt-session` | 卷名前缀 | | `VM_DOCKER_SOCKET` | | `/var/run/docker.sock` | Docker socket 路径(docker 模式) | | `VM_K8S_NAMESPACE` | | `opensandbox` | PVC 所在命名空间(k8s 模式) | -| `VM_K8S_KUBECONFIG` | | - | kubeconfig 路径,集群内运行时留空 | | `VM_K8S_PVC_STORAGE_CLASS` | | `standard` | PVC StorageClass(k8s 模式) | | `VM_K8S_PVC_STORAGE_SIZE` | | `1Gi` | PVC 容量(k8s 模式) | +## Kubernetes 部署要求 + +### StorageClass + +volume-manager 默认使用 StorageClass `fastgpt-local`(可通过 `VM_K8S_PVC_STORAGE_CLASS` 覆盖)。参考配置: + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: fastgpt-local +provisioner: rancher.io/local-path +reclaimPolicy: Delete +volumeBindingMode: WaitForFirstConsumer +``` + +关键特性说明: + +- `reclaimPolicy: Delete`:PVC 删除时自动清理底层数据 +- `volumeBindingMode: WaitForFirstConsumer`:延迟绑定,等待 Pod 调度后再绑定节点 + +也可使用集群现有的其他 StorageClass,需支持 `ReadWriteOnce` accessMode。 + +### RBAC 权限 + +volume-manager 需要在 `VM_K8S_NAMESPACE` 命名空间内操作 PVC,最小权限如下: + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +rules: + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "create", "delete"] +``` + +volume-manager 使用集群内 ServiceAccount 认证,无需挂载外部 kubeconfig。 + +### 部署检查清单 + +- [ ] 命名空间 `opensandbox`(或自定义值)已存在 +- [ ] StorageClass `fastgpt-local`(或自定义值)已创建并可用 +- [ ] ServiceAccount + Role + RoleBinding 已创建 +- [ ] Secret 中包含有效的 `VM_AUTH_TOKEN` + ## 项目结构 ```