Migration Guide: MinIO to SeaweedFS (huddo-boards-cp)¶
Background¶
MinIO changed its licence from Apache 2.0 to AGPLv3, which introduces compliance concerns for customers deploying Huddo charts. huddo-boards-cp v2.1.0 introduces SeaweedFS (Apache 2.0) as the replacement S3-compatible object store.
SeaweedFS deploys alongside MinIO by default, so existing installations continue to work without interruption. A built-in migration Job uses rclone to copy data from MinIO to SeaweedFS, and the cutover is a simple values change.
What changed in v2.1.0¶
| Component | Before | After |
|---|---|---|
| S3 store | MinIO (AGPLv3) — always deployed | MinIO (conditional, minio.enabled: true by default) + SeaweedFS (always deployed) |
| S3 endpoint default | huddo-boards-cp-minio-service:9000 |
Unchanged by default — apps still point at MinIO until you switch |
| S3 bucket default | kudos-boards |
huddo-boards (rebrand) |
| New subchart | — | huddo-s3 (SeaweedFS, port 8333) deployed as huddo-boards-cp-s3 |
| Migration Job | — | rclone sync Job, opt-in via s3.migration.enabled: true |
Upgrading to v2.1.0 alone changes nothing for your apps. MinIO remains the active S3 backend. SeaweedFS runs alongside it but receives no traffic until you explicitly redirect the apps.
Bucket rename: v2.1.0 changes the default S3 bucket name from
kudos-boardstohuddo-boards. Migration copies legacy data from MinIOkudos-boardsto SeaweedFShuddo-boards. Existing installs must keep reading the legacy bucket name during Phase 1 (overrideglobal.env.S3_BUCKET: kudos-boards) and drop the override at cutover so apps fall back to the new default.
Prerequisites¶
huddo-boards-cpv2.1.0 or later- Your existing MinIO is healthy and accessible
- Enough storage capacity for SeaweedFS to hold a copy of your data during migration
Know your current S3 configuration¶
Check your deployed values for the S3 settings your apps are using:
helm get values <release> -n <namespace> | grep -i s3
The v2.1.0 chart defaults are:
global:
env:
S3_ENDPOINT: huddo-boards-cp-minio-service
S3_ACCESS_KEY: ioueygr4t589
S3_SECRET_KEY: 7a863d41-2d8f-4143-bc8a-02501edbea6f
S3_BUCKET: huddo-boards # was 'kudos-boards' in <2.1.0
If you have overridden any of these, use your actual values in the migration configuration below. Existing installs running pre-2.1.0 will have data in the legacy bucket kudos-boards — see the bucket rename note above.
Migration steps¶
Phase 1 — Deploy SeaweedFS and migrate data¶
Apps continue to read and write to MinIO during this phase. SeaweedFS deploys alongside it and the migration Job copies all objects from MinIO to SeaweedFS.
Add the following to your values file:
global:
env:
# Existing installs only — pin apps to the legacy MinIO bucket name during migration.
# Drop this override at cutover (Phase 2) to use the new chart default 'huddo-boards'.
S3_BUCKET: kudos-boards
s3:
persistence:
# NFS (recommended for existing NFS-based installations):
nfs:
server: <nfs-server>
path: /pv-connections/huddo-boards-s3
# Or for dynamic storage provisioning:
# storageClassName: fast
migration:
enabled: true
source:
endpoint: "http://huddo-boards-cp-minio-service:9000"
accessKey: ioueygr4t589
secretKey: 7a863d41-2d8f-4143-bc8a-02501edbea6f
bucket: kudos-boards
The migration job copies minio:kudos-boards → seaweedfs:huddo-boards (the new chart-default bucket name).
Important:
s3.persistenceis required. Without it SeaweedFS has no durable storage and data will be lost on pod restart.Note: If your MinIO secret key is stored in a Kubernetes Secret rather than in plain text, use
secretKeyRefinstead ofsecretKey:s3: migration: enabled: true source: endpoint: "http://huddo-boards-cp-minio-service:9000" accessKey: ioueygr4t589 secretKeyRef: name: my-minio-secret key: secret-key bucket: kudos-boards
Run the upgrade:
helm upgrade huddo-boards-cp \
https://docs.huddo.com/assets/config/kubernetes/huddo-boards-cp-2.2.0.tgz \
-n <namespace> \
-f <your-values.yaml>
Verify migration progress¶
The migration runs as a Kubernetes Job. Find the Job name (it includes the Helm release revision):
kubectl get jobs -n <namespace> | grep migration
Follow the rclone logs:
kubectl logs -n <namespace> job/<job-name-from-above> -f
When complete, the Job will log object counts and total size.
Verify data integrity¶
Compare object counts between source and destination:
# Exec into any pod with network access, or run a temporary pod:
kubectl run s3-check --rm -it --image=amazon/aws-cli:latest -n <namespace> -- sh
# Inside the pod — count MinIO objects (legacy bucket name):
aws s3 ls s3://kudos-boards --recursive --endpoint-url http://huddo-boards-cp-minio-service:9000 | wc -l
# Count SeaweedFS objects (new bucket name):
aws s3 ls s3://huddo-boards --recursive --endpoint-url http://huddo-boards-cp-s3:8333 | wc -l
For total size + object count in one shot, append --summarize and read the trailing Total Objects / Total Size lines.
Tip for large datasets: If your data is too large for a single Job run (e.g. the Job times out or the pod is evicted), you can safely run the upgrade again. The migration Job uses
rclone sync, which is idempotent — it only copies objects that are missing or changed in the destination.
Phase 2 — Cutover to SeaweedFS¶
Once you have verified the data is fully migrated, redirect the apps to SeaweedFS and disable MinIO.
Update your values file:
global:
env:
S3_ENDPOINT: huddo-boards-cp-s3
S3_PORT: '8333'
S3_USE_SSL: 'false'
# Drop the Phase 1 'S3_BUCKET: kudos-boards' override here so apps fall back
# to the chart default 'huddo-boards' (matches the SeaweedFS dest bucket).
minio:
enabled: false
s3:
migration:
enabled: false
Note: If you previously had a non-default
S3_SECRET_KEYor usedsecretKeyRefto supply credentials, ensureglobal.env.S3_SECRET_KEY(or its secret reference) is set to the same credentials you configured for SeaweedFS in Phase 1.
Run the upgrade:
helm upgrade huddo-boards-cp \
https://docs.huddo.com/assets/config/kubernetes/huddo-boards-cp-2.2.0.tgz \
-n <namespace> \
-f <your-values.yaml>
This will:
1. Update the S3_ENDPOINT env var in all app pods, triggering a rolling restart
2. Remove the MinIO Deployment, Service, PVC and PV (all rendered from the conditional dependency)
3. Remove the migration Job
Note: Helm prunes the MinIO PVC and PV when
minio.enabled: falsebecause they are rendered from the conditionalhuddo-minio-cpdependency. The underlying NFS data on the server is not affected — those files persist independently of the K8s objects, so a rollback (re-enableminio.enabled: true) will rebind to the same NFS path. If you want to permanently reclaim the NFS data after the soak period, delete the files on the NFS server manually:# On the NFS server (example path — confirm with your minio.nfs.path value): rm -rf /pv-connections/huddo-boards-minio
Verification¶
1. Apps are using SeaweedFS¶
Confirm the S3_ENDPOINT env var on any app pod points to huddo-boards-cp-s3:
kubectl get pod -n <namespace> -l app=<release>-app \
-o jsonpath='{.items[0].spec.containers[0].env}' | grep -A1 S3_ENDPOINT
2. MinIO is removed¶
kubectl get deploy -n <namespace> | grep minio
# Should return nothing
3. SeaweedFS is healthy¶
kubectl get pods -n <namespace> | grep huddo-boards-cp-s3
# Should show 1/1 Running
4. Functional verification¶
- Log in to Huddo Boards and confirm the board list loads
- Open a board with file attachments and confirm files download correctly
- Upload a new file attachment and confirm it persists
Troubleshooting¶
Migration Job stays in Pending state¶
The rclone container cannot be scheduled. Check for resource constraints:
kubectl get jobs -n <namespace> | grep migration
kubectl describe job <job-name> -n <namespace>
Migration Job fails with NoSuchBucket on destination¶
The bucket creation Job must complete before the migration Job starts. The migration Job polls and waits for SeaweedFS to be ready, but if the bucket setup Job itself failed, check its logs:
kubectl logs -n <namespace> job/huddo-boards-cp-s3-bucket-setup
Then re-run the upgrade.
Apps return errors after cutover¶
If the cutover was premature (data not fully migrated), roll back by pointing apps at MinIO again:
global:
env:
S3_ENDPOINT: huddo-boards-cp-minio-service
S3_BUCKET: kudos-boards
# Remove S3_PORT and S3_USE_SSL overrides to restore defaults
minio:
enabled: true
helm upgrade huddo-boards-cp \
https://docs.huddo.com/assets/config/kubernetes/huddo-boards-cp-2.2.0.tgz \
-n <namespace> \
-f <your-values.yaml>
This immediately restores MinIO as the active backend with no data loss.
rclone is slow on large datasets¶
The default configuration uses 8 parallel transfers and 16 checkers. For very large datasets, you can exec into the migration pod and run rclone manually with tuned settings, or increase the Job timeout by adjusting spec.activeDeadlineSeconds.
Alternatively, run the migration outside of the Helm Job entirely:
kubectl run rclone-manual --rm -it --image=rclone/rclone:latest -n <namespace> -- \
sync \
:s3,provider=Other,access_key_id=<key>,secret_access_key=<secret>,endpoint=http://huddo-boards-cp-minio-service:9000,force_path_style=true:kudos-boards \
:s3,provider=Other,access_key_id=<key>,secret_access_key=<secret>,endpoint=http://huddo-boards-cp-s3:8333,force_path_style=true:huddo-boards \
--progress --transfers 16 --checkers 32
Reclaiming MinIO data after the soak period¶
Helm prunes the MinIO PVC and PV automatically when minio.enabled: false (they come from the conditional huddo-minio-cp dependency). The NFS-backed data is not affected — files at the configured minio.nfs.path on the NFS server remain in place so that re-enabling MinIO rebinds to the same data. Once you are confident the SeaweedFS cutover is stable, delete the data on the NFS server manually:
# Example — adjust path to match your minio.nfs.path value:
rm -rf /pv-connections/huddo-boards-minio