Skip to content
Container Runtimes

Container Runtimes

Podplane runs Pods in the gVisor sandbox by default. gVisor gives each Pod its own application kernel, so a compromised container attacks gVisor rather than the node’s Linux kernel. You don’t need to change your app to use it.

Some workloads need the node’s kernel directly, for compatibility or measured performance. Those can run under runc, the standard container runtime, in namespaces an admin has allowed.

How Pods get their runtime

Podplane provides two RuntimeClasses, gvisor and runc, and checks every new Pod, whoever creates it:

Pod’s runtimeClassNameNamespace allows runcResult
Not set, or gvisorEitherRuns in gVisor
runcNoRejected
runcYesRuns under runc
Anything else, including ""EitherRejected

Allowing runc doesn’t change the default: Pods in that namespace still run in gVisor unless they ask for runc. Pod Security still applies under both runtimes, and runc does not grant privileged access to the node.

Using runc

To run a deployment template under runc:

podplane deploy web --name app --image myorg/app --set runtimeClassName=runc

In your own manifests, set it in the Pod template:

spec:
  template:
    spec:
      runtimeClassName: runc

The selection applies to every container in the Pod, including init and ephemeral containers.

Allowing runc in a namespace

Only cluster admins can allow runc, by labelling the namespace:

kubectl label namespace native-workloads runtime.podplane.dev/runc=allowed

The value must be exactly allowed. Remove the label to stop new runc Pods; running Pods keep their runtime until they are replaced.

The permission applies to everyone who can create Pods in the namespace. To limit it to particular people or automation, use a dedicated restricted namespace and grant access with RoleBindings:

apiVersion: v1
kind: Namespace
metadata:
  name: native-workloads
  labels:
    runtime.podplane.dev/runc: allowed
    rbac.podplane.dev/restricted: "true"

What differs under gVisor

Most apps run unchanged. These differences come up most often:

  • Watching files: apps notice updated ConfigMaps, Secrets, and certificates by reading them, but inotify watches never fire for those updates. Poll the files instead. The web template’s Envoy sidecar already handles this for automatically reloading rotated certificates.

  • Sockets shared between containers: containers in a Pod see separate copies of an emptyDir, so a Unix socket one creates is invisible to the others. Share the volume with these Pod annotations, using a mount path that doesn’t end in /:

    metadata:
      annotations:
        dev.gvisor.spec.mount.<volume>.share: pod
        dev.gvisor.spec.mount.<volume>.type: tmpfs
  • Node access: host networking, the node’s Unix sockets, /dev/kmsg, and mount propagation don’t work. Host ports and read-only hostPath files do.

  • Seccomp: a Pod’s seccomp profile isn’t applied inside the sandbox; gVisor itself runs under a strict seccomp filter on the node.

If an app doesn’t work in gVisor, it fails visibly. Podplane never falls back to runc automatically.

Platform components

Platform components run in gVisor unless they need node access it can’t provide. Cilium, the CSI drivers, the Secrets Store providers, and Node Problem Detector run under runc, and their namespaces allow it. Kubelet static Pods, such as the VM tunnel in kube-system, also run under runc.

Bare clusters

Clusters created with --components=none have both runtimes on their nodes but no Podplane runtime policies, so their Pods run under runc. The API server’s Pod Security defaults still apply. Installing components enables the runtime policies for new Pods; recreate any existing Pods to move them into gVisor.

Troubleshooting

See which runtime each Pod uses, and which namespaces allow runc:

kubectl get pods -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,RUNTIME:.spec.runtimeClassName
kubectl get namespaces -l runtime.podplane.dev/runc=allowed

Rejected Pods appear as a FailedCreate event and a ReplicaFailure condition on the Deployment. podplane deploy explains these rejections when a deploy times out; for other workloads, check the Deployment:

kubectl describe deployment <name>
  • RuntimeClass "runc" requires namespace ... to have the label ...: ask an admin to allow runc in the namespace, or remove runtimeClassName: runc.
  • RuntimeClass "..." is not supported: use gvisor or runc, or omit runtimeClassName.