Kubernetes Deployment
Chart: curvine/curvine, version 0.3.2-alpha.
Prerequisitesâ
- Kubernetes 1.20+
- Helm 3.x
- A default
StorageClassfor master/worker PVCs
Architectureâ
Helm release curvine is deployed in namespace curvine:
| Resource | Description |
|---|---|
StatefulSet curvine-master | Metadata and Raft journal |
StatefulSet curvine-worker | Data nodes |
Service curvine-master | Headless, RPC 8995 |
Service curvine-worker | Headless, RPC 8997 |
Deployment curvine-transfer | Load / Export service, created only when enabled |
Service curvine-transfer | Internal Transfer RPC and web endpoint, created only when enabled |
openKruise.enabled defaults to false. StatefulSets use apps/v1.
Transfer Serviceâ
Transfer is an optional service for independent Load and Export scheduling. It is not created by the current Helm chart and does not require changing the running Master or Worker configuration. Deploy it separately after the cluster is healthy; see Deploy Transfer on Kubernetes.
Deploymentâ
Add repositoryâ
helm repo add curvine https://curvineio.github.io/helm-charts
helm repo update
Installâ
helm upgrade --install curvine curvine/curvine \
--version 0.3.2-alpha \
-n curvine \
--create-namespace \
--wait --timeout 10m
Enable Transferâ
Use a Curvine image release that contains the Transfer binary. Do not use an older chart image tag just because the chart itself supports the values below. For high availability or more than one Transfer replica, MySQL must be reachable before the Transfer Pod starts:
transfer:
enabled: true
storeUrl: "mysql://transfer_user:password@mysql.curvine.svc:3306/curvine_transfer"
replicas: 1
helm upgrade --install curvine curvine/curvine \
-n curvine \
-f transfer-values.yaml \
--wait --timeout 10m
The chart creates curvine-transfer as an internal ClusterIP Service and
writes its Service FQDN to [transfer].hostname. Curvine infers the RPC
endpoint from that hostname and transfer.rpcPort; do not configure
endpoints in normal Helm deployments.
An empty transfer.storeUrl uses the single-Pod SQLite default. The chart
creates a ReadWriteOnce PVC for its data directory without setting
storageClassName, so Kubernetes uses the default StorageClass. The PVC
persists across Pod replacement. MySQL is mandatory when
transfer.replicas > 1 and recommended for high availability.
For SQLite, the Transfer Deployment uses Recreate so the old Pod detaches its
ReadWriteOnce volume before a replacement starts. Helm retains the SQLite PVC
on uninstall; delete it explicitly only when discarding Transfer metadata.
The generated ConfigMap is used by Master, Worker, and Transfer. External CLI
hosts must also use a cluster config with [transfer] enabled = true; the CLI
commands remain cv load, cv export, cv load-status, and
cv cancel-load.
Verifyâ
kubectl get pods,svc,pvc -n curvine
Web UI:
kubectl port-forward -n curvine svc/curvine-master 9000:9000
Master addressesâ
Single replica:
curvine-master.curvine.svc.cluster.local:8995
Three replicas:
curvine-master-0.curvine-master.curvine.svc.cluster.local:8995,curvine-master-1.curvine-master.curvine.svc.cluster.local:8995,curvine-master-2.curvine-master.curvine.svc.cluster.local:8995
Upgradeâ
helm upgrade curvine curvine/curvine \
--version 0.3.2-alpha \
-n curvine \
--reuse-values \
--set worker.replicas=3
master.replicas cannot be changed after install.
Uninstallâ
helm uninstall curvine -n curvine
kubectl delete pvc -n curvine -l app.kubernetes.io/instance=curvine
kubectl delete namespace curvine
Troubleshootingâ
| Symptom | Command | Cause |
|---|---|---|
| Pod Pending | kubectl describe pod -n curvine <name> | Insufficient resources; no StorageClass |
| Slow master startup | kubectl logs curvine-master-0 -n curvine | Raft replay in progress |
| PVC Pending | kubectl get sc | No available StorageClass |
Configuration Referenceâ
Chart version 0.3.2-alpha. Defaults below match helm show values curvine/curvine --version 0.3.2-alpha.
Globalâ
| Parameter | Default | Description |
|---|---|---|
global.clusterDomain | cluster.local | Kubernetes cluster domain |
Clusterâ
| Parameter | Default | Description |
|---|---|---|
cluster.id | curvine | Cluster ID |
cluster.formatMaster | false | Format master data on startup |
cluster.formatWorker | false | Format worker data on startup |
cluster.formatJournal | false | Format journal data on startup |
Imageâ
| Parameter | Default | Description |
|---|---|---|
image.repository | ghcr.io/curvineio/curvine | Image repository |
image.tag | "" | Empty uses v{Chart.AppVersion} |
image.pullPolicy | IfNotPresent | Image pull policy |
image.pullSecrets | [] | Image pull secrets |
OpenKruiseâ
openKruise.enabled defaults to false. Master and worker use standard apps/v1 StatefulSets.
Set openKruise.enabled=true to install the kruise subchart and switch master/worker to Advanced StatefulSet (apps.kruise.io/v1beta1).
| Parameter | Default | Description |
|---|---|---|
openKruise.enabled | false | Enable Advanced StatefulSet |
openKruise.podUpdatePolicy | InPlaceOnly | InPlaceOnly | InPlaceIfPossible | ReCreate |
openKruise.persistentPodState.autoGenerate | true | Auto-generate PersistentPodState |
openKruise.persistentPodState.preferredPersistentTopology | kubernetes.io/hostname | Preferred topology key |
openKruise.persistentPodState.requiredPersistentTopology | "" | Required topology key (optional) |
kruise.installation.namespace | kruise-system | Kruise subchart namespace (when enabled) |
kruise.installation.createNamespace | true | Create Kruise namespace |
Masterâ
| Parameter | Default | Description |
|---|---|---|
master.replicas | 1 | Must be odd (1, 3, 5, âĻ) |
master.rpcPort | 8995 | RPC port |
master.journalPort | 8996 | Journal/Raft port |
master.webPort | 9000 | Web UI port |
master.web1Port | 9001 | Additional web port |
master.startupProbe.enabled | true | Startup probe |
master.startupProbe.failureThreshold | 90 | Allow long Raft replay |
master.storage.meta.enabled | true | Enable metadata PVC |
master.storage.meta.storageClass | "" | Empty uses default StorageClass |
master.storage.meta.size | 5Gi | Metadata PVC size |
master.storage.meta.hostPath | "" | hostPath when no StorageClass |
master.storage.meta.mountPath | /opt/curvine/data/meta | Mount path |
master.storage.journal.enabled | true | Enable journal PVC |
master.storage.journal.storageClass | "" | Empty uses default StorageClass |
master.storage.journal.size | 10Gi | Journal PVC size |
master.storage.journal.hostPath | "" | hostPath when no StorageClass |
master.storage.journal.mountPath | /opt/curvine/data/journal | Mount path |
master.resources.requests.cpu | 500m | CPU request |
master.resources.requests.memory | 1Gi | Memory request |
master.resources.limits.cpu | 1000m | CPU limit |
master.resources.limits.memory | 2Gi | Memory limit |
master.antiAffinity.enabled | false | Pod anti-affinity |
master.antiAffinity.type | required | required or preferred |
master.persistentTopology.enabled | true | PersistentPodState topology |
master.persistentTopology.key | kubernetes.io/hostname | Topology key |
master.nodeSelector | {} | Node selector |
master.tolerations | [] | Tolerations |
master.affinity | {} | Affinity rules |
Workerâ
| Parameter | Default | Description |
|---|---|---|
worker.replicas | 1 | Worker replica count |
worker.rpcPort | 8997 | RPC port |
worker.webPort | 9001 | Web UI port |
worker.s3Gateway.enabled | false | Enable S3 gateway |
worker.s3Gateway.listen | 0.0.0.0:9900 | S3 gateway listen address |
worker.s3Gateway.enableDistributedAuth | true | Distributed auth for S3 |
worker.s3Gateway.service.type | ClusterIP | S3 service type |
worker.hostNetwork | false | Use host network |
worker.dnsPolicy | ClusterFirst | DNS policy |
worker.usePodIPAsHostname | false | Use Pod IP as worker hostname |
worker.privileged | true | Privileged mode (FUSE) |
worker.storage.dataDirs[0].name | data1 | Data directory name |
worker.storage.dataDirs[0].type | SSD | Storage type |
worker.storage.dataDirs[0].enabled | true | Enable data directory |
worker.storage.dataDirs[0].size | 20Gi | PVC size |
worker.storage.dataDirs[0].storageClass | "" | Empty uses default StorageClass |
worker.storage.dataDirs[0].hostPath | "" | hostPath when no StorageClass |
worker.storage.dataDirs[0].mountPath | /data/data1 | Mount path |
worker.resources.requests.cpu | 500m | CPU request |
worker.resources.requests.memory | 1Gi | Memory request |
worker.resources.limits.cpu | 1000m | CPU limit |
worker.resources.limits.memory | 2Gi | Memory limit |
worker.antiAffinity.enabled | true | Pod anti-affinity |
worker.antiAffinity.type | preferred | required or preferred |
worker.nodeSelector | {} | Node selector |
worker.tolerations | [] | Tolerations |
worker.affinity | {} | Affinity rules |
Transferâ
| Parameter | Default | Description |
|---|---|---|
transfer.enabled | false | Creates no Transfer resources until enabled; disabled mode preserves the legacy Master Load API. |
transfer.storeUrl | "" | Empty infers local SQLite backed by a chart-managed PVC. Use mysql://... for high availability or multiple replicas. |
transfer.storage.size | 1Gi | Requested capacity for the SQLite PVC. Kubernetes selects the default StorageClass. |
transfer.replicas | 1 | Transfer Pod replicas. Values greater than one require a MySQL storeUrl. |
transfer.rpcPort | 9010 | Transfer RPC Service and container port. |
transfer.webPort | 9011 | Transfer /healthz, /readyz, and /metrics port. |
transfer.resources.requests.cpu | 500m | CPU request. |
transfer.resources.requests.memory | 1Gi | Memory request. |
transfer.resources.limits.cpu | 1000m | CPU limit. |
transfer.resources.limits.memory | 2Gi | Memory limit. |
Serviceâ
| Parameter | Default | Description |
|---|---|---|
service.master.type | ClusterIP | Headless (ClusterIP: None) |
service.worker.type | ClusterIP | Headless (ClusterIP: None) |
service.masterExternal.enabled | false | External master access |
service.masterExternal.type | ClusterIP | External service type |
service.masterExternal.loadBalancerIP | "" | LoadBalancer IP |
Service account and RBACâ
| Parameter | Default | Description |
|---|---|---|
serviceAccount.create | true | Create ServiceAccount |
serviceAccount.name | "" | Auto-generated when empty |
rbac.create | true | Create RBAC resources |
Curvine config (config.*)â
| Parameter | Default | Description |
|---|---|---|
config.master.metaDir | /opt/curvine/data/meta | Master metadata directory |
config.journal.enable | true | Enable journal |
config.journal.journalDir | /opt/curvine/data/journal | Journal directory |
config.journal.snapshotInterval | 6h | Snapshot interval |
config.journal.snapshotEntries | 1000000 | Snapshot entry threshold |
config.client.blockSizeStr | 64MB | Client block size |
config.log.level | INFO | Log level |
config.log.logDir | /opt/curvine/logs | Log directory |
config.log.console | true | Route logs to stdout |
Config overrides (configOverrides.*)â
Override individual TOML sections without replacing the full config:
| Parameter | Default | Description |
|---|---|---|
configOverrides.master | {} | Master section overrides |
configOverrides.journal | {} | Journal section overrides |
configOverrides.worker | {} | Worker section overrides |
configOverrides.client | {} | Client section overrides |
configOverrides.transfer | {} | Additional public [transfer] settings such as max_running_transfers, lease_timeout, and terminal_retention. Chart-managed enabled, hostname, ports, and store_url cannot be overridden here. |
configOverrides.log | {} | Log section overrides |
Storage modesâ
| Mode | Configuration |
|---|---|
| PVC (default) | storageClass: "" uses cluster default StorageClass |
| Named StorageClass | master.storage.*.storageClass, worker.storage.dataDirs[].storageClass |
| hostPath | storageClass: "" with hostPath set |
Examplesâ
Lower resource requests:
helm upgrade curvine curvine/curvine -n curvine --reuse-values \
--set master.resources.requests.cpu=200m \
--set master.resources.requests.memory=512Mi \
--set worker.resources.requests.cpu=200m \
--set worker.resources.requests.memory=512Mi
Full parameter list:
helm show values curvine/curvine --version 0.3.2-alpha