-
Notifications
You must be signed in to change notification settings - Fork 29
docs(development): explain why packages live in apps vs extra #594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -122,6 +122,25 @@ Development can be done locally by modifying and updating files in this reposito | |
|
|
||
| ## Packages | ||
|
|
||
| Cozystack is, at its core, a **provider of managed services**. Much like the managed | ||
| offerings of AWS or Google Cloud, a user comes to order a **final entity** — a | ||
| PostgreSQL database, a Kafka queue, an S3 bucket, a Kubernetes cluster, a virtual | ||
| machine — rather than to assemble the underlying infrastructure themselves. Each of these is a **first-class object** in the Cozystack | ||
| API (`apps.cozystack.io`): the user declares *what* they want, and the platform | ||
| provisions and operates the implementation underneath. The user gets an endpoint and | ||
| credentials and never has to know — or even see — how or where the service actually runs. | ||
|
|
||
| The four package categories follow directly from this model: | ||
|
|
||
| - **`core`** — how the platform bootstraps and configures itself. | ||
| - **`system`** — the operators and upstream charts that actually run workloads. | ||
| - **`apps`** — the first-class managed services a user orders directly. | ||
| - **`extra`** — enabler modules a tenant switches on, which power those services under | ||
| the hood without being ordered as standalone services. | ||
|
|
||
| The split between `apps` and `extra` is the one most often misunderstood, so it is | ||
| spelled out in detail below. | ||
|
|
||
| ### [core](https://github.com/cozystack/cozystack/tree/main/packages/core) | ||
|
|
||
| Core packages handle bootstrap and platform-level configuration. | ||
|
|
@@ -173,12 +192,19 @@ System packages use Helm to install and are managed by FluxCD. | |
|
|
||
| ### [apps](https://github.com/cozystack/cozystack/tree/main/packages/apps) | ||
|
|
||
| These user-facing applications appear in the dashboard and include manifests to be applied to the cluster. | ||
| `apps` are the **first-class managed services** a user orders directly. Each one is a | ||
| final entity shown in the dashboard catalog and exposed through the `apps.cozystack.io` | ||
| API: `apps/postgres` ("Managed PostgreSQL service"), `apps/kubernetes` ("Managed | ||
| Kubernetes service"), `apps/kafka`, `apps/bucket` (an S3 bucket), `apps/vm-instance`, | ||
| and so on. | ||
|
|
||
| Apps charts serve as a high-level API for users. They define only the parameters that | ||
| should be exposed and validated through `values.schema.json`, keeping the interface | ||
| minimal and secure. Apps charts should not contain business logic for deploying the | ||
| application itself — instead they delegate to an operator or to FluxCD. | ||
| An app chart is a **high-level API**, not a deployment recipe. It defines only the | ||
| parameters that should be exposed and validated through `values.schema.json`, keeping | ||
| the interface minimal and secure — for example, a user selects a Postgres *version* but | ||
| cannot override the container image. The chart contains no business logic for running | ||
| the application itself; it delegates to an operator or to FluxCD. This thin API layer | ||
| over the raw operator exists so the platform keeps full control of every input | ||
| (security) and hands the user a final, ready-to-consume service (UX). | ||
|
|
||
| Depending on whether the application has a dedicated operator, apps follow one of two patterns: | ||
|
|
||
|
|
@@ -214,8 +240,31 @@ Other examples of this pattern: `extra/ingress`, `extra/seaweedfs`, `extra/monit | |
|
|
||
| ### [extra](https://github.com/cozystack/cozystack/tree/main/packages/extra) | ||
|
|
||
| Similar to `apps` but not shown in the application catalog. They can only be installed as part of a tenant. | ||
| They are allowed to use by bottom tenants installed in current tenant namespace. | ||
| `extra` packages are **enabler modules**, not first-class services. A user never orders | ||
| them as a final entity; instead they are switched on as **tenant options**, and once | ||
| enabled they provide capabilities that the `apps` services build on — working under the | ||
| hood. For that reason they are *not* shown in the application catalog and can only be | ||
| installed as part of a tenant. Because an `extra` module is enabled at the tenant level, | ||
| it is shared by the child (bottom) tenants nested in that tenant's namespace — | ||
| provisioned once and reused beneath them (for example, a child tenant without its own | ||
| `monitoring` sends its metrics to the parent tenant's monitoring stack instead of | ||
| running a second copy). | ||
|
|
||
| The clearest example is object storage: | ||
|
|
||
| - `extra/seaweedfs` ("Managed SeaweedFS Service") deploys a SeaweedFS cluster and | ||
| registers `BucketClass` resources for the tenant. | ||
| - `apps/bucket` ("S3 compatible storage") is what the user actually orders — it creates | ||
| a `BucketClaim` against one of those `BucketClass`es. | ||
|
|
||
| So a tenant administrator *enables the SeaweedFS module once*, and from then on users | ||
| can order S3 buckets as a first-class service. The user consumes a bucket; they never | ||
| see, order, or manage SeaweedFS itself — it is an implementation detail of "S3 bucket". | ||
| The same relationship holds for `extra/etcd` ("Storage for Kubernetes clusters"), which | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Heads-up: etcd is the flagship Suggestion: either add a short forward-note ("etcd's placement as a tenant module is under review — see community#25"), or lead the section with a more stable flagship example ( |
||
| provides the datastore for `apps/kubernetes` managed clusters. Other `extra` modules | ||
| supply tenant-wide infrastructure rather than orderable services: `extra/ingress` | ||
| (NGINX Ingress Controller), `extra/gateway` (per-tenant Gateway API backed by Cilium), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This example list is slightly off against the code:
Suggestion: keep |
||
| `extra/external-dns`, and `extra/monitoring`. | ||
|
|
||
| Read more about [Tenant System](/docs/guides/concepts/#tenant-system) on the Core Concepts page. | ||
|
|
||
|
|
@@ -227,6 +276,38 @@ Extra packages follow the same two architectural patterns as apps (operator-base | |
| Apps and extra packages use Helm for application and are installed from the dashboard and managed by FluxCD. | ||
| {{% /alert %}} | ||
|
|
||
| ### Choosing apps, extra, or a bundled dependency | ||
|
|
||
| When adding a new capability, decide where it belongs by asking who consumes it: | ||
|
|
||
| 1. **Does the user order it directly as a final service?** Then it is a first-class | ||
| managed service → `apps`, shown in the catalog (e.g., `apps/postgres`, `apps/bucket`). | ||
| 2. **Is it a shared dependency** — used by several apps, or reused across tenants? Then | ||
| it is an enabler the platform/tenant switches on once and many things build on → | ||
| `extra` (e.g., `extra/seaweedfs` backs every `apps/bucket`; `extra/monitoring` collects | ||
| metrics for all apps in a tenant). | ||
|
kvaps marked this conversation as resolved.
|
||
| 3. **Is it a single, private dependency** of one application, shared with no one? Then it | ||
| is *not* a package at all — it is bundled **inside the consuming chart** and deployed | ||
| together with it, invisible to the user. For example, the `monitoring` stack ships its | ||
| own PostgreSQL database for Alerta as part of its release (the former `ferretdb` app | ||
| likewise shipped its own PostgreSQL inside the chart); the user neither sees nor has | ||
| access to these internal databases. | ||
|
|
||
| Dependencies also run **between first-class services**. When a dependency is itself | ||
| something the user creates, keeps, and manages on its own, it stays an `apps` service | ||
| and other apps simply **reference** it instead of bundling it. For example, `apps/vm-disk` | ||
| ("Virtual Machine Disk") is ordered on its own, and `apps/vm-instance` attaches one or | ||
| more existing disks by name (the dashboard lists the available disks to choose from). A | ||
| disk has its own lifecycle — it can outlive an instance, be detached and reattached, or | ||
| join several disks on one VM — so it is a service in its own right, not something hidden | ||
| inside `vm-instance`. | ||
|
|
||
| Two questions settle most cases: **who orders it** (the user → `apps`; the platform or a | ||
| tenant → `extra`) and **does it have value on its own** (yes → its own `apps` service | ||
| that others reference; no → bundled and hidden inside the consuming chart). Sharing tips | ||
| the scale toward `extra`: a dependency that must be provisioned once and reused across | ||
| apps or tenants becomes a module rather than a per-instance bundle. | ||
|
|
||
| ## Package Structure | ||
|
|
||
| Every package is a typical Helm chart containing all necessary images and manifests | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: "not shown in the application catalog" is correct (the console excludes
module/Administrationdefinitions from the Marketplace —apps/console/src/routes/MarketplaceList.tsx), but they're not invisible — they appear under Administration → Modules (routes/ModulesPage.tsx) and are configured there per tenant. Consider "not shown in the application catalog (they appear under Administration → Modules instead)" so a reader doesn't expect them to be entirely absent from the dashboard. Optional nit.