Upgrading to v1.12.0: MinIO → SeaweedFS¶
From v1.12.0 the S3 store bundled with Depictio is
SeaweedFS (weed mini, Apache-2.0)
instead of MinIO, whose community edition no longer receives releases.
SeaweedFS cannot read MinIO's files, so the bundled store starts empty on a
new volume: dashboards miss their tables and images until you copy the bucket
over. MongoDB is untouched and object keys are the same on both sides, so that
copy is the whole migration.
| Your install | What to do |
|---|---|
| Docker Compose with the bundled store | Copy the bucket after the upgrade |
| Helm chart with the bundled store | Export the bucket before helm upgrade |
External S3 (DEPICTIO_S3_EXTERNAL_SERVICE=true, docker-compose.no-minio.yaml, Helm s3.enabled: false) |
Nothing |
| Fresh install, or the Python package (always used SeaweedFS) | Nothing |
Renamed settings¶
Settings are named after S3 rather than MinIO. The old names keep working: an old name is read when its new counterpart is unset, the new name wins when both are set, and the server logs a deprecation warning listing the old names it found.
| Before v1.12.0 | From v1.12.0 |
|---|---|
DEPICTIO_MINIO_*: ROOT_USER, ROOT_PASSWORD, BUCKET, PUBLIC_URL, EXTERNAL_SERVICE, VERIFY_TLS, EXTERNAL_HOST / _PORT / _PROTOCOL, SERVICE_NAME / _SERVICE_PORT |
DEPICTIO_S3_*, same suffixes |
Compose service minio |
s3, with minio as a network alias: http://minio:9000 in CLI configurations still resolves |
Compose MINIO_PORT / MINIO_CONSOLE_PORT |
S3_PORT / S3_CONSOLE_PORT |
Helm minio.*, persistence.minio, secrets.minioRootUser / minioRootPassword, global.urlPattern.templates.minio |
s3.*, persistence.s3, secrets.s3RootUser / s3RootPassword, global.urlPattern.templates.s3 |
- Helm still merges the legacy keys and renders the same manifests, with a deprecation warning in the install and upgrade notes. Its ConfigMaps export both prefixes, so a backend image older than v1.12.0 keeps working. The legacy copies will be dropped in a later release.
- Exception, the development stack:
docker-compose.dev.yamlrequiresDEPICTIO_S3_ROOT_USERandDEPICTIO_S3_ROOT_PASSWORDunder their new names indocker-compose/.env.
All storage settings: Environment Reference.
Names that stay minio on purpose
They are part of live state, and renaming them would break an upgrade:
- Helm: the
<release>-minioDeployment and Service and theirapp: minioselector (a Deployment selector cannot change); the<release>-minio-pvcPVC (a new name would mean an empty volume); the<release>-minio-ingressand-minio-httprouteroutes and the<release>-minio.<domain>host, which DNS, TLS certificates and presigned URLs point at; the Secret keysMINIO_ROOT_USER/MINIO_ROOT_PASSWORD, which keep the generated password stable across upgrades. - Compose: the backup-only
minio-backupservice and the filesdocker-compose.backup-minio.yaml,docker-compose.no-minio.yamlanddocker-compose.minio-legacy.yaml.
Docker Compose¶
The old MinIO is started again as a side-car on its untouched minio_data
volume, and scripts/migrate_minio_to_seaweedfs.py copies the bucket through
the S3 API. Run these steps from a clone of the
repository at v1.12.0,
which holds both files; uv run provides the script's only dependency,
boto3.
-
Upgrade.
--remove-orphansstops the oldminiocontainer, which the v1.12.0 file no longer declares; its volume stays. -
Start the old MinIO on
127.0.0.1:9100:docker compose -f docker-compose.yaml \ -f docker-compose/docker-compose.minio-legacy.yaml up -d minio-legacyFor the development stack, whose data is a bind mount, run
MINIO_LEGACY_DATA=./data/minio_data docker compose -f docker-compose.dev.yaml …instead. -
Publish the new store on
127.0.0.1:9000. The development stack already does. The rootdocker-compose.yamldoes not: add a temporary override. -
Copy. Credentials and bucket are read from
.env(docker-compose/.envfor the development stack). Dry run first, then copy and compare both listings:set -a; source .env; set +a uv run scripts/migrate_minio_to_seaweedfs.py --target-endpoint http://127.0.0.1:9000 --dry-run uv run scripts/migrate_minio_to_seaweedfs.py --target-endpoint http://127.0.0.1:9000 --verifyAn interrupted copy resumes with
--skip-existing. -
Check a dashboard, then clean up: drop the override (
docker compose up -d), remove the side-car and, once satisfied, the old volume.docker compose -f docker-compose.yaml \ -f docker-compose/docker-compose.minio-legacy.yaml rm -sf minio-legacy docker volume rm "$(docker compose config --format json | jq -r .name)_minio_data"For the development stack:
rm -rf ./data/minio_data.
Rolling back: go back to the previous release's compose files; minio_data
is untouched until step 5.
Helm¶
The chart keeps the <release>-minio names, so the upgrade reuses the same PVC.
That PVC is ReadWriteOnce: the old MinIO pod and the new SeaweedFS pod cannot
mount it at the same time, so the copy goes through a local directory, and the
export must happen before the upgrade.
SECRET=<release>-depictio-secrets
KEY=$(kubectl get secret $SECRET -o jsonpath='{.data.MINIO_ROOT_USER}' | base64 -d)
PASS=$(kubectl get secret $SECRET -o jsonpath='{.data.MINIO_ROOT_PASSWORD}' | base64 -d)
# 1. Before upgrading, while MinIO still runs: export the bucket
kubectl port-forward svc/<release>-minio 9100:9000 &
uv run scripts/migrate_minio_to_seaweedfs.py \
--source-access-key "$KEY" --source-secret-key "$PASS" --export-dir ./s3-export
kill %1
# 2. Upgrade: SeaweedFS starts on the same PVC and ignores MinIO's files
helm upgrade <release> ./helm-charts/depictio -f values.yaml
# 3. Import into the new store
kubectl port-forward svc/<release>-minio 9000:9000 &
uv run scripts/migrate_minio_to_seaweedfs.py --target-endpoint http://127.0.0.1:9000 \
--target-access-key "$KEY" --target-secret-key "$PASS" --import-dir ./s3-export --verify
kill %1
# 4. Once checked, reclaim the space of MinIO's old files on the PVC
kubectl exec deploy/<release>-minio -- sh -c 'rm -rf /data/.minio.sys /data/depictio-bucket'
Keep ./s3-export until the new store is checked: it is a full copy taken
before the upgrade. With a second bucket on an external S3, you can export there
(--target-endpoint https://…) instead of to a local directory.
Copy script options
| Option | Default |
|---|---|
--source-endpoint |
http://127.0.0.1:9100 |
--target-endpoint |
the S3 URL resolved from the Depictio settings, else http://127.0.0.1:9000 |
--source-access-key, --source-secret-key, --target-access-key, --target-secret-key |
DEPICTIO_S3_ROOT_USER / DEPICTIO_S3_ROOT_PASSWORD, else the DEPICTIO_MINIO_ROOT_* names |
--bucket (--target-bucket for another name on the target) |
DEPICTIO_S3_BUCKET, else depictio-bucket |
--prefix |
copy only the keys under this prefix |
--workers |
8 parallel copies |
--dry-run / --verify / --skip-existing |
list only / compare listings after the copy / skip keys already on the target with the same size |
--export-dir / --import-dir |
download the bucket into a directory / upload a directory into it, instead of copying directly |
Each endpoint and key can also come from a MIGRATE_SOURCE_* /
MIGRATE_TARGET_* variable (MIGRATE_SOURCE_ENDPOINT, …).
What else changes¶
- The S3 API stays on port 9000; the health check is
GET :9000/healthzinstead of/minio/health/live. WebDAV is off. - The SeaweedFS admin UI is off in the root compose file and in Helm
(
s3.adminUI.enabled); the development stack serves it on127.0.0.1:9001, the former MinIO console port, behind the root keys. - Root credentials are applied again from the environment at every start, so
changing
DEPICTIO_S3_ROOT_*and restarting rotates them, as with MinIO. - For very large object counts, pass
-volume.index=leveldbthrough Helms3.extraArgsto keep the volume index out of memory.