Upgrading
Standard upgrade
Check the Behavior changes index and the per-version section for any release between your current version and the target. These flag breaking changes, new values, and potential issues to address before running the recipe below.
Apply the updated CRDs before upgrading the Helm releases; Helm does not upgrade CRDs automatically:
helm show crds oci://ghcr.io/cosmonic/cosmonic-control --version 0.7.0 | kubectl apply -f -Then upgrade the control plane with the same values file used during installation:
# Check the currently installed release and chart version
helm list -n cosmonic-system
# Upgrade to a new chart version
helm upgrade cosmonic-control oci://ghcr.io/cosmonic/cosmonic-control \
--version 0.10.0 \
--namespace cosmonic-system \
-f cosmonic-control-values.yamlUpgrade the HostGroup release separately:
helm upgrade hostgroup oci://ghcr.io/cosmonic/cosmonic-control-hostgroup \
--version 0.10.0 \
--namespace cosmonic-systemWait for the rollout to complete before considering the upgrade done:
kubectl rollout status deploy -l app.kubernetes.io/instance=cosmonic-control -n cosmonic-system
kubectl rollout status deploy -l app.kubernetes.io/instance=hostgroup -n cosmonic-systemChart versions do not track appVersion one-to-one. A single chart version (e.g. 0.4.1) may ship updated appVersion values as underlying Cosmonic Control images are patched. Check the current appVersion before upgrading:
helm show chart oci://ghcr.io/cosmonic/cosmonic-control --version 0.10.0Rolling back
Rolling back the Helm release
To roll back to the previous release after a failed upgrade:
helm rollback cosmonic-control -n cosmonic-system
helm rollback hostgroup -n cosmonic-systemhelm rollback restores the Helm release to its previous revision. Check the rollback status:
kubectl rollout status deploy -l app.kubernetes.io/instance=cosmonic-control -n cosmonic-system
kubectl rollout status deploy -l app.kubernetes.io/instance=hostgroup -n cosmonic-systemCRD rollback caveat
Helm does not downgrade CRDs on rollback — by design, to prevent accidental data loss. If the failed upgrade included CRD changes, rolling back the Helm release will leave the newer CRD versions in place.
If you need to roll CRDs back to a previous version, apply the old CRD manifests manually:
# Pull CRDs from the target (older) chart version
helm show crds oci://ghcr.io/cosmonic/cosmonic-control --version <previous-version> | kubectl apply -f -Verify the CRDs were restored before proceeding:
kubectl get crd | grep -E 'cosmonic|wasmcloud'Behavior changes since v0.4.0
A scan of operator-visible changes by release. Each entry links to the upgrade section below where the change is explained in full. Releases not listed here ship only dependency bumps and internal fixes; see cosmonic/control releases for those.
| Version | Change | Action |
|---|---|---|
| v0.9.3 | HostGroup memory defaults raised; new hostMemory knobs | Review sizing before upgrade; the larger default request can leave host pods Pending |
| v0.9.3 | Host health-probe listener (/healthz, /readyz on 9192) | None needed; set health.enabled: false to disable |
| v0.9.3 | caBundle now trusts a private CA for image pulls | None unless pulling from a registry behind a private CA |
| v0.9.3 | wasmcloud:nats host plugin (core, JetStream, KV) | Configure on the HostGroup to grant workloads NATS access |
| v0.9.3 | Warm-pool idle reclaim (reclaimWindowSeconds, reclaimMinInstances) | None needed; additive and opt-in per component |
| v0.9.2 | control-host image is now a glibc build (unblocks GPU and native host plugins) | None — a host group picks it up on chart bump; only matters if you run the host on a custom base (needs glibc ≥ 2.34) |
| v0.7.0 | Default resource requests and limits on every pod | Review sizing after upgrade; raise or remove limits that don't fit your cluster |
| v0.7.0 | Hardened pod and container securityContexts by default | None unless a container must write outside its mounted volumes |
| v0.7.0 | Baseline NetworkPolicies (networkPolicy.enabled, on by default) | Set networkPolicy.enabled: false if a service mesh manages network policy |
| v0.7.0 | Named host interfaces and hostInterfaces admission validation | Deduplicate hostInterfaces entries that share a namespace:package before re-applying manifests |
| v0.6.x and earlier | Nexus StatefulSet PVC migration, Traefik-as-default ingress, Console/Cloud removal, CA bundle, unpinned trigger environment | Prefer a fresh install of the current chart; upgrading in place, migrate the nexus-data PVC and drop removed values |
Upgrading from v0.6.x or earlier
These are large jumps to the current chart, and each intervening release carried its own CRD and values changes. For a gap this size, a fresh install of the current chart is usually simpler than an in-place upgrade; the cosmonic/control release notes carry the per-version detail. If you do upgrade in place, apply the current CRDs first (see Standard upgrade) and account for the load-bearing changes from that era:
- Nexus persistence moved to a StatefulSet (v0.6.0). The
nexus.persistence.existingClaimvalue was removed. Migrate any pre-v0.6.0nexus-dataPVC ontodata-nexus-0before upgrading, or you lose durablewasi:keyvalueand Artifact JetStream state. Nexus also gained HA throughnexus.replicas(an odd number, for RAFT quorum). - Traefik became the default ingress (v0.4.0 and v0.4.1). Set
ingress.provider: istioif you rely on Istio, oringress.enabled: falseto expose Envoy directly. - Console and Cloud components were removed (v0.4.0). Delete any
console:andconsole_ui:blocks from your values. - CA bundle support was added (v0.5.0, opt-in), and
HTTPTrigger.spec.environmentbecame unpinned by default (v0.5.2); setenvironmentexplicitly on triggers that must stay on a tenant-scoped host group.
Then follow the v0.6.1 to v0.7.0 section below, which establishes the current baseline: default resource requests and limits, hardened pod securityContexts, baseline NetworkPolicies, and hostInterfaces admission validation.
Upgrading from v0.6.1 to v0.7.0
Chart 0.7.0 ships appVersion 0.7.0 and bumps the control-host image to wasmCloud v2.5.1. The release hardens every pod both charts deploy — securityContexts, resource limits, probes, and NetworkPolicies are now on by default — and adds admission-time validation plus named routing to hostInterfaces. All of the hardening is overridable through values, but an upgrade of an existing release changes running pods, so review the sections below before running helm upgrade.
Apply the updated CRDs
helm show crds oci://ghcr.io/cosmonic/cosmonic-control --version 0.7.0 | kubectl apply -f -The v0.7.0 CRDs add size bounds on hostInterfaces (at most 64 entries; name and version capped at 64 characters, namespace and package at 128) and two admission rules, enforced via CEL validation on create and update:
- No two entries may be exact duplicates — the same
namespace,package,name, andversion. - At most one entry of a given
namespace:packagemay be unnamed. The unnamed entry is the default route and cannot be shared; give additional entries of the same package distinctnames.
Validation runs at admission, so objects already stored in the cluster are untouched until their next update. Audit any manifests that declare multiple hostInterfaces entries for the same namespace:package before re-applying them — entries that violate either rule are rejected with a descriptive error.
Named host interfaces and hostInterfaces admission validation
The name field on a hostInterfaces entry (present since v0.4.1) is now a routing identity end to end: the wasmCloud v2.5.1 host routes a component's named (implements <name>) imports by it, so a workload can import the same namespace:package more than once and resolve each import to a differently configured backend. Entries that share a namespace, package, and name with semver-compatible versions merge to the highest version, per the component model's canonical-version rules; semver-incompatible versions of the same package coexist as distinct interfaces.
See Named host interfaces for the manifest shape and a worked example.
Pods now ship default resource requests and limits
Every resources block in both charts previously defaulted to {} — pods ran unconstrained unless your values file said otherwise. As of v0.7.0, every container ships a memory request and limit plus a CPU request. CPU is deliberately request-only: a CPU limit only throttles, so none is set.
Upgrading an existing release imposes these limits on all pods. The defaults are sized conservatively for a small cluster; components under real load may need more:
operator.resources— the informer cache grows with the number of watched objects (Hosts, Workloads, Pods, EndpointSlices). Raise the192Midefault limit for large clusters.prometheus.resources— TSDB memory scales with active series; the default limit is512Mi.- HostGroup
resources— host pods run Wasm components in-process, so memory scales with the workloads scheduled onto each host. Sizelimits.memory(default512Mi) for your expected per-host workload density, or remove the limit to leave host memory uncapped.
Values you already set win over the new defaults. After upgrading, watch for OOMKilled restarts (kubectl get pods -n cosmonic-system will show them) and raise the affected component's limit. See Resource sizing.
Pods are hardened by default
Every container in both charts now runs with a hardened securityContext: runAsNonRoot (UID 65532 for first-party images, 10001 for bundled third-party images), the RuntimeDefault seccomp profile, all capabilities dropped, privilege escalation disabled, and readOnlyRootFilesystem with writable emptyDir volumes mounted where a process legitimately writes (a universal /tmp, the host's HOME, Prometheus's TSDB, Tempo's trace store). Liveness and readiness probes now cover every container, and automountServiceAccountToken is disabled everywhere the Kubernetes API isn't used — it stays on only for the operator, the Perses provisioning sidecar, and Traefik.
Stock installs need no changes. Override any field via values if an extension writes outside its mounted volumes — for example, a HostGroup plugin that writes to the container filesystem:
# hostgroup-values.yaml
securityContext:
readOnlyRootFilesystem: falseBaseline NetworkPolicies
Both charts gain a networkPolicy.enabled value, on by default. Each enabled component gets a NetworkPolicy whose podSelector matches its pods, restricting ingress to the ports the component actually serves. Egress is intentionally left unrestricted — the operator talks to the Kubernetes API, hosts pull OCI images from arbitrary registries, and components export telemetry to one another — so tightening egress is left to environment-specific policy.
On a CNI without NetworkPolicy support the objects are inert. Set networkPolicy.enabled: false in either chart's values if a service mesh or cluster-level policy engine manages this instead.
With the values file updated and CRDs applied, run the Standard upgrade flow with --version 0.7.0.
Upgrading from v0.9.1 to v0.9.2
Chart 0.9.2 ships appVersion 0.9.2. This is a low-risk patch: there are no CRD or values changes, so stock installs upgrade with the Standard upgrade flow and --version 0.9.2. One behavior change is worth knowing.
This guide documents upgrades through v0.7.0 and then v0.9.2 and v0.9.3. If you are coming from v0.8.x, v0.9.0, or v0.9.1, review the cosmonic/control release notes for changes in those releases.
The control-host image is now a glibc build
The control-host release image is now built against glibc (floor 2.34) rather than statically against musl. A static musl build's dlopen is a stub that always fails, which blocked the GPU release image and any host component plugin that loads a native library at runtime. On glibc those load correctly, and this release also unblocks the GPU-enabled control-host image and corrects Perses dashboard routing in the observability stack.
The published image runs on any glibc ≥ 2.34 base (Ubuntu 22.04 and newer), and a host group picks it up automatically when you bump the chart version. This floor matters only if you build or run the host on your own base image, which must then meet it.
Run the Standard upgrade flow with --version 0.9.2.
Upgrading from v0.9.2 to v0.9.3
Chart 0.9.3 ships appVersion 0.9.3 and pins the control-host wash-runtime past wasmCloud v2.8.0 to a revision on main that backs the new native wasmcloud:nats host plugin. This release changes the HostGroup memory defaults, adds a host health-probe listener, extends CA-bundle trust to image pulls, and adds two optional CRD fields. Stock installs upgrade with the Standard upgrade flow and --version 0.9.3, but the memory defaults change what the scheduler places, so review the sections below before running helm upgrade on an install that relies on the chart defaults.
Apply the updated CRDs
helm show crds oci://ghcr.io/cosmonic/cosmonic-control --version 0.9.3 | kubectl apply -f -The v0.9.3 CRDs add two optional fields to a Workload component's warm instance pool: reclaimWindowSeconds (how long the pool watches its own peak concurrency before retiring the warm instances that peak did not need) and reclaimMinInstances (a floor an idle sweep never retires below). Both are additive and preserve today's behavior (a pool that sets neither never reclaims warm instances for idleness), so existing Workloads are untouched until you opt in. See warm instance pools.
HostGroup memory defaults changed
The HostGroup chart now sizes host memory explicitly, and the defaults are larger than before. resources.requests.memory moves from 64Mi to 768Mi and resources.limits.memory from 512Mi to 6Gi, and a new hostMemory block governs how much of the pod the host hands to Wasm guests:
hostMemory.maxGuestMemory: total guest memory the host may hand out. Unset, the host derives it as three-quarters ofresources.limits.memory, so under Kubernetes it tracks the pod automatically; set it only to override.hostMemory.defaultHeapMemory(the chart ships1Gi): the ceiling on any single guest's linear memory, so one runaway component cannot exhaust the pod. Clear this value and the host falls back to wasmtime's 4GiB default, which exceeds the guest budget and makes the host warn at every start. Raising it is safe; lowering it is the change that needs testing.hostMemory.coreInstances: instance slots the pooling allocator keeps (wasmtime's default is 1000). Multiplied bydefaultHeapMemorythis is the pool's virtual reservation, mappedPROT_NONEand committed only as guests touch it, so the node needs nowhere near it and the pod's accounted memory is unaffected.
The host takes three-quarters of resources.limits.memory as its guest budget, reports the resolved numbers at startup (host memory resolved), and warns when defaultHeapMemory does not fit inside it. Because requests.memory is what the scheduler places on, the larger default request means an existing install that keeps the chart defaults will have its host pods request 768Mi and may reschedule onto nodes that can back it. Values you already set win over the new defaults, so an install that had sized resources for its workload density keeps those. Set hostMemory.defaultHeapMemory to fit within that guest budget. After upgrading, check for host pods stuck Pending (kubectl get pods -n cosmonic-system): a Pending host means its larger memory request does not fit the node, so lower resources.requests.memory to suit. The chart's values.yaml documents small/medium/large sizings; see also Resource sizing.
Host health-probe listener
The HostGroup gains a plaintext health listener, on by default, serving /healthz and /readyz for the kubelet's liveness and readiness probes:
# hostgroup-values.yaml
health:
enabled: true
port: 9192It is deliberately separate from the workload HTTP ingress, so probes never traverse TLS and a host with no ingress is still probed. Stock installs need no changes; set health.enabled: false only if the listener conflicts with your environment.
CA bundles now apply to image pulls
caBundle previously mounted your extra CA certificates over the container trust store, but the host's OCI client never read that store, so image pulls from a private registry fronted by an internal CA still failed. As of v0.9.3, enabling caBundle also passes --oci-ca-path to the host, so those CAs are honored for every image the host pulls: workload components and host component plugins alike. If you run a private registry with an internal CA, set caBundle.enabled: true and supply the bundle through caBundle.contents (or caBundle.mountPath); no other change is needed.
The wasmcloud:nats host plugin
This release adds a native wasmcloud:nats host plugin (NATS core pub/sub, JetStream, and KV) configured on the HostGroup with deny-by-default subject, stream, and bucket grants and per-binding overrides. It is operator-configured through hostPlugins and requires no new CRD. See The wasmcloud:nats host plugin.
Observability: the Envoy dashboard now populates
This release also fixes the bundled Envoy dashboard in the observability stack: the metrics collector can now reach the Envoy admin endpoint, so the dashboard renders data instead of coming up empty. No action is required, the dashboard definitions themselves are unchanged, and the fix applies on chart bump.
With the values file updated and CRDs applied, run the Standard upgrade flow with --version 0.9.3.