What must survive a restart
The Helm chart enables persistence for bundled PostgreSQL by default. Application file mounts are separate and must be configured throughextraVolumes and extraVolumeMounts.
A file can remain listed in BOW after its bytes are lost because its database record still exists. A healthy PostgreSQL PVC therefore does not prove that uploads are safe.
Container writable layers are ephemeral. An
emptyDir survives a container crash within the same pod but is deleted when that pod is removed. Use a PVC backed by durable storage for files you need to keep. See Kubernetes volumes.
Choose storage for your environment
NFS is one way to provide shared file storage. You can use your cluster’s existing storage services instead.
For a single replica,
ReadWriteOnce disk storage is sufficient when the pod can be scheduled on a node that can attach that disk. Plan for disk attachment and zone constraints. Use Recreate for this deployment to stop the previous pod before starting its replacement; expect downtime during updates.
For replicas across nodes, use ReadWriteMany storage and mount the same claims at the same application paths in every replica. All replicas also need the same PostgreSQL database and encryption key. Shared storage alone does not provide full application high availability; see Day 2 Operations.
ReadWriteOnce means read/write access from one node, not necessarily one pod. It does not provide a shared filesystem across nodes. See Kubernetes access modes.AWS EKS
For a single replica on EC2 nodes, follow the EBS CSI setup. EBS volumes cannot be mounted by Fargate pods. For shared files, follow the EFS CSI setup. Configure the filesystem, access permissions, and network access before attaching it to BOW. Fargate uses static EFS provisioning rather than dynamic provisioning.Azure AKS
Use Azure Disk for a single replica or Azure Files for files shared across nodes. Follow the AKS storage overview and Azure Files volume setup.Other clusters
Ask your cluster administrator for a durable StorageClass and its supported access modes. A PVC backed by a node-local directory can still become unavailable when the workload moves to another node. BOW’s file storage settings expect filesystem paths. A plain S3 bucket URL or Azure Blob URL is not a value you can substitute for a mounted directory.Mount application file storage
For an existing installation, complete the migration procedure before applying these values. Create two PVCs in the application’s namespace using your provider’s provisioning instructions:bow-uploadsfor/app/backend/uploads.bow-brandingfor/app/backend/branding_uploads.
ReadWriteMany if replicas must mount them across nodes. Confirm the claims provision successfully; some StorageClasses wait for the first consumer before binding.
Add the following excerpt to your existing Helm values. This example uses one application replica and two existing PVCs; it does not create the claims or configure the database.
extraVolumes or extraVolumeMounts, merge these entries into those lists. Helm values files replace lists rather than appending to them.
For a new artifact app file store, you can place it inside the persistent uploads directory:
extraEnv list. If you already use another BOW_ARTIFACT_STORAGE path, mount persistent storage there and migrate its contents as well.
Ensure the application user can create, read, and write files on every mount. Check the user ID and group ID in your pinned image and configure filesystem ownership, export permissions, or CSI mount options accordingly. A mount hides directories from the container image; prepare any required directory structure on the volume.
Keep your existing config.secretRef pointing at a Secret containing the original BOW_ENCRYPTION_KEY. Do not generate a replacement key during a storage migration.
After preparing storage and copying existing files, apply your complete values file:
bowapp and bow if your release and namespace differ, and replace <installed-chart-version> with your current chart version. Keep the image version pinned in your complete values file during the storage migration.
Migrate an existing installation
Use a maintenance window. Do not scale down or restart the old pods to begin this procedure: their local files may be the only copies.- Pause changes without replacing pods. Suspend automated deployments and scaling, block new writes at your ingress or maintenance layer, and let active runs finish. Account for scheduled jobs and integrations that can still create files.
- Inventory every application pod. Record the image version, mounted paths, artifact storage path, Helm values, and encryption-key source. With several replicas, each pod may contain different files.
- Back up the database, original encryption key, and files. Copy the whole uploads directory from every pod into a separate backup directory. Repeat for branding and the configured artifact storage path. For example, replace
<pod-name>with one running application pod:Repeat with a different backup directory for each pod. If a directory is absent, record that explicitly. Keep backups outside the pods and verify file counts, sizes, and checksums. - Prepare the target PVCs. Provision storage, prepare directories and permissions, and mount it in a temporary migration pod using your cluster’s storage procedures.
- Restore files into the target volumes. Preserve directory structure and filenames. Combine copies from every source pod without silently overwriting conflicting files. Investigate conflicts and retain the original backups. Confirm checksums after copying.
- Deploy the persistent mounts. Stop the temporary migration pod so single-node disks can detach before the application mounts them. Apply the values above only after verifying the copies. Keep the same database, encryption key, and configured file paths. Account for any autoscaler or GitOps controller that could override your maintenance settings.
- Verify before resuming writes. Open existing uploads, generated files, branding, and artifact app files. Then run the replacement check below. Resume traffic, integrations, scheduling, and automated deployments after these checks pass.
Verify persistence after pod replacement
Test first in staging. In production, schedule this check because replacing a pod interrupts in-flight work.- Upload a small test file through BOW and record its contents. If you use branding or artifact app file resources, test those too.
- Confirm the application’s pod mounts reference your intended PVCs. Check both the pod specification and the actual mounted directories.
- Replace the application pod with a controlled rollout:
- Open and download the same file through BOW and compare its contents. Also verify a pre-migration file and a stored connection credential.
- If you run multiple replicas, verify file access through each replica and after rescheduling to another eligible node.
Bound PVC alone does not verify that BOW is reading the persisted files.
