Migrating to SeaweedFS
Move on-premises object storage from MinIO to SeaweedFS, including data transfer with rclone and the fossa-core cutover.
Overview
This guide moves your on-premises object storage backend from MinIO to SeaweedFS, FOSSA's S3-compatible storage option. FOSSA uses two SeaweedFS instances (one for Core analysis artifacts and one for Hubble compliance data) and the migration copies your existing MinIO data into them before cutting the deployment over.
The migration has two phases: prepare the SeaweedFS deployments, then execute the cutover during a maintenance window.
Warning
The cutover requires maintenance mode and a data transfer. Plan for downtime proportional to how much object data you're migrating.
Preparation
Create SeaweedFS deployments for Core and Hubble sized to your storage needs. FOSSA requires two instances:
core-seaweedfs: stores analysis artifacts for FOSSA Corehubble-seaweedfs: stores compliance data for FOSSA Hubble
The template below documents installation, upgrade, and the sizing guide:
# =============================================================================# SeaweedFS Storage Values Template for FOSSA Deployment# =============================================================================## FOSSA requires two SeaweedFS instances for S3-compatible object storage:# 1. core-seaweedfs - Stores analysis artifacts for FOSSA Core# 2. hubble-seaweedfs - Stores compliance data for FOSSA Hubble## Adjust storage sizes based on your expected workload. See the "Sizing Guide"# at the bottom of this file for recommendations.## Prerequisites:# - A Kubernetes cluster with a default StorageClass configured# - Helm 3.x## Installation:# helm repo add fossa https://charts.fossa.com# helm repo update## helm install core-seaweedfs fossa/seaweedfs \# --namespace <namespace> \# --version 4.17.0 \# -f core-seaweedfs-values.yaml## helm install hubble-seaweedfs fossa/seaweedfs \# --namespace <namespace> \# --version 4.17.0 \# -f hubble-seaweedfs-values.yaml## Upgrade:# helm upgrade core-seaweedfs fossa/seaweedfs \# --namespace <namespace> \# --version 4.17.0 \# -f core-seaweedfs-values.yaml## helm upgrade hubble-seaweedfs fossa/seaweedfs \# --namespace <namespace> \# --version 4.17.0 \# -f hubble-seaweedfs-values.yaml## =============================================================================# Sizing Guide# =============================================================================## The main values to adjust are volume.dataDirs[].size fields. These control# how much raw data each SeaweedFS instance can store.## Recommended volume sizes by deployment scale:## Deployment Size | Core volume.size | Hubble volume.size | Notes# ------------------------|------------------|--------------------|-------------------# Small (<100 projects) | 50Gi | 25Gi | Dev/eval environments# Medium (<500 projects) | 100Gi | 50Gi | Standard production# Large (<2000 projects) | 250Gi | 100Gi | Large organizations# XLarge (2000+ projects) | 500Gi+ | 250Gi+ | Enterprise scale## Other parameters:## master.data.size - Volume metadata. 1Gi is sufficient for all but the# largest deployments (10k+ volumes).## filer.data.size - File index. 1Gi handles millions of objects. Increase# to 5-10Gi only if you expect tens of millions of files.## maxVolumes - Upper limit on the number of logical volumes SeaweedFS# can create. The defaults (10000 for core, 6000 for# hubble) are generous and rarely need adjustment.## storageClass - Uncomment and set if you need a specific Kubernetes# StorageClass (e.g., for SSD-backed storage, specific# provisioners, or cloud-specific volume types). If left# commented out, the cluster default StorageClass is used.## Storage can be expanded after initial deployment by increasing the PVC size,# provided your StorageClass supports volume expansion# (allowVolumeExpansion: true).# =============================================================================Core: core-seaweedfs-values.yaml
After installation, the Core S3 endpoint is available at http://core-seaweedfs-s3:8333.
nameOverride: core-seaweedfs global: serviceAccountName: core-seaweedfs imagePullSecrets: test-fossa-core-quay.io # <-- existing pull secret created by fossa-core when release name is `test`; list them with `kubectl get secrets --field-selector type=kubernetes.io/dockerconfigjson` # -- S3 API Configurations3: enabled: true enableAuth: true createBuckets: - name: fossa.test anonymousRead: false # -- Master Server Storage (volume metadata and cluster topology; lightweight)master: data: type: persistentVolumeClaim size: 1Gi # <-- Adjust if needed (rarely necessary) # storageClass: "" # <-- Uncomment to use a specific StorageClass # -- Filer Storage (file-to-chunk mapping index)filer: data: type: persistentVolumeClaim size: 1Gi # <-- Adjust if needed # storageClass: "" # <-- Uncomment to use a specific StorageClass logs: type: emptyDir # -- Volume Server Storage (primary data storage)volume: dataDirs: - name: data1 type: persistentVolumeClaim size: 100Gi # <-- ADJUST: Set based on expected data volume maxVolumes: 10000 # storageClass: "" # <-- Uncomment to use a specific StorageClassHubble: hubble-seaweedfs-values.yaml
After installation, the Hubble S3 endpoint is available at http://hubble-seaweedfs-s3:8333.
nameOverride: hubble-seaweedfs global: serviceAccountName: hubble-seaweedfs imagePullSecrets: test-hubble-quay.io # <-- existing pull secret created by fossa-core when release name is `test`; list them with `kubectl get secrets --field-selector type=kubernetes.io/dockerconfigjson` # -- S3 API Configurations3: enabled: true enableAuth: true createBuckets: - name: hubble.fossa.test anonymousRead: false # -- Master Server Storage (volume metadata and cluster topology; lightweight)master: data: type: persistentVolumeClaim size: 1Gi # <-- Adjust if needed (rarely necessary) # storageClass: "" # <-- Uncomment to use a specific StorageClass # -- Filer Storage (file-to-chunk mapping index)filer: data: type: persistentVolumeClaim size: 1Gi # <-- Adjust if needed # storageClass: "" # <-- Uncomment to use a specific StorageClass logs: type: emptyDir # -- Volume Server Storage (primary data storage)volume: dataDirs: - name: data1 type: persistentVolumeClaim size: 100Gi # <-- ADJUST: Set based on expected data volume maxVolumes: 6000 # storageClass: "" # <-- Uncomment to use a specific StorageClassExecution
- 1
Schedule a maintenance window
Pick a window long enough to transfer your object data and verify the cutover.
- 2
Set the application to maintenance mode
Assuming the namespace is
fossa:Shellkubectl config set-context --current --namespace=fossahelm upgrade -i fossa fossa/fossa-core --values fossa-core-config.yml --set global.maintenanceMode.enabled=true --version "^4.0.0" - 3
Deploy SeaweedFS for Core and Hubble
Shellhelm upgrade -i core-seaweedfs fossa/seaweedfs --values core-seaweedfs-values.yamlhelm upgrade -i hubble-seaweedfs fossa/seaweedfs --values hubble-seaweedfs-values.yaml - 4
Transfer data from MinIO to SeaweedFS
The Job below uses
rcloneto copy all data from Core and Hubble MinIO into SeaweedFS. Update therclone.confendpoints and credentials to match your deployment. The example assumes:- Core: bucket
fossa.test; MinIOminio/minio123athttp://fossa-core-minio:80; SeaweedFS athttp://core-seaweedfs-s3:8333 - Hubble: bucket
hubble.fossa.test; MinIOminio/minio123athttp://fossa-hubble-minio:80; SeaweedFSseaweedfs/seaweedfs123athttp://hubble-seaweedfs-s3:8333
YAML# rclone-migration-minio-seaweedfs.yamlapiVersion: v1kind: ConfigMapmetadata: name: rclone-migration-configdata: rclone.conf: | [minio-core] type = s3 provider = Minio access_key_id = minio secret_access_key = minio123 endpoint = http://fossa-core-minio:80 region = minio [minio-hubble] type = s3 provider = Minio access_key_id = minio secret_access_key = minio123 endpoint = http://fossa-hubble-minio:80 region = minio [seaweedfs-core] type = s3 provider = Other access_key_id = seaweedfs secret_access_key = seaweedfs123 endpoint = http://core-seaweedfs-s3:8333 region = us-east-1 force_path_style = true [seaweedfs-hubble] type = s3 provider = Other access_key_id = seaweedfs secret_access_key = seaweedfs123 endpoint = http://hubble-seaweedfs-s3:8333 region = us-east-1 force_path_style = true core-bucket: "fossa.test" hubble-bucket: "hubble.fossa.test" migrate.sh: | #!/bin/sh set -e echo "============================================" echo " MinIO -> SeaweedFS Migration" echo " Started: $(date -u +%Y-%m-%dT%H:%M:%SZ)" echo "============================================" # ---------- tuning knobs (adjust for production) ---------- # TRANSFERS: number of file transfers in parallel # CHECKERS: number of parallel hash-checking threads # S3_CONCURRENCY: multipart upload concurrency per file # S3_CHUNK: multipart chunk size (bigger = fewer API calls for large files) # BUFFER: in-memory buffer per transfer TRANSFERS="${RCLONE_TRANSFERS:-16}" CHECKERS="${RCLONE_CHECKERS:-8}" S3_CONCURRENCY="${RCLONE_S3_UPLOAD_CONCURRENCY:-4}" S3_CHUNK="${RCLONE_S3_CHUNK_SIZE:-64M}" BUFFER="${RCLONE_BUFFER_SIZE:-32M}" COMMON_FLAGS="--transfers=$TRANSFERS \ --checkers=$CHECKERS \ --s3-upload-concurrency=$S3_CONCURRENCY \ --s3-chunk-size=$S3_CHUNK \ --buffer-size=$BUFFER \ --stats=10s \ --stats-one-line \ --log-level=INFO \ --checksum \ --retries=3 \ --retries-sleep=5s \ --low-level-retries=10" # ---------- pre-flight checks ---------- echo "" echo ">>> Pre-flight: listing source buckets" echo "--- minio-core ---" rclone lsd minio-core: 2>&1 echo "--- minio-hubble ---" rclone lsd minio-hubble: 2>&1 echo "--- seaweedfs-core ---" rclone lsd seaweedfs-core: 2>&1 echo "--- seaweedfs-hubble ---" rclone lsd seaweedfs-hubble: 2>&1 echo "" echo ">>> Source object counts" CORE_SRC=$(rclone size minio-core:$CORE_BUCKET --json 2>/dev/null) HUBBLE_SRC=$(rclone size minio-hubble:$HUBBLE_BUCKET --json 2>/dev/null) echo " core: $CORE_SRC" echo " hubble: $HUBBLE_SRC" # ---------- migration: core ---------- echo "" echo "============================================" echo " [1/2] Migrating core: minio -> seaweedfs" echo "============================================" eval rclone sync minio-core:$CORE_BUCKET seaweedfs-core:$CORE_BUCKET $COMMON_FLAGS 2>&1 CORE_RC=$? echo " core migration exit code: $CORE_RC" # ---------- migration: hubble ---------- echo "" echo "============================================" echo " [2/2] Migrating hubble: minio -> seaweedfs" echo "============================================" eval rclone sync minio-hubble:$HUBBLE_BUCKET seaweedfs-hubble:$HUBBLE_BUCKET $COMMON_FLAGS 2>&1 HUBBLE_RC=$? echo " hubble migration exit code: $HUBBLE_RC" # ---------- post-migration validation ---------- echo "" echo "============================================" echo " Post-migration validation" echo "============================================" echo "" echo ">>> Destination object counts" CORE_DST=$(rclone size seaweedfs-core:$CORE_BUCKET --json 2>/dev/null) HUBBLE_DST=$(rclone size seaweedfs-hubble:$HUBBLE_BUCKET --json 2>/dev/null) echo " core src: $CORE_SRC" echo " core dst: $CORE_DST" echo " hubble src: $HUBBLE_SRC" echo " hubble dst: $HUBBLE_DST" echo "" echo ">>> Checking for differences (core)..." rclone check minio-core:$CORE_BUCKET seaweedfs-core:$CORE_BUCKET --one-way $COMMON_FLAGS 2>&1 CORE_CHECK=$? echo "" echo ">>> Checking for differences (hubble)..." rclone check minio-hubble:$HUBBLE_BUCKET seaweedfs-hubble:$HUBBLE_BUCKET --one-way $COMMON_FLAGS 2>&1 HUBBLE_CHECK=$? echo "" echo "============================================" echo " Migration Summary" echo " Finished: $(date -u +%Y-%m-%dT%H:%M:%SZ)" echo "============================================" echo " Core sync=$CORE_RC check=$CORE_CHECK" echo " Hubble sync=$HUBBLE_RC check=$HUBBLE_CHECK" if [ "$CORE_RC" -ne 0 ] || [ "$HUBBLE_RC" -ne 0 ] || [ "$CORE_CHECK" -ne 0 ] || [ "$HUBBLE_CHECK" -ne 0 ]; then echo " STATUS: FAILED (see logs above)" exit 1 fi echo " STATUS: SUCCESS"---apiVersion: batch/v1kind: Jobmetadata: name: rclone-minio-to-seaweedfsspec: backoffLimit: 2 ttlSecondsAfterFinished: 86400 template: metadata: labels: app: rclone-migration spec: restartPolicy: OnFailure containers: - name: rclone image: rclone/rclone:latest imagePullPolicy: IfNotPresent command: ["/bin/sh", "/scripts/migrate.sh"] env: - name: CORE_BUCKET valueFrom: configMapKeyRef: name: rclone-migration-config key: core-bucket - name: HUBBLE_BUCKET valueFrom: configMapKeyRef: name: rclone-migration-config key: hubble-bucket # --- Tune these for production (1-4TB) --- # For a Kind test, keep conservative to avoid overwhelming the node - name: RCLONE_TRANSFERS value: "8" - name: RCLONE_CHECKERS value: "4" - name: RCLONE_S3_UPLOAD_CONCURRENCY value: "4" - name: RCLONE_S3_CHUNK_SIZE value: "16M" - name: RCLONE_BUFFER_SIZE value: "16M" resources: requests: cpu: 500m memory: 256Mi limits: cpu: "2" memory: 1Gi volumeMounts: - name: rclone-config mountPath: /config/rclone readOnly: true - name: scripts mountPath: /scripts readOnly: true volumes: - name: rclone-config configMap: name: rclone-migration-config items: - key: rclone.conf path: rclone.conf - name: scripts configMap: name: rclone-migration-config items: - key: migrate.sh path: migrate.sh mode: 0755Apply the Job:
Shellkubectl config set-context --current --namespace=fossakubectl apply -f rclone-migration-minio-seaweedfs.yaml - Core: bucket
- 5
Follow the migration progress
Shellkubectl logs jobs/rclone-minio-to-seaweedfs --follow - 6
Point your values file at SeaweedFS
Update
fossa-core-config.ymlwith the SeaweedFS endpoints,iam.region, andiam.kind:YAMLiam: region: seaweedfs kind: AccessKey storage: forcePathStyle: true endpoint: http://core-seaweedfs-s3:8333 bucket: fossa.test auth: type: AccessKey accessKey: seaweedfs secretKey: seaweedfs123 hubble: iam: region: seaweedfs kind: AccessKey storage: endpoint: http://hubble-seaweedfs-s3:8333 bucket: hubble.fossa.test auth: type: AccessKey accessKey: seaweedfs secretKey: seaweedfs123 - 7
Cut over and disable maintenance mode
Once the data migration completes, upgrade the deployment to use SeaweedFS and turn off maintenance mode:
Shellhelm upgrade -i fossa fossa/fossa-core --values fossa-core-config.yml --set global.maintenanceMode.enabled=false --version "^5.0.0" - 8
Verify your data
Log in to the console and confirm your data is still available.
- 9
Decommission MinIO
After a week or two of healthy operation, delete the MinIO deployments:
Shellhelm delete fossa-core-miniohelm delete fossa-hubble-minioIf you're certain the MinIO data is no longer needed, delete its PVCs:
Shellkubectl delete pvc fossa-core-miniokubectl delete pvc fossa-hubble-minio