Skip to content

feat(compression): allow configuring the Kopia compression policy - #189

Merged
fcanovai merged 9 commits into
mainfrom
dev/126
Sep 10, 2026
Merged

feat(compression): allow configuring the Kopia compression policy#189
fcanovai merged 9 commits into
mainfrom
dev/126

Conversation

@gabriele-wolfox

@gabriele-wolfox gabriele-wolfox commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Adds Kopia compression policy configuration for base backups, both per-server and per-cluster, covering tier1 and tier2 independently.

  • A policy sets algorithm plus optional minSize/maxSize bounds. A per-cluster policy overrides the tier's repository-wide default.
  • Every apply point (tier1 per-backup, tier2 relay, global at server start) fully reconciles the policy on each run, including resetting it to inherit when unconfigured.
  • A read-only server or PluginConfiguration never takes backups, so it's forbidden from touching tier2's compression policy.

Closes #126.

@gabriele-wolfox
gabriele-wolfox force-pushed the dev/126 branch 5 times, most recently from c1b9f04 to e424a8d Compare August 31, 2026 07:48
@armru
armru force-pushed the dev/126 branch 2 times, most recently from 1a8f9c7 to e06c0f8 Compare September 2, 2026 11:07
@fcanovai
fcanovai requested review from a team and jlong49 as code owners September 9, 2026 13:55
@fcanovai
fcanovai force-pushed the dev/126 branch 2 times, most recently from 43513fb to 0829176 Compare September 9, 2026 15:46
gabriele-wolfox and others added 9 commits September 10, 2026 10:00
Kopia repositories were created without a compression policy, so base
backup data was stored uncompressed. Allow users to configure a
compression policy repository-wide on the Server (applied to the global
Kopia policy at server start) and per-cluster on the PluginConfiguration
(applied to the cluster's own source, overriding the global policy).
Both tier1 and tier2 are covered: tier1 is set through the Kopia server
during the backup, while tier2 travels over gRPC and is applied by the
backup consumer before the relay.

The policy exposes the compression algorithm plus the optional minSize
and maxSize bounds (in bytes) that restrict which files are compressed.
Kopia's only-compress and never-compress extension lists are left out on
purpose: they select files by extension, which does not fit a PostgreSQL
data directory (relation files are numeric and carry no meaningful
extension), and WAL files are compressed on a separate path regardless.

Closes #126

Assisted-by: Claude

Signed-off-by: Gabriele Quaresima <gabriele.quaresima@enterprisedb.com>
The policy builder emitted `--compression-min-size` and
`--compression-max-size` only for non-zero values, so a bound written to
the Kopia repository could never be removed: no value of the
configuration field produced a flag that reset it, and files outside the
stale range silently stayed uncompressed.

Both bounds are now always emitted, with zero rendered as `inherit`,
which Kopia resets to the value inherited from the parent policy.

Document that removing the whole `compression` section still leaves the
stored policy in place, and that `algorithm: none` is the way to stop
compressing.

Refs #126

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
A `minSize` above a non-zero `maxSize` matches no file at all: Kopia
accepts the policy and then skips compression for every file, so the
resource reported compression as enabled while nothing was compressed.

The range is now validated in the client policy, in the tier1 and tier2
server configuration, and through a CEL rule on the shared CRD type, so
an inconsistent range is refused at admission. The check runs even when
no algorithm is set, because the size bounds are applied independently
of it.

Refs #126

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
CompressionServerConfig duplicated CompressionPolicy field-for-field in
both core/pkg/config and operator/pkg/config, with only the algorithm
validation and IsZero helper split unevenly between the two. Reuse
CompressionPolicy for Tier1Config/Tier2Config.Compression in both
modules instead, closing a sync gap between the two copies.

Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Francesco Canovai <francesco.canovai@enterprisedb.com>
Kopia's `--compression` flag accepts `inherit` just like the size
bound flags do, resetting the stored value so the source falls back
to its parent (or the repository default). buildCompressionPolicyArgs
only used this for the size bounds, omitting the flag entirely for an
empty algorithm, so a previously-set per-source or global override
could never be cleared once written.

Send `--compression=inherit` too when the algorithm is unset, and
always apply the tier1/tier2/global compression policy instead of
skipping the call when the configured policy is zero-valued. Removing
a `compression` section now correctly resets that policy to inherit
from its parent on the next backup (or server start, for the global
policy), rather than leaving the last applied policy stuck in the
repository.

Drops the now-unused CompressionPolicy.IsZero helpers this uncovered.

Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Francesco Canovai <francesco.canovai@enterprisedb.com>
…ly servers

A read-only server requires tier2 but never takes backups, so it has
no business writing to the shared tier2 global compression policy.
Two gaps allowed it to anyway:

- The CRD had no rule stopping tier2.compression from being set when
  mode is read-only, unlike tier1 and queue which are already
  forbidden in that mode.
- applyGlobalCompressionPolicy for tier2 ran whenever tier2 was
  enabled, regardless of mode. Combined with the previous commit
  always applying the policy (even when unconfigured, to reset it to
  inherit), a read-only server would reset the shared tier2 global
  policy on every restart, clobbering whatever the tier1-enabled
  server that actually owns backups had configured.

Add a CEL validation rule rejecting tier2.compression when mode is
read-only, and gate the tier2 compression apply on tier1 being
enabled so a read-only server never touches it, set or not.

Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Francesco Canovai <francesco.canovai@enterprisedb.com>
…guration

A read-only PluginConfiguration already forbids tier1 and requires
tier2.enableBackup to be false, so no backup is ever taken from such
a cluster. tier2.compression was still settable despite being dead
config: it can never be applied, since backup run requires the tier1
client section (absent in read-only mode) before it ever reaches
compression, and the cnpgi tier2 backup capability is disabled by the
same enableBackup flag.

Add a CEL validation rule rejecting it, matching the equivalent rule
just added for the Server CRD's tier2.compression.

Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Francesco Canovai <francesco.canovai@enterprisedb.com>
Signed-off-by: Francesco Canovai <francesco.canovai@enterprisedb.com>
The compression feature provisions its own isolated namespace, RustFS
bucket, and Klio Server per run, so it shares no state with other
parallel e2e features and doesn't need to run serially.

Signed-off-by: Francesco Canovai <francesco.canovai@enterprisedb.com>
@fcanovai
fcanovai merged commit ce10e13 into main Sep 10, 2026
26 of 27 checks passed
@fcanovai
fcanovai deleted the dev/126 branch September 10, 2026 08:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support configuring Kopia compression policy

4 participants