GitOps without the operator¶
Built packages are ordinary Helm charts in an OCI registry, so any tool that installs Helm charts can install them. What those tools lack is the package layer: resolving requirements, choosing versions from a repository, and ordering components across releases. kubepkg render adds that part and writes the result in the tool's own format, for you to commit to Git.
kubepkg render virtualization --format flux > clusters/prod/virtualization.yaml
kubepkg render virtualization --format argo > apps/virtualization.yaml
kubepkg render virtualization --format helmfile > helmfile.yaml
render resolves the packages and their requirements as install would for an empty cluster, and then writes them in kubepkg's order:
| Format | Writes | Ordering through |
|---|---|---|
flux |
an OCIRepository or HelmRepository and a HelmRelease per component |
dependsOn across components and packages |
argo |
an Application per component |
sync waves, for an app of apps |
helmfile |
a release per component | needs |
Packages come from the cluster's repositories, or from --repo indexes when you have no cluster at hand, for example in CI:
kubepkg render virtualization --format argo \
--repo https://kuberoot-dev.github.io/kubepkg-recipes/index.yaml --public-key index.pub
$ kubepkg render virtualization --format argo --repo https://kuberoot-dev.github.io/kubepkg-recipes/index.yaml --public-key index.pub | head -40
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0"
finalizers:
- resources-finalizer.argocd.argoproj.io
labels:
kubepkg.dev/package: cdi
name: cdi-operator
namespace: argocd
spec:
destination:
namespace: cdi
server: https://kubernetes.default.svc
project: default
source:
chart: cdi-operator
helm:
releaseName: operator
repoURL: ghcr.io/kuberoot-dev/kubepkg-packages/cdi
targetRevision: 1.66.1-2
syncPolicy:
automated:
prune: true
selfHeal: true
retry:
limit: 5
syncOptions:
- CreateNamespace=true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1"
finalizers:
- resources-finalizer.argocd.argoproj.io
labels:
kubepkg.dev/package: cdi
Package defaults are applied, and values end up in the output, where you can change them in Git.
What you give up¶
Rendered output is plain Flux, Argo CD or helmfile configuration. The operator is not involved, so these do not apply:
- package revisions and whole-package rollback;
- CRD ownership checks;
- requirement and conflict checks while the cluster runs, beyond the resolution done by
render; readyWhenand pre-upgrade hooks.
If you want GitOps and these, commit Package objects to Git instead and let the operator install them. Flux or Argo CD applies the Package manifests, and kubepkg does the rest:
apiVersion: kubepkg.dev/v1
kind: Package
metadata:
name: virtualization
spec:
version: "~1.0"
---
apiVersion: kubepkg.dev/v1
kind: Package
metadata:
name: kubevirt
spec:
version: "~1.9"
---
apiVersion: kubepkg.dev/v1
kind: Package
metadata:
name: cdi
spec:
version: "~1.66"
List the requirements too. The operator never installs a requirement on its own: a package whose requirements are missing waits with RequirementsNotMet and names them. That keeps what is in the cluster exactly what is in Git. kubepkg plan shows the full list to commit.
This is the usual setup: Git holds the desired packages and versions, and kubepkg decides how to get there safely.