Configure sync and setup Jobs
Configure the controller's sync and setup Jobs to meet cluster policies. For Cortex's status exporter Deployment, use the exporter overlay.
Apply Job settings
You need permission to manage ConfigMaps in kratix-platform-system and an installed
Portal Controller. These settings apply to every portal, not just one Promise.
-
Save the complete ConfigMap below as
portal-workloads.yaml. Edit the example labels, annotations and node selector for your cluster; remove settings you do not need. -
Review the protected fields before adding container overrides.
-
Apply the file:
kubectl apply --filename portal-workloads.yaml -
Verify that new Jobs and their Pods carry the intended settings.
You configure these settings in the ske-portal-workloads-config ConfigMap in the kratix-platform-system namespace, under the workloads.yaml key:
apiVersion: v1
kind: ConfigMap
metadata:
name: ske-portal-workloads-config
namespace: kratix-platform-system
data:
workloads.yaml: |
jobTemplate:
metadata:
labels:
app.kubernetes.io/name: ske-portal
acs.customer.com/securityZone: dmz
annotations:
acs.customer.com/owner: platform-team
spec:
backoffLimit: 5
ttlSecondsAfterFinished: 3600
template:
spec:
nodeSelector:
kubernetes.io/os: linux
jobTemplate is a partial Kubernetes
JobTemplateSpec.
The controller merges it into each Job it builds: Promise sync Jobs, Resource sync Jobs, and portal
setup Jobs.
Manage this ConfigMap directly; there is no equivalent SKEIntegration field.
It applies to every portal instance.
Changes recreate affected Jobs. Deleting the ConfigMap restores defaults.
Labels and annotations reach the pods
jobTemplate.metadata applies to Jobs and their Pods.
For Pod-only metadata, use jobTemplate.spec.template.metadata. Pod-level values win conflicts.
In YAML, 4711 is a number and yes is a boolean, but Kubernetes labels, annotations and
nodeSelector values all have to be text. Put quote marks around anything that is not obviously a
word:
labels:
acme.com/cost-centre: "4711" # not 4711
audited: "yes" # not yes
Unquoted non-string values are rejected. See configuration errors.
What you cannot set
The controller restores these fields after merging:
| Field | Why the controller keeps it |
|---|---|
metadata.name, metadata.namespace | It finds and cleans up its Jobs by name |
metadata.ownerReferences | This is how a Promise notices its Job has finished |
metadata.finalizers | A finalizer would stop the controller deleting its own Job |
| Which containers exist | You can change a container it builds, but not add one. A sync Job runs reader, generate and work-writer (writer on Cortex portals) as init containers, followed by status-writer. A setup Job runs a single setup container |
Labels and annotations starting kratix.io/, and app.kubernetes.io/managed-by | These are how the controller finds its Jobs and protects them from being cleaned up early |
Labels such as app.kubernetes.io/name, app.kubernetes.io/component and
app.kubernetes.io/version are yours to set.
Override existing containers by name. You cannot add containers here.
Match the container's list: initContainers or containers. Entries in the wrong list
are silently ignored.
Setting resources on a container
This is how you set CPU, memory or ephemeral storage limits:
jobTemplate:
spec:
template:
spec:
initContainers:
- name: generate
resources:
limits:
memory: 512Mi
ephemeral-storage: 1Gi
Setting environment variables on a container
Naming a container also lets you set environment variables on it.
Name all of the containers to reach everything the controller runs. A single document is merged onto every Job, and an entry for a container that a Job does not run is ignored, so one file covers both portal types, sync Jobs and setup Jobs:
jobTemplate:
spec:
template:
spec:
initContainers:
- name: reader
env:
- name: YOUR_ENV_VAR
value: "your-value"
- name: generate
env:
- name: YOUR_ENV_VAR
value: "your-value"
- name: writer
env:
- name: YOUR_ENV_VAR
value: "your-value"
- name: work-writer
env:
- name: YOUR_ENV_VAR
value: "your-value"
containers:
- name: status-writer
env:
- name: YOUR_ENV_VAR
value: "your-value"
- name: setup
env:
- name: YOUR_ENV_VAR
value: "your-value"
Each Job takes the entries matching the containers it runs. A Backstage sync Job takes reader,
generate, work-writer and status-writer; a Cortex sync Job takes writer in place of
work-writer; a setup Job takes setup. A delete Job runs fewer containers than a configure Job,
and takes the entries for the ones it does run.
Your variables are added to the ones the controller already sets on those containers, which are
left alone. If the setting is only needed where the controller calls a portal's API, that is
writer on a Cortex sync Job and setup on a Cortex setup Job. Backstage portals make no such
calls: they reach the Kubernetes API only.
name is how the merge finds the container to change. An entry without one matches no container,
and the Jobs it would apply to are not created until you add the name.
When the file is wrong
If workloads.yaml cannot be read, the controller creates no new Jobs until you fix it, and records
a warning on the ConfigMap itself. Existing Jobs are left alone.
kubectl -n kratix-platform-system describe configmap ske-portal-workloads-config
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning PortalWorkloadConfigInvalid 110s portal-setup-controller could not parse the portal
workloads configuration: jobTemplate: json: cannot unmarshal number into Go struct field
ObjectMeta.metadata.labels of type string
That message is the unquoted number from the tip above.
The controller rejects anything it cannot make sense of: unknown fields, misspelled fields, values of
the wrong type, and an empty (null) metadata or spec. It does not ignore them. That way a typo
cannot quietly drop the labels your policy needs.
Two things keep working while the file is broken. Cleaning up after a portal connection you have removed from your configuration still runs. So does deleting a Resource, because its Job has to run for the Resource to finish being removed.
The warning appears on the ConfigMap, not on the Promises whose Jobs were not created. If a Promise has stopped syncing to its portal and you cannot see why, check this ConfigMap's events.
Verify Job settings
Inspect ConfigMap events first, then a newly created setup or sync Job and one of its Pods. Select their names from the list; sync Jobs can run in a Promise's pipeline namespace:
kubectl describe configmap ske-portal-workloads-config --namespace kratix-platform-system
kubectl get jobs --all-namespaces
kubectl get job <JOB_NAME> --namespace <JOB_NAMESPACE> -o yaml
kubectl get pods --namespace <JOB_NAMESPACE> --selector job-name=<JOB_NAME>
kubectl get pod <POD_NAME> --namespace <JOB_NAMESPACE> -o yaml
Check your labels, annotations, node placement and container resources on the new objects.
If they are missing, confirm the container name and whether it is in initContainers or
containers. For PortalWorkloadConfigInvalid, correct the field reported by the event.
Existing Jobs are not a reliable check of a newly applied template.
