## Summary Annotate `storageClass` as immutable across every stateful chart that exposes one: clickhouse, foundationdb, harbor, http-cache, kafka (Kafka + ZooKeeper), kubernetes (top-level + nodeGroups[]), mariadb, mongodb, nats, openbao, opensearch, postgres, qdrant, rabbitmq, redis, vm-disk. The PVC-pinning argument is identical for every chart — Kubernetes fixes `storageClassName` on each PVC at creation, so editing this field on an existing resource never migrated data; the schema annotation makes that contract explicit and lets schema-aware consumers refuse the edit up-front. Schema-aware consumers today: the Cozystack UI (cozystack/cozystack-ui#6) reads the rule from the chart's openAPISchema and renders the field read-only on edit forms. This PR is **schema-side only**. The cozystack aggregated apiserver does not yet evaluate CEL rules in `openAPISchema` (`MariaDB` / `Postgres` / etc. are application-backed, not CRDs); tracking issue cozystack/cozystack#2657 covers wiring CEL into `pkg/registry/apps/application/rest.go::Update`. Until that lands, an apiserver-level `kubectl patch` that changes `storageClass` is still accepted — but the underlying StatefulSet PVCs do not move, so there's no data-corruption risk, only a confusing UX. The UI catches that case today; the apiserver gate closes it permanently. ## What changes For each app in the list above: - `packages/apps/<app>/values.yaml` — gain a `## @immutable` directive directly above (or below, for fields inside a `@typedef`) the `storageClass` line. - Regenerated via `make generate` in each package: - `api/apps/v1alpha1/<app>/types.go` — kubebuilder `XValidation` marker on the relevant field(s). - `packages/apps/<app>/values.schema.json` — `x-kubernetes-validations: [{rule: "self == oldSelf", message: …}]` on `storageClass`. - `packages/apps/<app>/README.md` — regenerated parameter table. - `packages/system/<app>-rd/cozyrds/<app>.yaml` — the embedded `openAPISchema` on the ApplicationDefinition reflects the change. Refactor: `pkg/registry/apps/application/rest.go` factors the inline schema-build path into a new `buildSpecSchema` helper so it can be unit-tested without standing up a fake apiserver. Three regression tests in `pkg/registry/apps/application/rest_spec_schema_test.go` pin the contract that `x-kubernetes-validations` survives the v1→internal→structural conversion (test loads the actual MariaDB ApplicationDefinition fixture on disk, asserts the rule reaches the structural schema). Empty-input and malformed-JSON paths are also pinned. No e2e admission test is added because the apiserver does not yet enforce the rule — see cozystack/cozystack#2657. No changelog entry: schema-side annotation is invisible at the apiserver layer today (UI-only consumer) and the release-cut PR will add the entry when admission enforcement lands. ## Dependencies Requires cozystack/cozyvalues-gen#24 to be merged and released, and the `cozyvalues-gen` binary pin in `.github/workflows/pre-commit.yml` line 50 bumped to the release that includes that PR. Pre-commit CI will fail until both happen — the stock `v1.3.0` binary silently ignores `## @immutable` and regenerates artefacts without the rule, producing a drift against what's committed. Once that ordering is satisfied, rebase this branch and the pre-commit job will be green. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * storageClass is now treated as immutable after creation for many stateful apps (enforced by chart/CRD schema validation). * **Documentation** * Added a storage immutability guide explaining the contract and enforcement. * Updated chart READMEs and values docs to mark storageClass as immutable and clarified nodeGroup storage remains intentionally mutable. * **Tests** * Added tests validating schema parsing and preservation of immutability rules. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/cozystack/cozystack/pull/2639?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Managed Nginx-based HTTP Cache Service
The Nginx-based HTTP caching service is designed to optimize web traffic and enhance web application performance. This service combines custom-built Nginx instances with HAProxy for efficient caching and load balancing.
Deployment information
The Nginx instances include the following modules and features:
- VTS module for statistics
- Integration with ip2location
- Integration with ip2proxy
- Support for 51Degrees
- Cache purge functionality
HAproxy plays a vital role in this setup by directing incoming traffic to specific Nginx instances based on a consistent hash calculated from the URL. Each Nginx instance includes a Persistent Volume Claim (PVC) for storing cached content, ensuring fast and reliable access to frequently used resources.
Deployment Details
The deployment architecture is illustrated in the diagram below:
┌─────────┐
│ metallb │ arp announce
└────┬────┘
│
│
┌───────▼───────────────────────────┐
│ kubernetes service │ node
│ (externalTrafficPolicy: Local) │ level
└──────────┬────────────────────────┘
│
│
┌────▼────┐ ┌─────────┐
│ haproxy │ │ haproxy │ loadbalancer
│ (active)│ │ (backup)│ layer
└────┬────┘ └─────────┘
│
│ balance uri whole
│ hash-type consistent
┌──────┴──────┬──────────────┐
┌───▼───┐ ┌───▼───┐ ┌───▼───┐ caching
│ nginx │ │ nginx │ │ nginx │ layer
└───┬───┘ └───┬───┘ └───┬───┘
│ │ │
┌────┴───────┬─────┴────┬─────────┴──┐
│ │ │ │
┌───▼────┐ ┌────▼───┐ ┌───▼────┐ ┌────▼───┐
│ origin │ │ origin │ │ origin │ │ origin │
└────────┘ └────────┘ └────────┘ └────────┘
Known issues
- VTS module shows wrong upstream response time, github.com/vozlt/nginx-module-vts#198
storageClassis annotated as immutable in the chart schema — seedocs/storage-immutability.mdfor the contract and which consumers enforce it.
Parameters
Common parameters
| Name | Description | Type | Value |
|---|---|---|---|
size |
Persistent Volume Claim size available for application data. | quantity |
10Gi |
storageClass |
StorageClass used to store the data. | string |
"" |
external |
Enable external access from outside the cluster. | bool |
false |
Application-specific parameters
| Name | Description | Type | Value |
|---|---|---|---|
endpoints |
Endpoints configuration, as a list of ip:port. | []string |
[] |
HAProxy parameters
| Name | Description | Type | Value |
|---|---|---|---|
haproxy |
HAProxy configuration. | object |
{} |
haproxy.replicas |
Number of HAProxy replicas. | int |
2 |
haproxy.resources |
Explicit CPU and memory configuration. When omitted, the preset defined in resourcesPreset is applied. |
object |
{} |
haproxy.resources.cpu |
CPU available to each replica. | quantity |
"" |
haproxy.resources.memory |
Memory (RAM) available to each replica. | quantity |
"" |
haproxy.resourcesPreset |
Default sizing preset used when resources is omitted. |
string |
t1.nano |
Nginx parameters
| Name | Description | Type | Value |
|---|---|---|---|
nginx |
Nginx configuration. | object |
{} |
nginx.replicas |
Number of Nginx replicas. | int |
2 |
nginx.resources |
Explicit CPU and memory configuration. When omitted, the preset defined in resourcesPreset is applied. |
object |
{} |
nginx.resources.cpu |
CPU available to each replica. | quantity |
"" |
nginx.resources.memory |
Memory (RAM) available to each replica. | quantity |
"" |
nginx.resourcesPreset |
Default sizing preset used when resources is omitted. |
string |
t1.nano |
Parameter examples and reference
resources and resourcesPreset
resources sets explicit CPU and memory configurations for each replica.
When left empty, the preset defined in resourcesPreset is applied.
resources:
cpu: 4000m
memory: 4Gi
resourcesPreset sets named CPU and memory configurations for each replica.
This setting is ignored if the corresponding resources value is set.
| Preset name | CPU | memory |
|---|---|---|
nano |
250m |
128Mi |
micro |
500m |
256Mi |
small |
1 |
512Mi |
medium |
1 |
1Gi |
large |
2 |
2Gi |
xlarge |
4 |
4Gi |
2xlarge |
8 |
8Gi |
endpoints
endpoints is a flat list of IP addresses:
endpoints:
- 10.100.3.1:80
- 10.100.3.11:80
- 10.100.3.2:80
- 10.100.3.12:80
- 10.100.3.3:80
- 10.100.3.13:80