feat(installer): let upgrades copy the uploads uncompressed (#2995)

This commit is contained in:
Hampus
2026-09-27 23:51:24 +02:00
committed by GitHub
parent e2d05a44a8
commit 153dad11e1
3 changed files with 52 additions and 11 deletions
@@ -156,6 +156,7 @@ The run ends by naming the record it wrote and the command that rolls back to it
| `--dry-run` | `-DryRun` | Print the plan. Change nothing |
| `--backup-dir <path>` | `-BackupDir` | Where records go. Default `<dir>/backups` |
| `--no-volume-backup` | `-NoVolumeBackup` | Take the database dump and skip the uploads copy |
| `--no-volume-compression` | `-NoVolumeCompression` | Copy the uploads as a plain `.tar`. Less downtime, more disk |
| `--skip-backup-accept-data-loss` | `-SkipBackupAcceptDataLoss` | Upgrade with no backup at all |
`--dir` and `--ref` mean what they mean on an install, and the installer derives an omitted `--ref` from the `FLUXER_IMAGE_TAG` line in `.env`. Every failure prints a sentence on standard error and exits non-zero, and the script header lists what each code means. A Postgres major version change is exit 3.
@@ -218,7 +219,7 @@ Each upgrade writes one record directory, named `record-` and a UTC stamp, under
| Artefact | What it covers |
| --- | --- |
| `fluxer.dump` | Every account, message, guild and configuration row, in the Postgres custom format |
| `seaweedfs-data.tgz` | Every upload, avatar, report and harvest |
| `seaweedfs-data.tgz` | Every upload, avatar, report and harvest, or `seaweedfs-data.tar` under `--no-volume-compression` |
| `.env` | Every secret the instance was built with |
The stack files sit in the record beside them, so a rollback puts back the exact files the instance was running. The record directory is created `0700` and the `.env` copy inside it is `0600`. Keep records wherever you already keep secrets.
@@ -306,7 +307,7 @@ docker run --rm -v fluxer_seaweedfs-data:/data \
docker compose up -d
```
`tar` extracts over whatever is already on the volume, so the `find` empties it first. In PowerShell write `${PWD}` instead of `$PWD`. Success is an existing attachment URL answering 200 again. The `fluxer_` prefix is the Compose project name, which `docker-compose.yml` sets to `fluxer`.
For a `seaweedfs-data.tar`, write `tar xf` in place of `tar xzf`. `tar` extracts over whatever is already on the volume, so the `find` empties it first. In PowerShell write `${PWD}` instead of `$PWD`. Success is an existing attachment URL answering 200 again. The `fluxer_` prefix is the Compose project name, which `docker-compose.yml` sets to `fluxer`.
## Move to a new Postgres major version
+21 -4
View File
@@ -52,6 +52,7 @@ param(
[switch]$Update,
[switch]$Rollback,
[switch]$NoVolumeBackup,
[switch]$NoVolumeCompression,
[switch]$SkipBackupAcceptDataLoss,
[switch]$Help,
[Parameter(ValueFromRemainingArguments = $true)]
@@ -86,9 +87,8 @@ $FluxerImagesFile = 'images'
$FluxerTagFile = 'image-tag'
$FluxerDumpFile = 'fluxer.dump'
# Free space demanded before a volume copy, as a percentage of the measured volume size. The
# tarball compresses, so this is generous on purpose. A backup that fills the disk it writes to
# takes the instance down with it.
# Free space demanded before a volume copy, as a percentage of the measured volume size. A backup
# that fills the disk it writes to takes the instance down with it.
$FluxerVolumeHeadroomPercent = 110
$FluxerExitUsage = 1
@@ -238,6 +238,7 @@ function Show-FluxerUsage {
Write-FluxerLine ' -Rollback Restore the images and stack files of the last record.'
Write-FluxerLine ' -BackupDir <path> Where records go. Default: the backups folder under -Dir.'
Write-FluxerLine ' -NoVolumeBackup Take the database dump and skip the uploads copy.'
Write-FluxerLine ' -NoVolumeCompression Copy the uploads as a plain .tar. Faster, larger.'
Write-FluxerLine ' -SkipBackupAcceptDataLoss'
Write-FluxerLine ' Upgrade with no backup at all. Losable data is lost.'
Write-FluxerLine ' -Help Print this text.'
@@ -1413,6 +1414,12 @@ function Copy-FluxerVolumes([string]$Record, [string]$Project, [string]$TargetDi
if ($present.Count -eq 0) {
return
}
$tarFlags = 'czf'
$tarExtension = 'tgz'
if ($NoVolumeCompression) {
$tarFlags = 'cf'
$tarExtension = 'tar'
}
Write-FluxerLine 'Stopping the stack for a consistent copy of the uploads.'
if ((Invoke-FluxerDocker @('compose', 'stop')) -ne 0) {
Stop-Fluxer 'docker compose stop failed.' $FluxerExitBackup
@@ -1420,7 +1427,7 @@ function Copy-FluxerVolumes([string]$Record, [string]$Project, [string]$TargetDi
foreach ($volume in $present) {
$full = "${Project}_$volume"
Write-FluxerLine "Copying $full."
$code = Invoke-FluxerDocker @('run', '--rm', '-v', "${full}:/data:ro", '-v', "${Record}:/backup", $FluxerHelperImage, 'tar', 'czf', "/backup/$volume.tgz", '-C', '/data', '.')
$code = Invoke-FluxerDocker @('run', '--rm', '-v', "${full}:/data:ro", '-v', "${Record}:/backup", $FluxerHelperImage, 'tar', $tarFlags, "/backup/$volume.$tarExtension", '-C', '/data', '.')
if ($code -ne 0) {
[void](Invoke-FluxerDocker @('compose', 'up', '-d', '--remove-orphans'))
Stop-Fluxer "Copying $full failed. The stack is started again on the images it was running." $FluxerExitBackup
@@ -1528,8 +1535,12 @@ function Show-FluxerUpdatePlan([string]$TargetDir, [string]$EnvPath, [string]$Ba
Write-FluxerLine ' Backup: none, and a schema change would have no way back'
} elseif ($NoVolumeBackup) {
Write-FluxerLine ' Backup: the database dump, .env, and the stack files'
} else {
if ($NoVolumeCompression) {
Write-FluxerLine ' Backup: the database dump, the uploads volume uncompressed, .env, and the stack files'
} else {
Write-FluxerLine ' Backup: the database dump, the uploads volume, .env, and the stack files'
}
Write-FluxerLine ' Downtime: the stack stops for the uploads copy, then again for the recreate'
}
# The dry run downloads into a temporary directory so it can name the files that actually
@@ -1925,6 +1936,12 @@ function Invoke-FluxerInstall {
if ($SkipBackupAcceptDataLoss -and $NoVolumeBackup) {
Stop-Fluxer '-SkipBackupAcceptDataLoss already skips the volume copy.' $FluxerExitUsage
}
if ($NoVolumeCompression -and -not $Update) {
Stop-Fluxer '-NoVolumeCompression belongs to -Update.' $FluxerExitUsage
}
if ($NoVolumeCompression -and ($SkipBackupAcceptDataLoss -or $NoVolumeBackup)) {
Stop-Fluxer '-NoVolumeCompression changes the volume copy, which this run skips.' $FluxerExitUsage
}
Invoke-FluxerPreflight
+26 -3
View File
@@ -82,8 +82,8 @@ FLUXER_TAG_FILE='image-tag'
FLUXER_DUMP_FILE='fluxer.dump'
# Free space demanded before a volume copy, as a percentage of the measured
# volume size. The tarball compresses, so this is generous on purpose. A backup
# that fills the disk it writes to takes the instance down with it.
# volume size. A backup that fills the disk it writes to takes the instance down
# with it.
FLUXER_VOLUME_HEADROOM=110
# The keys .env carries, in the order they are written. The installer iterates
@@ -226,6 +226,7 @@ Options:
--rollback Restore the images and stack files of the last record.
--backup-dir <path> Where records go. Default <dir>/backups.
--no-volume-backup Take the database dump and skip the uploads copy.
--no-volume-compression Copy the uploads as a plain .tar. Faster, larger.
--skip-backup-accept-data-loss
Upgrade with no backup at all. Losable data is lost.
--allow-root Permit running as root.
@@ -298,6 +299,7 @@ opt_update=0
opt_rollback=0
opt_backup_dir=''
opt_no_volume_backup=0
opt_no_volume_compression=0
opt_skip_backup=0
opt_allow_root=0
@@ -372,6 +374,10 @@ while [ $# -gt 0 ]; do
opt_no_volume_backup=1
shift
;;
--no-volume-compression)
opt_no_volume_compression=1
shift
;;
--skip-backup-accept-data-loss)
opt_skip_backup=1
shift
@@ -687,6 +693,12 @@ fluxer_validate_options() {
if [ "$opt_skip_backup" -eq 1 ] && [ "$opt_no_volume_backup" -eq 1 ]; then
fluxer_bad_usage '--skip-backup-accept-data-loss already skips the volume copy.'
fi
if [ "$opt_no_volume_compression" -eq 1 ] && [ "$opt_update" -eq 0 ]; then
fluxer_bad_usage '--no-volume-compression belongs to --update.'
fi
if [ "$opt_no_volume_compression" -eq 1 ] && { [ "$opt_skip_backup" -eq 1 ] || [ "$opt_no_volume_backup" -eq 1 ]; }; then
fluxer_bad_usage '--no-volume-compression changes the volume copy, which this run skips.'
fi
}
fluxer_ref_for_tag() {
@@ -1566,6 +1578,13 @@ $(fluxer_volume_error ' ')" ;;
if [ "$fluxer_copy_any" -eq 0 ]; then
return 0
fi
if [ "$opt_no_volume_compression" -eq 1 ]; then
fluxer_tar_flags='cf'
fluxer_tar_ext='tar'
else
fluxer_tar_flags='czf'
fluxer_tar_ext='tgz'
fi
fluxer_say 'Stopping the stack for a consistent copy of the uploads.'
if ! $fluxer_engine compose stop; then
fluxer_fail 7 "$fluxer_engine compose stop failed in $opt_dir."
@@ -1574,7 +1593,7 @@ $(fluxer_volume_error ' ')" ;;
[ -n "$fluxer_volume" ] || continue
fluxer_full="${fluxer_project}_${fluxer_volume}"
fluxer_say "Copying $fluxer_full."
if ! $fluxer_engine run --rm -v "$fluxer_full:/data:ro" -v "$fluxer_record:/backup" "$FLUXER_HELPER_IMAGE" tar czf "/backup/$fluxer_volume.tgz" -C /data .; then
if ! $fluxer_engine run --rm -v "$fluxer_full:/data:ro" -v "$fluxer_record:/backup" "$FLUXER_HELPER_IMAGE" tar "$fluxer_tar_flags" "/backup/$fluxer_volume.$fluxer_tar_ext" -C /data .; then
$fluxer_engine compose up -d --remove-orphans || true
fluxer_fail 7 "Copying $fluxer_full failed. The stack is started again on the images it was running."
fi
@@ -1760,8 +1779,12 @@ fluxer_plan_update() {
fluxer_say ' backup none, and a schema change would have no way back'
elif [ "$opt_no_volume_backup" -eq 1 ]; then
fluxer_say ' backup the database dump, .env, and the stack files'
else
if [ "$opt_no_volume_compression" -eq 1 ]; then
fluxer_say ' backup the database dump, the uploads volume uncompressed, .env, and the stack files'
else
fluxer_say ' backup the database dump, the uploads volume, .env, and the stack files'
fi
fluxer_say ' downtime the stack stops for the uploads copy, then again for the recreate'
fi
fluxer_fetch_stack