Node profiles
Reusable direct-workload Kubernetes policy referenced explicitly by network Nodes.
A NodeProfile contains reusable Kubernetes policy for the direct device workload that
realizes one or more Nodes. It keeps Kubernetes deployment concerns separate from the
containerlab-shaped Node payload.
Typical profile settings include:
- CPU and memory for a Node's primary application container
- scheduling, tolerations, and affinity rules
- service exposure
- Kubernetes image pull policy and pull Secrets
- status probes
- persistence
- management overlay address allocation
Device privilege, capabilities, and devices are never profile policy: they come from the imported containerlab package's plan.
Explicit references
A Node references at most one NodeProfile in the same namespace:
apiVersion: c9s.run/v1alpha1
kind: NodeProfile
metadata:
name: lab-policy
spec:
resources:
requests:
memory: 4Gi
cpu: "2"
statusProbes:
enabled: true
---
apiVersion: c9s.run/v1alpha1
kind: Node
metadata:
name: srl1
spec:
profileRef:
name: lab-policy
kind: nokia_srlinux
image: ghcr.io/nokia/srlinux:26.3Profiles are not selected by labels and are not merged into inheritance chains. Fields set on the
referenced profile take precedence over supported global Config defaults; omitted fields use
their built-in defaults or, where available, Config resolution. Service exposure uses the built-in
LoadBalancer default because Config has no exposure-mode field. Set spec.expose.exposeType to
ClusterIP, Headless, or None to override it.
The spec.scheduling.affinity field accepts the native Kubernetes node affinity, pod affinity, and
pod anti-affinity structure. A single NodeProfile can be referenced by multiple Nodes, so the
same affinity policy can be reused across direct device Pods. For a Topology, configure the
equivalent field at spec.deployment.scheduling.affinity; the Topology controller copies it into
the generated NodeProfile.
c9s considers a Node ready only when every device application container representing it is running
and passes its Kubernetes probes: readiness behavior declared by the imported containerlab plan,
and any image-defined OCI healthcheck or Node healthcheck contract merged over it, translate
into container startup and readiness probes. When statusProbes.enabled is true, optional TCP or
SSH probe configuration adds an application-level requirement executed inside the device
container; c9s does not infer ports, credentials, or behavior from a containerlab kind or image
name.
For a kind whose imported plan declares no readiness behavior and an image without a healthcheck,
this generic signal is intentionally process-level: a running network OS may still be booting
services or converging protocols. Declare a healthcheck, define one in the image, or configure
an explicit TCP or SSH probe when application-level readiness is required.
SSH probe credentials are stored in a Secret that c9s creates for the Node; the probe workload
reads the password from that Secret. The planner finishes its input and plan before resolving probe
credentials. If the same bytes already appear in the declared topology or generated plan, such as
the Cumulus VX default password included by containerlab, c9s does not treat that coincidence as
a leaked probe password. Other Secret values remain screened from plan artifacts. A refused plan
is reported on the Node as PlanApplied=False with reason PlanRejected and a Warning event; the
last applied workload keeps running.
If a Node names a profile that does not exist, c9s does not silently fall back to global defaults. The Node remains unrealized until that explicit reference resolves.
Profiles generated from Topology
The Topology compiler normally creates one shared NodeProfile and references it from every generated Node. A Node with distinct resource policy receives a complete dedicated profile rather than a partial child profile.