Allow relative volume paths for k8s-kind deployments

For k8s-kind, relative paths (e.g., ./data/rpc-config) are resolved to
$DEPLOYMENT_DIR/path by _make_absolute_host_path() during kind config
generation. This provides Docker Host persistence that survives cluster
restarts.

Previously, validation threw an exception before paths could be resolved,
making it impossible to use relative paths for persistent storage.

Changes:
- deployment_create.py: Skip relative path check for k8s-kind
- cluster_info.py: Allow relative paths to reach PV generation
- docs/deployment_patterns.md: Document volume persistence patterns

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
A. F. Dudley 2026-02-02 23:26:13 -05:00
parent 581ceaea94
commit ee59918082
3 changed files with 54 additions and 9 deletions

View File

@ -163,3 +163,40 @@ To stop a single deployment without affecting the cluster:
```bash ```bash
laconic-so deployment --dir my-deployment stop --skip-cluster-management laconic-so deployment --dir my-deployment stop --skip-cluster-management
``` ```
## Volume Persistence in k8s-kind
k8s-kind has 3 storage layers:
- **Docker Host**: The physical server running Docker
- **Kind Node**: A Docker container simulating a k8s node
- **Pod Container**: Your workload
For k8s-kind, volumes with paths are mounted from Docker Host → Kind Node → Pod via extraMounts.
| spec.yml volume | Storage Location | Survives Pod Restart | Survives Cluster Restart |
|-----------------|------------------|---------------------|-------------------------|
| `vol:` (empty) | Kind Node PVC | ✅ | ❌ |
| `vol: ./data/x` | Docker Host | ✅ | ✅ |
| `vol: /abs/path`| Docker Host | ✅ | ✅ |
**Recommendation**: Always use paths for data you want to keep. Relative paths
(e.g., `./data/rpc-config`) resolve to `$DEPLOYMENT_DIR/data/rpc-config` on the
Docker Host.
### Example
```yaml
# In spec.yml
volumes:
rpc-config: ./data/rpc-config # Persists to $DEPLOYMENT_DIR/data/rpc-config
chain-data: ./data/chain # Persists to $DEPLOYMENT_DIR/data/chain
temp-cache: # Empty = Kind Node PVC (lost on cluster delete)
```
### The Antipattern
Empty-path volumes appear persistent because they survive pod restarts (data lives
in Kind Node container). However, this data is lost when the kind cluster is
recreated. This "false persistence" has caused data loss when operators assumed
their data was safe.

View File

@ -690,10 +690,14 @@ def _check_volume_definitions(spec):
for volume_name, volume_path in spec.get_volumes().items(): for volume_name, volume_path in spec.get_volumes().items():
if volume_path: if volume_path:
if not os.path.isabs(volume_path): if not os.path.isabs(volume_path):
raise Exception( # For k8s-kind: allow relative paths, they'll be resolved
f"Relative path {volume_path} for volume {volume_name} not " # by _make_absolute_host_path() during kind config generation
f"supported for deployment type {spec.get_deployment_type()}" if not spec.is_kind_deployment():
) deploy_type = spec.get_deployment_type()
raise Exception(
f"Relative path {volume_path} for volume "
f"{volume_name} not supported for {deploy_type}"
)
@click.command() @click.command()

View File

@ -352,11 +352,15 @@ class ClusterInfo:
continue continue
if not os.path.isabs(volume_path): if not os.path.isabs(volume_path):
print( # For k8s-kind, allow relative paths:
f"WARNING: {volume_name}:{volume_path} is not absolute, " # - PV uses /mnt/{volume_name} (path inside kind node)
"cannot bind volume." # - extraMounts resolve the relative path to Docker Host
) if not self.spec.is_kind_deployment():
continue print(
f"WARNING: {volume_name}:{volume_path} is not absolute, "
"cannot bind volume."
)
continue
if self.spec.is_kind_deployment(): if self.spec.is_kind_deployment():
host_path = client.V1HostPathVolumeSource( host_path = client.V1HostPathVolumeSource(