k8s-runner
August 9, 2026 ยท View on GitHub
k8s-runner is the Kubernetes-native implementation of the RunnerService gRPC API.
Architecture: k8s-runner
Local Development
Full setup: Local Development
Prepare environment
git clone https://github.com/agynio/bootstrap.git
cd bootstrap
chmod +x apply.sh
./apply.sh -y
See bootstrap for details.
Run from sources
# Deploy once (exit when healthy)
devspace dev
# Watch mode (streams logs, re-syncs on changes)
devspace dev -w
E2E tests
E2E coverage runs from the centralized suite in
agynio/e2e using the k8s_runner service tag.
See E2E Testing.
Docker capability notes
The docker capability injects a Docker sidecar. For the rootless
implementation, the sidecar runs nested runc and requires additional
permissions and mounts to allow docker run to work:
allowPrivilegeEscalation: truefor rootlesskit/newuidmap.seccompProfile: UnconfinedandappArmorProfile: Unconfinedbecause default RuntimeDefault/AppArmor profiles block mount-related syscalls (for example mounting/proc) required by nestedrunc.procMount: Unmaskedto avoid/procmount masking interfering with nestedrunccontainer setup.pod.spec.hostUsers: falsewith an init container that writes/etc/subuidand/etc/subgidentries inside the pod user namespace.- HostPath mount for
/dev/net/tun(typeCharDevice). docker-dataemptyDir mounted at/home/rootless/.local/shareso dockerd can create its owndocker/data root with correct ownership.
These settings can require Pod Security Admission exceptions for docker-capable workloads (baseline/restricted clusters may reject them).
Kata (microVM) docker runtimes
CAPABILITY_IMPLEMENTATIONS also supports docker: kata-qemu (and optionally
docker: kata-fc). When enabled, k8s-runner keeps the privileged DinD sidecar
behavior but sets pod.spec.runtimeClassName to match the selected Kata
implementation. The cluster must provide the matching RuntimeClass and schedule
onto KVM-capable nodes. This cannot be validated on local k3d/mac setups.
Workload egress NetworkPolicy
The Helm chart can install the static egress NetworkPolicy used by egress v1.
Enable workloadEgressNetworkPolicy.enabled and set workloadNamespace to the
namespace where runner-created workload pods run. The policy selects workload
pods with agyn.dev/managed-by=agents-orchestrator, allows OpenZiti synthetic
addresses (100.64.0.0/10), cluster DNS, and public internet, and excludes
workloadEgressNetworkPolicy.clusterPodCIDR,
workloadEgressNetworkPolicy.clusterServiceCIDR, and
workloadEgressNetworkPolicy.additionalInternalCIDRs from public internet
egress. blockedCIDRs remains as a deprecated compatibility alias.
Ziti underlay egress is configured with first-class chart values. Enable
zitiWorkloadDNS to allow workload pods to reach the Ziti workload DNS pods on
TCP/UDP 53. Configure zitiUnderlay.endpoints for the enrollment controller,
runtime Istio ingress gateway, and router underlay endpoints returned by
ziti-workload-dns. Each endpoint can allow a concrete service ClusterIP /32,
endpoint/backend pod CIDRs through backendCIDRs, a namespace/pod selector,
or a combination. Runtime ziti.<base-domain>:443 resolves to
the Istio ingress gateway so TLS passthrough can route SNI to the controller
client service. This keeps .agyn application traffic on the overlay while
allowing only the underlay endpoints required for sidecar startup:
workloadEgressNetworkPolicy:
zitiWorkloadDNS:
enabled: true
zitiUnderlay:
endpoints:
- name: controller
cidr: "10.43.245.186/32"
port: 2496
- name: ingress-gateway
cidr: "10.43.245.188/32"
backendCIDRs:
- "10.42.2.4/32"
namespaceSelector:
kubernetes.io/metadata.name: istio-system
podSelector:
istio: ingressgateway
port: 443
- name: router
cidr: "10.43.245.187/32"
port: 2496
Bootstrap should derive the underlay endpoint CIDRs from the live
ziti-controller-client, istio-ingressgateway, and ziti-router-edge
ClusterIPs. For the runtime ingress gateway endpoint, bootstrap should also
set endpoint pod CIDRs and the Istio ingress gateway namespace/pod selectors
when available so CNIs can follow endpoint pods instead of only the Service
ClusterIP. Set the controller and router ports to the configured
OpenZiti underlay port, and set the runtime ingress gateway port to 443.
The deprecated zitiControllerEnrollment and zitiRuntimeIngressGateway values
remain as named compatibility helpers for deployments that prefer fixed keys.
zitiRuntimeIngressGateway accepts the same runtime backend CIDR and selector
fields as zitiUnderlay.endpoints, but new bootstrap config should use
zitiUnderlay.endpoints for the complete endpoint set.
The runner runtime does not create or update NetworkPolicy resources, and its
ServiceAccount does not need networkpolicies RBAC.