Skip to main content

Runtime

Overview​

The Runtime custom resource is the primary way to configure a Heir tenant cluster. Its spec is split into two top-level sections:

  • controlPlane — controls how the tenant control plane is deployed inside the management cluster (image, replicas, service exposure, plane tunnel)
  • cluster — controls the Kubernetes cluster itself (networking, storage, API server configuration, worker node settings, addons)
kind: Runtime
metadata:
name: my-cluster
namespace: default
spec:
controlPlane: ...
cluster: ...

spec.controlPlane​

Configures the Deployment and Service created in the management cluster to host the Heir control plane, plus the plane tunnel that lets worker nodes reach it.

controlPlane.heir​

FieldTypeDescriptionDefault
imagestringFully qualified container image for the Heir control plane, e.g. ghcr.io/tardigradeproj/heir:v1.2.3—

controlPlane.clusterAgent​

FieldTypeDescriptionDefault
imagestringFully qualified container image for the Heir ClusterAgent, e.g. ghcr.io/tardigradeproj/clusteragent:v1.2.3—

controlPlane.deployment​

FieldTypeDescriptionDefault
replicasintegerDesired number of control plane pod replicas1
serviceAccountNamestringServiceAccount mounted into the control plane podsdefault
runtimeClassNamestringReferences a RuntimeClass that controls which container runtime is used. Omit to use the cluster default—
tolerations[]TolerationTolerations applied to the control plane pods. See Kubernetes docs—
affinityAffinityScheduling constraints for the control plane pods. See Kubernetes docs—
resourcesResourceRequirementsCPU and memory requests and limits for the control plane container—
additionalMetadata.labelsmap[string]stringExtra labels added to the Deployment—
additionalMetadata.annotationsmap[string]stringExtra annotations added to the Deployment—

controlPlane.service​

Controls how the tenant control plane's API server is exposed outside the management cluster.

FieldTypeDescriptionDefault
serviceTypestringHow the Service is exposed. One of NodePort, ClusterIP, LoadBalancer, ExternalNameNodePort
apiServerNodePortintegerNodePort assigned to the API server port. Only applies when serviceType is NodePort30080
additionalPorts[]AdditionalPortExtra ports added to the Service beyond the default API server port—
additionalMetadata.labelsmap[string]stringExtra labels added to the Service—
additionalMetadata.annotationsmap[string]stringExtra annotations added to the Service—

additionalPorts​

FieldTypeDescriptionDefault
namestringPort name within the Service. Must be unique across all ports—
portintegerPort number exposed by the Service—
targetPortinteger or stringPort number or named port on the control plane pod that receives this traffic—
protocolstringIP protocol for this port. One of TCP, UDP, SCTPTCP
appProtocolstringHint to implementations about the application-layer protocol on this port, e.g. https—

controlPlane.planeTunnel​

The plane tunnel is a TCP multiplexer that lets worker nodes reach the tenant control plane over a single outbound connection, so no inbound connectivity to worker nodes is ever required. It runs as its own Deployment and Service in the management cluster, separate from the control plane's own Deployment and Service above.

planeTunnel.server​

FieldTypeDescriptionDefault
imagestringContainer image for the plane tunnel serverghcr.io/tardigradeproj/heir-tunnel:latest
deployment.replicasintegerDesired number of plane tunnel server pod replicas1
deployment.serviceAccountNamestringServiceAccount mounted into the plane tunnel server podsdefault
deployment.runtimeClassNamestringReferences a RuntimeClass that controls which container runtime is used. Omit to use the cluster default—
deployment.tolerations[]TolerationTolerations applied to the plane tunnel server pods—
deployment.affinityAffinityScheduling constraints for the plane tunnel server pods—
deployment.resourcesResourceRequirementsCPU and memory requests and limits for the plane tunnel server container—
deployment.additionalMetadata.labelsmap[string]stringExtra labels added to the Deployment—
deployment.additionalMetadata.annotationsmap[string]stringExtra annotations added to the Deployment—

planeTunnel.service​

FieldTypeDescriptionDefault
serviceTypestringHow the Service is exposed. One of NodePort, ClusterIP, LoadBalancer, ExternalNameNodePort
nodePortintegerNodePort assigned to the plane tunnel port. Only applies when serviceType is NodePort30081
additionalMetadata.labelsmap[string]stringExtra labels added to the Service—
additionalMetadata.annotationsmap[string]stringExtra annotations added to the Service—

spec.cluster​

Defines the configuration for the Heir Kubernetes cluster being created, including networking, storage, and individual component settings.

cluster.controlPlaneExternalEndpoint​

Describes the per-component address and port through which worker nodes reach the API server and plane tunnel. The two components can be exposed on different hosts, allowing them to sit behind separate load balancers.

FieldTypeDescriptionDefault
apiServer.hoststringIP address or hostname of the API server endpoint, as reached by worker nodes. Must be a bare hostname or IP, no URL scheme or port suffix—
apiServer.portintegerPort on the above host that exposes the Kubernetes API server30080
planeTunnel.hoststringIP address or hostname of the plane tunnel endpoint, as reached by worker nodes. Must be a bare hostname or IP, no URL scheme or port suffix—
planeTunnel.portintegerPort on the above host that exposes the plane tunnel server30081

cluster.apiServer​

FieldTypeDescription
sans[]stringAdditional Subject Alternative Names added to the API server's serving certificate. Use this to include load-balancer IPs, external hostnames, or any address through which clients reach the API server
extraArgsmap[string]stringExtra flags passed directly to kube-apiserver. Keys are flag names without the leading --

cluster.controllerManager​

FieldTypeDescription
extraArgsmap[string]stringExtra flags passed directly to kube-controller-manager. Keys are flag names without the leading --

cluster.scheduler​

FieldTypeDescription
extraArgsmap[string]stringExtra flags passed directly to kube-scheduler. Keys are flag names without the leading --

cluster.network​

Configures pod and service networking and kube-proxy deployed inside the tenant cluster.

FieldTypeDescriptionDefault
podCIDRstringIP range from which pod IP addresses are allocated10.244.0.0/16
serviceCIDRstringIP range from which ClusterIP service addresses are allocated10.96.0.0/16
dnsDomainstringDNS domain suffix for the tenant clustercluster.local

network.kubeProxy​

FieldTypeDescriptionDefault
disabledbooleanSet to true to skip deploying kube-proxy entirely, e.g. when a CNI plugin provides its own replacementfalse
modestringkube-proxy proxying mode. One of iptables, ipvs, userspace, nftiptables
registrySettings.registrystringContainer registry hostname for the kube-proxy imageregistry.k8s.io
registrySettings.imagestringkube-proxy image name and tag within the registrykube-proxy:v1.35.7
registrySettings.pullPolicystringImage pull policy for the kube-proxy container—
metricsBindAddressstringAddress kube-proxy binds its metrics endpoint to—
nodePortAddresses[]stringRestricts NodePort traffic to the given address ranges—
extraArgsmap[string]stringExtra flags passed directly to the kube-proxy process—
iptables.masqueradeBitintegerfwmark bit used to mark packets for SNAT, in the iptables backend—
iptables.masqueradeAllbooleanSNAT all traffic sent via ClusterIP, in the iptables backend—
iptables.localhostNodePortsbooleanAllow NodePort services to be accessed via localhost, in the iptables backend—
iptables.syncPerioddurationMaximum interval between iptables rule resyncs—
iptables.minSyncPerioddurationMinimum interval between iptables rule resyncs—
ipvs.schedulerstringIPVS load balancing algorithm—
ipvs.excludeCIDRs[]stringCIDRs excluded from IPVS load balancing—
ipvs.strictARPbooleanEnable strict ARP mode, required by some load-balancer integrations (e.g. MetalLB)—
ipvs.syncPerioddurationMaximum interval between IPVS rule resyncs—
ipvs.minSyncPerioddurationMinimum interval between IPVS rule resyncs—
ipvs.tcpTimeoutdurationIPVS TCP session timeout—
ipvs.tcpFinTimeoutdurationIPVS TCP FIN wait timeout—
ipvs.udpTimeoutdurationIPVS UDP session timeout—
nftables.masqueradeBitintegerfwmark bit used to mark packets for SNAT, in the nftables backend—
nftables.masqueradeAllbooleanSNAT all traffic sent via ClusterIP, in the nftables backend—
nftables.syncPerioddurationMaximum interval between nftables rule resyncs—
nftables.minSyncPerioddurationMinimum interval between nftables rule resyncs—

cluster.storage​

Configures the storage backend used by the tenant API server in place of etcd.

FieldTypeDescriptionDefault
typestringStorage backend to use. Currently only kine is supportedkine
kine.dataSourceRefSecretKeySelectorReference to a Secret key whose value is the kine data source URL, e.g. a SQLite file path or a PostgreSQL connection string. When omitted, kine uses its default SQLite storage location—

Example — kine.dataSourceRef:

cluster:
storage:
type: kine
kine:
dataSourceRef:
name: my-db-secret # name of the Kubernetes Secret
key: connection-url # key within the Secret whose value is the data source URL

cluster.kubelet​

Configuration applied to kubelet on every worker node that joins this tenant cluster.

FieldTypeDescription
extraArgsmap[string]stringExtra flags passed directly to the kubelet process. Keys are flag names without the leading --
configPatchesstringPartial KubeletConfiguration document strategically merged on top of the default kubelet configuration written to worker nodes. Only the fields you specify are overridden

Example — configPatches:

cluster:
kubelet:
configPatches: |
maxPods: 200
evictionHard:
memory.available: "100Mi"
nodefs.available: "10%"
kubeReserved:
cpu: "250m"
memory: "256Mi"

cluster.addons​

Configures cluster addons installed via the HelmChart controller. coredns and flannel are built-in default addons, enabled automatically.

FieldTypeDescriptionDefault
helm.runtime.imagestringImage that runs helm for every addon's installer Jobghcr.io/tardigradeproj/helmer:latest
helm.charts[]AddonChartSpecList of addons to enable, disable, install, or override—

AddonChartSpec​

FieldTypeDescription
namestringIdentifies the addon
enabledbooleanSet to false to disable one of Heir's built-in default addons (coredns, flannel). Only applies to a built-in addon
installHelmChartSpecAdds an entirely new Helm chart for an addon that isn't one of Heir's built-in defaults. Mirrors a HelmChart resource's own spec exactly
override.valuesValuesSpecCustomizes one of Heir's built-in default addons' Helm values, without changing its chart source

Addon values​

FieldTypeDescription
setmap[string]stringOverrides simple chart values. Takes precedence over content
contentstringOverrides complex chart values via inline YAML content

Example — disabling a built-in addon and overriding another:

cluster:
addons:
helm:
charts:
- name: flannel
enabled: false
- name: coredns
override:
values:
content: |
replicaCount: 3
- name: metrics-server
install:
chart:
name: metrics-server
repo: https://kubernetes-sigs.github.io/metrics-server/
targetNamespace: kube-system

Full Example​

kind: Runtime
metadata:
name: my-cluster
namespace: default
spec:
controlPlane:
heir:
image: ghcr.io/tardigradeproj/heir:latest
clusterAgent:
image: ghcr.io/tardigradeproj/clusteragent:latest
deployment:
replicas: 1
serviceAccountName: default
service:
serviceType: NodePort
apiServerNodePort: 30080
planeTunnel:
service:
serviceType: NodePort
nodePort: 30081
cluster:
controlPlaneExternalEndpoint:
apiServer:
host: "127.0.0.1"
port: 30080
planeTunnel:
host: "127.0.0.1"
port: 30081
network:
podCIDR: "10.244.0.0/16"
serviceCIDR: "10.96.0.0/16"
storage:
type: kine
apiServer:
extraArgs:
audit-log-maxage: "30"
kubelet:
extraArgs:
max-pods: "110"
addons:
helm:
charts:
- name: coredns
override:
values:
content: |
replicaCount: 2