Skip to content

Commit 6e3dcc4

Browse files
authored
docs(concepts): add PackageSource/Package architecture to Key Concepts (#445)
## Summary - Add PackageSource and Package CRD architecture documentation to the Key Concepts page - Cover the full application lifecycle: reconciliation flow, dependencies, update propagation, rollback strategies, and FluxPlunger auto-recovery - Document the cozypkg CLI tool for managing Package and PackageSource resources - Include Mermaid diagrams following existing project conventions ## Test plan - [ ] Hugo builds without errors - [ ] All Mermaid diagrams render correctly at `/docs/v1/guides/concepts/` - [ ] Page structure and navigation work as expected - [ ] Content reads naturally as a reference page
2 parents b9f1d1d + 0feed82 commit 6e3dcc4

1 file changed

Lines changed: 251 additions & 1 deletion

File tree

content/en/docs/v1/guides/concepts.md

Lines changed: 251 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Key Concepts
33
linkTitle: Key Concepts
4-
description: "Learn about the key concepts of Cozystack, such as management cluster, tenants, and variants."
4+
description: "Learn about the key concepts of Cozystack, such as management cluster, tenants, variants, and the PackageSource/Package lifecycle."
55
weight: 10
66
aliases:
77
- /docs/v1/concepts
@@ -79,3 +79,253 @@ Each variant is tested, versioned, and guaranteed to work as a unit.
7979
They simplify installation, reduce the risk of misconfiguration, and make it easier to choose the right set of features for your deployment.
8080

8181
Read more: [Variants]({{% ref "/docs/v1/operations/configuration/variants" %}}).
82+
83+
## PackageSource and Package
84+
85+
`PackageSource` and `Package` are the two Custom Resource Definitions (CRDs) that drive the entire application lifecycle in Cozystack.
86+
87+
- **PackageSource** (cluster-scoped) defines what is available: it references a Flux source (OCIRepository or GitRepository) that polls an external registry, lists variants, declares dependencies, and specifies the components that make up each application.
88+
- **Package** (cluster-scoped) defines what is deployed: it selects a variant from a PackageSource, provides per-component value overrides, and triggers the creation of a HelmRelease that manages the actual Kubernetes resources.
89+
90+
Together, they form a declarative pipeline: external charts flow through Flux sources and artifact generators into ready-to-install Helm charts, which Packages then instantiate as running workloads.
91+
92+
### Reconciliation Flow
93+
94+
The full reconciliation chain from an external registry to running Kubernetes resources:
95+
96+
```mermaid
97+
flowchart TD
98+
REG["External Helm Registry<br/>(OCI Registry or Git Repo)"]
99+
SRC["Flux Source<br/>(OCIRepository / GitRepository)<br/>Periodically polls the registry"]
100+
PS["PackageSource<br/>(cluster-scoped)<br/>Defines variants, dependencies,<br/>libraries, and components"]
101+
AG["ArtifactGenerator<br/>(in cozy-system namespace)<br/>Builds an ExternalArtifact<br/>for each component"]
102+
EA["ExternalArtifact<br/>Assembled Helm chart<br/>ready for installation"]
103+
PKG["Package<br/>(cluster-scoped)<br/>Selects variant + per-component values"]
104+
HR["HelmRelease<br/>(namespace-scoped)<br/>References ExternalArtifact via chartRef"]
105+
K8S["Kubernetes Resources<br/>(Pods, Services, ConfigMaps, Secrets, ...)"]
106+
107+
REG --> SRC
108+
PS -->|"references via sourceRef"| SRC
109+
PS -->|"reconciler creates"| AG
110+
AG -->|"reads charts from"| SRC
111+
AG --> EA
112+
PKG -->|"triggers creation of"| HR
113+
HR -->|"references via chartRef"| EA
114+
HR --> K8S
115+
```
116+
117+
The naming convention for ExternalArtifacts follows the pattern `<packagesource>-<variant>-<component>`, with dots replaced by dashes to comply with Kubernetes naming rules. For example, a PackageSource named `cozystack.keycloak` with variant `default` and component `keycloak` produces `cozystack-keycloak-default-keycloak`.
118+
119+
### Package Dependencies
120+
121+
PackageSource variants can declare `dependsOn` to gate HelmRelease creation until all dependencies are ready:
122+
123+
```mermaid
124+
flowchart LR
125+
A["Package A"]
126+
B["Package B"]
127+
CHECK{"All dependencies<br/>Ready?"}
128+
C["Package C"]
129+
HR["HelmRelease for C"]
130+
131+
A -->|"status: Ready"| CHECK
132+
B -->|"status: Ready"| CHECK
133+
CHECK -->|"Yes"| HR
134+
CHECK -->|"No"| WAIT["Package C waits"]
135+
```
136+
137+
If all dependencies report a `Ready` status, the dependent Package proceeds to create its HelmRelease. Otherwise, the Package remains in a waiting state until the conditions are met.
138+
139+
### Update Flow
140+
141+
When a new chart version is pushed to the registry, updates propagate automatically through the reconciliation chain:
142+
143+
```mermaid
144+
flowchart TD
145+
PUSH["Push new chart version<br/>to OCI registry"]
146+
FLUX["Flux detects digest change<br/>(periodic polling)"]
147+
REBUILD["ArtifactGenerator rebuilds<br/>ExternalArtifact"]
148+
UPGRADE["HelmRelease triggers<br/>helm upgrade"]
149+
DEPLOY["New version deployed"]
150+
151+
PUSH --> FLUX
152+
FLUX --> REBUILD
153+
REBUILD --> UPGRADE
154+
UPGRADE --> DEPLOY
155+
```
156+
157+
To speed up synchronization without waiting for the next polling interval (Flux sources live in the `cozy-system` namespace):
158+
159+
```text
160+
flux reconcile source oci <source-name> --namespace cozy-system
161+
```
162+
163+
To update application values without changing the chart version, patch the Package CR directly.
164+
Values are scoped per component under `spec.components.<component-name>.values`:
165+
166+
```text
167+
kubectl patch package <name> --type merge --patch '{"spec":{"components":{"<component-name>":{"values":{"key":"value"}}}}}'
168+
```
169+
170+
### Rollback Strategies
171+
172+
There are three approaches to rolling back a Package, listed from most to least recommended:
173+
174+
**GitOps rollback (recommended):** Push the previous chart version to the OCI registry. Flux detects the change and triggers an upgrade to the "old" version through the standard reconciliation flow.
175+
176+
```mermaid
177+
flowchart LR
178+
PUSH["Push previous chart<br/>to registry"]
179+
FLUX["Flux detects change"]
180+
UP["Helm upgrade<br/>to previous version"]
181+
OK["Rollback complete"]
182+
183+
PUSH --> FLUX --> UP --> OK
184+
```
185+
186+
**Emergency rollback:** Run `helm rollback` directly and suspend the HelmRelease to prevent Flux from re-applying the newer version. This bypasses GitOps and should only be used in emergencies.
187+
188+
```mermaid
189+
flowchart LR
190+
ROLLBACK["helm rollback<br/>&lt;release&gt; &lt;revision&gt;"]
191+
SUSPEND["flux suspend helmrelease<br/>&lt;name&gt;"]
192+
NOTE["Flux will NOT re-apply<br/>while suspended"]
193+
194+
ROLLBACK --> SUSPEND --> NOTE
195+
```
196+
197+
**Controlled rollback:** Suspend the HelmRelease first, then run `helm rollback`, fix the chart in the registry, and resume the HelmRelease.
198+
199+
```mermaid
200+
flowchart TD
201+
S1["Suspend HelmRelease"]
202+
S2["helm rollback"]
203+
S3["Fix chart in registry"]
204+
S4["Resume HelmRelease"]
205+
S5["Flux reconciles<br/>with fixed chart"]
206+
207+
S1 --> S2 --> S3 --> S4 --> S5
208+
```
209+
210+
### FluxPlunger Auto-Recovery
211+
212+
FluxPlunger is an automatic recovery component that handles the common "has no deployed releases" HelmRelease error. This error occurs when Helm's release state becomes inconsistent.
213+
214+
```mermaid
215+
flowchart TD
216+
ERR["HelmRelease enters error state<br/>'has no deployed releases'"]
217+
DETECT["FluxPlunger detects the error"]
218+
FIND["Finds the last release Secret"]
219+
SUSPEND["Suspends HelmRelease"]
220+
DEL["Deletes the stale Secret"]
221+
ANNOTATE["Records processed version<br/>in annotation (crash recovery)"]
222+
RESUME["Resumes HelmRelease"]
223+
REINSTALL["Flux performs a clean reinstall"]
224+
225+
ERR --> DETECT
226+
DETECT --> FIND
227+
FIND --> SUSPEND
228+
SUSPEND --> DEL
229+
DEL --> ANNOTATE
230+
ANNOTATE --> RESUME
231+
RESUME --> REINSTALL
232+
```
233+
234+
If FluxPlunger crashes mid-process, the `flux-plunger.cozystack.io/last-processed-version` annotation ensures it can resume correctly on the next reconciliation.
235+
236+
### Lifecycle Operations Summary
237+
238+
| Action | What to do | Handled by |
239+
| --- | --- | --- |
240+
| Update chart version | Push new chart to OCI registry | Flux + ArtifactGenerator |
241+
| Update values | Patch the Package CR | Package controller + HelmRelease |
242+
| Speed up sync | `flux reconcile source oci <name>` | Manual trigger |
243+
| GitOps rollback | Push previous chart version to registry | Flux (standard flow) |
244+
| Emergency rollback | `helm rollback` + suspend HelmRelease | Manual intervention |
245+
| Recovery from error | Automatic via FluxPlunger | FluxPlunger controller |
246+
247+
## cozypkg CLI
248+
249+
`cozypkg` is a command-line tool for managing Package and PackageSource resources interactively.
250+
It handles dependency resolution, variant selection, and safe deletion with cascade analysis, so you don't have to craft YAML manifests by hand.
251+
252+
### Installation
253+
254+
Pre-built binaries are available for Linux, macOS, and Windows (amd64 and arm64) as part of each Cozystack release.
255+
256+
### Commands
257+
258+
#### `cozypkg add` --- Install Packages
259+
260+
Installs one or more packages with automatic dependency resolution:
261+
262+
```text
263+
cozypkg add cozystack.keycloak cozystack.monitoring
264+
cozypkg add --file packages.yaml
265+
```
266+
267+
For each package, `cozypkg add`:
268+
269+
1. Finds the corresponding PackageSource in the cluster.
270+
2. Prompts you to select a variant if multiple are available.
271+
3. Resolves all transitive dependencies (topological sort).
272+
4. Creates Package resources in dependency-first order, skipping already-installed packages.
273+
274+
#### `cozypkg list` --- List Packages
275+
276+
```text
277+
cozypkg list # Available PackageSources
278+
cozypkg list --installed # Installed Packages
279+
cozypkg list --installed --components # Installed Packages with component details
280+
```
281+
282+
Example output:
283+
284+
```text
285+
NAME VARIANT READY STATUS
286+
cozystack.networking cilium True reconciliation succeeded, generated 2 helmrelease(s)
287+
cozystack.keycloak default False DependenciesNotReady
288+
```
289+
290+
#### `cozypkg del` --- Delete Packages
291+
292+
Safely removes packages with reverse-dependency analysis:
293+
294+
```text
295+
cozypkg del cozystack.keycloak
296+
```
297+
298+
Before deletion, `cozypkg del` shows which other installed packages depend on the target and asks for confirmation. Packages are deleted in reverse topological order (dependents first).
299+
300+
#### `cozypkg dot` --- Visualize Dependencies
301+
302+
Generates a dependency graph in GraphViz DOT format:
303+
304+
```text
305+
cozypkg dot | dot -Tpng > dependencies.png
306+
cozypkg dot --installed --components # Component-level graph of installed packages
307+
```
308+
309+
Missing dependencies are highlighted in red, making it easy to spot incomplete installations.
310+
311+
### How cozypkg Fits into the Lifecycle
312+
313+
```mermaid
314+
flowchart LR
315+
USER["User"]
316+
CLI["cozypkg add"]
317+
PKG["Package CR"]
318+
CTRL["Package Controller"]
319+
HR["HelmRelease"]
320+
321+
USER -->|"selects variant"| CLI
322+
CLI -->|"creates"| PKG
323+
PKG -->|"reconciled by"| CTRL
324+
CTRL -->|"creates"| HR
325+
```
326+
327+
`cozypkg` operates exclusively on `Package` and `PackageSource` custom resources.
328+
It does not interact with HelmReleases, ArtifactGenerators, or Flux sources directly --- those are managed by the controllers described above.
329+
330+
You can always manage Package resources with `kubectl` instead of `cozypkg`.
331+
The CLI simply automates variant selection, dependency ordering, and cascade analysis.

0 commit comments

Comments
 (0)