c9s
Release Notes

0.8

2026-08-18 · Full Changelog

Existing 0.7.x installations can upgrade in place.

Component-based Nokia SR-SIM support

Support for the Nokia SR-SIM nodes has been added for both single- and multi-component configurations. See the Nokia SR-SIM guide for details and examples.

Note, that the distributed SR-SIM nodes are running inside the single launcher pod, and are not distributed across multiple pods.

SR Linux management DNS

SR Linux nodes are now able to resolve cluster DNS names (using cluster DNS service like kube-dns or CoreDNS). This allows you to use node names in SR Linux configurations when the node reaches out to the other c9s nodes in the topology.

The cluster DNS IP is automatically added to the SR Linux configuration, so no manual configuration is needed.

Portable service ports

To enable the upcoming containerlab's "c9s as runtime" feature, we needed a way to encode in the topology file the ports that should be exposed by the c9s manager which are not using the containerlab's ports directive, since the ports directive exposes the ports to the local Docker host, and that is not always desired.

To provide this port metadata, the reserved node label c9s.run/exposePorts was added:

topology:
  nodes:
    gnmic:
      kind: linux
      image: ghcr.io/openconfig/gnmic:latest
      labels:
        c9s.run/exposePorts: "9273/tcp,8125/udp"

Entries use the same destination-port grammar as Node.spec.ports. The list of ports in this label will be used by the c9s manager to expose the ports via the K8s service.

The effective LauncherProfile still chooses whether the Service is ClusterIP, LoadBalancer, Headless, or disabled. See Service exposure.

Launcher affinity

Launcher Pods can now carry native Kubernetes node affinity, pod affinity, and pod anti-affinity.

Set spec.scheduling.affinity on a LauncherProfile to reuse one policy across every Node that references it. For a Topology, set the same structure at spec.deployment.scheduling.affinity; the controller copies it into generated shared and dedicated profiles. Grouped Nodes keep the primary profile's affinity on the shared launcher Pod.

Affinity labelSelector fields select peer Pods; they do not assign LauncherProfiles. See Resource management for Topology and LauncherProfile examples.

Containerd registry hosts for pull-through

Some Kubernetes distributions keep containerd registry mirrors, TLS certificates, and host configuration outside the default /etc/containerd/certs.d path. Pull-through launchers can now mount that node directory through global Config:

spec:
  imagePull:
    pullThroughOverride: always
    criHostsDir: /path/to/containerd/hosts

The directory is mounted read-only at both its original path and /etc/containerd/certs.d, so absolute certificate paths rooted in the node tree continue to work. The mount is omitted when pull-through is disabled or the effective CRI is not containerd. On Talos, the volume is an untyped hostPath so kubelet does not type-check a path that exists only in the host mount namespace.

See Image pull.

Readiness and topology compilation

With statusProbes.enabled, every non-excluded Node now gets startup and readiness probes, even when no TCP or SSH check is configured. Readiness is additive:

  • the nested Docker container is running and is not paused, restarting, or dead;
  • an image-defined Docker healthcheck, when present, is healthy;
  • configured TCP and SSH probes remain additional application-level requirements.

A running image without a healthcheck is still only process-level readiness. Grouped Nodes and expanded component sets share one atomic result: every nested container must pass the generic checks before the launcher reports ready. The manager Deployment also waits on /alive, so Helm rollouts do not become available before controllers have finished starting.

Topology compilation continues to warn, with source locations, when it omits lossy compatibility fields. Structures that cannot produce valid c9s resources now fail instead of emitting a partial lab: unresolved or special link endpoints, invalid launcher-group network modes, and unsupported explicit link types. Concurrent Node and Topology status writes retry from an uncached API read after a resource-version conflict.

Recovering from failed launcher deploys

If containerlab creates a host-side veth and then fails before moving both ends into nested namespaces, Kubernetes restarts only the launcher container. The stale interface used to survive in the pod network namespace and block every subsequent deploy until the pod was deleted.

The launcher now removes topology-defined host-side interfaces before invoking containerlab, while protecting lo, eth0, and docker0. Failed deploys can retry in place.

On this page