Skip to main content

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.yaml

Upgrade the HostGroup release separately:

helm upgrade hostgroup oci://ghcr.io/cosmonic/cosmonic-control-hostgroup \
  --version 0.10.0 \
  --namespace cosmonic-system

Wait 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-system
Chart version vs. appVersion

Chart 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.0

Rolling 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-system

helm 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-system

CRD rollback caveat

warning

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.

VersionChangeAction
v0.9.3HostGroup memory defaults raised; new hostMemory knobsReview sizing before upgrade; the larger default request can leave host pods Pending
v0.9.3Host health-probe listener (/healthz, /readyz on 9192)None needed; set health.enabled: false to disable
v0.9.3caBundle now trusts a private CA for image pullsNone unless pulling from a registry behind a private CA
v0.9.3wasmcloud:nats host plugin (core, JetStream, KV)Configure on the HostGroup to grant workloads NATS access
v0.9.3Warm-pool idle reclaim (reclaimWindowSeconds, reclaimMinInstances)None needed; additive and opt-in per component
v0.9.2control-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.0Default resource requests and limits on every podReview sizing after upgrade; raise or remove limits that don't fit your cluster
v0.7.0Hardened pod and container securityContexts by defaultNone unless a container must write outside its mounted volumes
v0.7.0Baseline NetworkPolicies (networkPolicy.enabled, on by default)Set networkPolicy.enabled: false if a service mesh manages network policy
v0.7.0Named host interfaces and hostInterfaces admission validationDeduplicate hostInterfaces entries that share a namespace:package before re-applying manifests
v0.6.x and earlierNexus StatefulSet PVC migration, Traefik-as-default ingress, Console/Cloud removal, CA bundle, unpinned trigger environmentPrefer 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.existingClaim value was removed. Migrate any pre-v0.6.0 nexus-data PVC onto data-nexus-0 before upgrading, or you lose durable wasi:keyvalue and Artifact JetStream state. Nexus also gained HA through nexus.replicas (an odd number, for RAFT quorum).
  • Traefik became the default ingress (v0.4.0 and v0.4.1). Set ingress.provider: istio if you rely on Istio, or ingress.enabled: false to expose Envoy directly.
  • Console and Cloud components were removed (v0.4.0). Delete any console: and console_ui: blocks from your values.
  • CA bundle support was added (v0.5.0, opt-in), and HTTPTrigger.spec.environment became unpinned by default (v0.5.2); set environment explicitly 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:

  1. No two entries may be exact duplicates — the same namespace, package, name, and version.
  2. At most one entry of a given namespace:package may be unnamed. The unnamed entry is the default route and cannot be shared; give additional entries of the same package distinct names.

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 the 192Mi default limit for large clusters.
  • prometheus.resources — TSDB memory scales with active series; the default limit is 512Mi.
  • HostGroup resources — host pods run Wasm components in-process, so memory scales with the workloads scheduled onto each host. Size limits.memory (default 512Mi) 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: false

Baseline 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.

note

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 of resources.limits.memory, so under Kubernetes it tracks the pod automatically; set it only to override.
  • hostMemory.defaultHeapMemory (the chart ships 1Gi): 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 by defaultHeapMemory this is the pool's virtual reservation, mapped PROT_NONE and 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: 9192

It 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.