Pod Templates
The Function Runner builds each function evaluator pod from a base PodTemplate and a ServiceTemplate, then merges per-function overrides from the matching FunctionConfig. This is how you set resource limits, security context, service account, node scheduling, extra env, and service ports for function pods.
There is no --function-pod-template flag and no ConfigMap template.
The objects live in the function-pod namespace (default porch-fn-system) and are named base-pod-template and base-service-template.
For how those templates are used during pod creation, see Pod Lifecycle Management.
How templates are applied
On pod creation the function-runner:
- Gets
base-pod-template(corev1.PodTemplate) andbase-service-template(config.porch.kpt.dev/v1alpha1ServiceTemplate) from the function-pod namespace (--pod-namespace, defaultporch-fn-system). If either is missing, it creates it from the inline default shipped in the binary. - Patches the function container with the requested image, the wrapper-server command, the original image entrypoint as arguments, and any image-pull secret required for private registries.
- Patches pod metadata:
fn.kpt.dev/imagelabel andfn.kpt.dev/template-versionset to the PodTemplateresourceVersion. - Merges
spec.podExecutor.templateOverridesfrom the FunctionConfig for that image, if any. - Creates the pod and a ClusterIP Service from the ServiceTemplate.
Cluster-wide defaults (node selectors, extra volumes, security context that every function should inherit) belong on the base PodTemplate. Per-function CPU/memory, env, or service account belong on templateOverrides.
Template contract
Any custom base-pod-template must keep a container named function.
That container’s command must start the wrapper gRPC server; the function-runner replaces the image and appends the original function entrypoint to args.
An init container named copy-wrapper-server is expected as the first init container when templateOverrides.initContainer is used, because overrides are merged by index.
The Function Runner patches the template before creating pods. Leave the function image as a placeholder; it is always replaced.
Default templates
The default install deploys these objects (trimmed from deployments/porch/22-function-templates.yaml):
apiVersion: v1
kind: PodTemplate
metadata:
name: base-pod-template
namespace: porch-fn-system
template:
metadata:
annotations:
cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
spec:
initContainers:
- name: copy-wrapper-server
image: ghcr.io/kptdev/porch-wrapper-server:latest
command:
- cp
- -a
- /home/nonroot/wrapper-server/.
- /wrapper-server-tools
volumeMounts:
- name: wrapper-server-tools
mountPath: /wrapper-server-tools
containers:
- name: function
image: image-replaced-by-kpt-func-image
command:
- /wrapper-server-tools/wrapper-server
env:
- name: OTEL_METRICS_EXPORTER
value: prometheus
- name: OTEL_TRACES_EXPORTER
value: none
- name: OTEL_EXPORTER_PROMETHEUS_HOST
value: 0.0.0.0
readinessProbe:
exec:
command: ["/wrapper-server-tools/grpc-health-probe", "-addr", "localhost:9446"]
volumeMounts:
- name: wrapper-server-tools
mountPath: /wrapper-server-tools
volumes:
- name: wrapper-server-tools
emptyDir: {}
---
apiVersion: config.porch.kpt.dev/v1alpha1
kind: ServiceTemplate
metadata:
name: base-service-template
namespace: porch-fn-system
template:
spec:
ports:
- port: 9446
protocol: TCP
targetPort: 9446
name: server
selector:
fn.kpt.dev/image: to-be-replaced
type: ClusterIP
If you delete them, the function-runner recreates them from its inline defaults the next time it needs a pod. Edits you make to the live objects are used for subsequent pod creates.
Customizing the base PodTemplate
Edit base-pod-template in porch-fn-system to change every function pod.
Typical additions are resource requests and limits on the function container, a pod securityContext, nodeSelector / tolerations, and extra volumes.
kubectl edit podtemplate base-pod-template -n porch-fn-system
Example resource limits on the function container:
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
Example pod security context:
securityContext:
runAsNonRoot: true
runAsUser: 65532
fsGroup: 65532
seccompProfile:
type: RuntimeDefault
Per-function overrides
FunctionConfig spec.podExecutor.templateOverrides is merged after the base template is patched.
Supported fields are serviceAccountName, pod securityContext, and resources / env / envFrom on the init container and the function container.
Scheduling fields such as nodeSelector are not part of templateOverrides; put those on the base PodTemplate.
apiVersion: config.porch.kpt.dev/v1alpha1
kind: FunctionConfig
metadata:
name: gatekeeper
namespace: porch-fn-system
spec:
image: gatekeeper
podExecutor:
tags:
- v0.2.1
templateOverrides:
serviceAccountName: function-sa
container:
resources:
limits:
memory: "1Gi"
cpu: "1000m"
Template versioning
The Function Runner records the PodTemplate resourceVersion on each pod as fn.kpt.dev/template-version.
On the next reuse, a mismatch against the current template causes the old pod to be deleted and a new one created.
Existing pods keep serving until they are reused or garbage-collected, so template edits do not immediately disrupt in-flight evaluations.
RBAC
The default porch-function-executor Role in porch-fn-system already allows get/list/watch/create/update/patch on podtemplates and servicetemplates.
No extra Role is required for the base templates.
Troubleshooting
If pods fail to start after a template edit:
kubectl get pods -n porch-fn-system
kubectl describe pod -n porch-fn-system <pod-name>
kubectl logs -n porch-system deployment/function-runner
Common causes are invalid YAML on the PodTemplate, a missing function container, resource-quota or image-pull failures, and security-policy or node-selector mismatches. If the function-runner logs that it cannot get base-pod-template or base-service-template, check that the RoleBinding for porch-function-executor is present in porch-fn-system.