PodTemplate
Package: flyte
Custom PodTemplate specification for a Task.
Parameters
class PodTemplate(
pod_spec: Optional['V1PodSpec'],
primary_container_name: str,
labels: Optional[Dict[str, str]],
annotations: Optional[Dict[str, str]],
)| Parameter | Type | Description |
|---|---|---|
pod_spec |
Optional['V1PodSpec'] |
|
primary_container_name |
str |
|
labels |
Optional[Dict[str, str]] |
|
annotations |
Optional[Dict[str, str]] |
Methods
| Method | Description |
|---|---|
allow_fuse() |
Return a copy of this template granted everything an unprivileged. |
allow_nested_sandboxing() |
Return a copy of this template granted the prerequisites for creating. |
from_spec() |
Create a :class:PodTemplate from an existing V1PodSpec. |
to_k8s_pod() |
allow_fuse()
def allow_fuse(
privileged: bool,
) -> PodTemplateReturn a copy of this template granted everything an unprivileged
container needs to perform an in-process FUSE mount (e.g. for Volume
support).
By default (privileged=False) the copy:
- requests the
smarter-devices/fuseextended resource (request + limit) on the primary container, so the cluster’s FUSE device plugin (smarter-device-manager / fuse-device-plugin DaemonSet) injects/dev/fuseinto the container’s devices-cgroup allowlist — making the node device usable from an unprivileged container; and - adds
CAP_SYS_ADMINto the primary container, required for themount(2)syscall that attaches the FUSE filesystem; - stamps the
flyte.org/capability-fuseannotation for auditability.
It does not set privileged: true and does not add a
/dev/fuse hostPath. A hostPath only makes the device node visible;
the devices cgroup still denies open() with EPERM — the device
plugin is what actually grants access. This default composes with
allow_nested_sandboxing(). The cluster must run a FUSE device plugin
advertising smarter-devices/fuse (the Union dataplane chart ships an
opt-in fuseDevicePlugin DaemonSet for this).
privileged=True is a legacy escape hatch for clusters without a
FUSE device plugin: it instead adds a /dev/fuse hostPath volume +
mount and sets privileged: true on the primary container (the device
cgroup is bypassed by privilege). It does not compose with
allow_nested_sandboxing() (Kubernetes rejects privileged containers
that set allowPrivilegeEscalation: false).
AppArmor note: on clusters that enforce a restrictive default AppArmor
profile, the mount syscall may additionally need the primary
container’s profile set to unconfined — set that annotation on the
template yourself if needed; it is not applied by default to keep this
grant minimal.
The original template is never mutated; existing volumes, mounts, resources, sidecars, labels, annotations, and unrelated security-context fields are preserved. Re-applying with the same arguments is idempotent.
Raises ValueError if the template already pins a conflicting security
posture (with privileged=True: privileged: false or
allowPrivilegeEscalation: false pre-set).
| Parameter | Type | Description |
|---|---|---|
privileged |
bool |
allow_nested_sandboxing()
def allow_nested_sandboxing()Return a copy of this template granted the prerequisites for creating
nested sandboxes (e.g. the bubblewrap/bwrap backend of
SandboxEnvironment) — and nothing more.
bwrap runs as a non-root user via unprivileged user namespaces, but the
containerd default seccomp profile only permits the mount /
pivot_root / setns / unshare syscalls it needs when the
container’s capability set includes CAP_SYS_ADMIN, and the default
AppArmor profile must be unconfined so those calls aren’t blocked.
The copy carries exactly that:
CAP_SYS_ADMINadded to the primary container’s capabilities;allowPrivilegeEscalation: false(no other caps, not privileged);- the
container.apparmor.security.beta.kubernetes.io/<primary>: unconfinedpod annotation (on K8s >= 1.30 thesecurityContext.appArmorProfile: {type: Unconfined}field is the equivalent; the annotation is used here for version compatibility); - the
flyte.org/capability-nested-sandboxingannotation for auditability.
A cluster that already permits unprivileged user namespaces needs none
of this for the userns sandbox backend — only use this when the
seccomp/AppArmor defaults block the sandboxing syscalls.
Composes with allow_fuse(privileged=False); not with the default
allow_fuse(), which makes the container privileged.
The original template is never mutated; existing fields are preserved
and re-applying is idempotent. Raises ValueError if the template
already pins a conflicting security posture (privileged: true,
allowPrivilegeEscalation: true, or a different AppArmor profile
for the primary container).
from_spec()
def from_spec(
pod_spec: 'V1PodSpec',
primary_container_name: Optional[str],
labels: Optional[Dict[str, str]],
annotations: Optional[Dict[str, str]],
) -> PodTemplateCreate a :class:PodTemplate from an existing V1PodSpec.
The spec is deep-copied, so later mutations of the input (or of the returned template) don’t leak into each other.
The primary container — the one Flyte injects the task image/command into — is resolved as follows:
- If
primary_container_nameis given, a container with that name must exist in the spec. - Otherwise, a container named
primaryis used if present. - Otherwise, if the spec has exactly one container, that container is adopted as the primary.
- Otherwise (multiple containers, none named
primary), aValueErroris raised — passprimary_container_nameto pick one explicitly.
| Parameter | Type | Description |
|---|---|---|
pod_spec |
'V1PodSpec' |
The kubernetes.client.V1PodSpec to wrap. |
primary_container_name |
Optional[str] |
Optional explicit name of the primary container within pod_spec. |
labels |
Optional[Dict[str, str]] |
Optional pod labels. |
annotations |
Optional[Dict[str, str]] |
Optional pod annotations. |
to_k8s_pod()
def to_k8s_pod()