Russell Brooks
04/29/2026, 12:19 PMMarvin
04/29/2026, 12:19 PMMarvin
04/29/2026, 12:19 PM{{ ... }} is the right approach.
If your ConfigMap itself is rendered by Helm, you can inject values from values.yaml directly into the JSON you store there.
Typical approach
In your environment-specific values.yaml files:
yaml
worker:
image:
repository: my-registry/prefect-worker
tag: tst
and in `prd`:
yaml
worker:
image:
repository: my-registry/prefect-worker
tag: latest
Then in your configmap.yaml template, render the JSON using Helm values:
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prefect-base-job-template
data:
baseJobTemplate.json: |
{
"job_configuration": {
"image": "{{ .Values.worker.image.repository }}:{{ .Values.worker.image.tag }}"
}
}
That would produce ...:tst in test and ...:latest in prod.
Important caveat
This only works if the ConfigMap is part of the Helm template rendering process, e.g. under templates/. If you have a static JSON file that Kubernetes reads directly, Helm will not substitute anything inside it unless you explicitly tell Helm to treat it as a template.
If your JSON lives in a separate file, a common pattern is to load it and run tpl on it.
Example:
files/base-job-template.json
json
{
"job_configuration": {
"image": "{{ .Values.worker.image.repository }}:{{ .Values.worker.image.tag }}"
}
}
Then in your ConfigMap template:
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prefect-base-job-template
data:
baseJobTemplate.json: |
{{ tpl (.Files.Get "files/base-job-template.json") . | indent 4 }}
Why tpl?
Because .Files.Get reads the file as plain text; tpl tells Helm to evaluate any Helm template expressions inside that text.
My recommendation
For maintainability, I’d suggest:
1. Put the tag in values.yaml
2. Keep the base job template in a separate file if it’s large
3. Use tpl to render that file into the ConfigMap
4. Optionally use a single computed value like:
yaml
worker:
image:
repository: my-registry/prefect-worker
tag: tst
full: my-registry/prefect-worker:tst
But usually it’s cleaner to compute the full image string in the template instead of duplicating it in values.
Even better pattern
If you want a default with override support:
yaml
worker:
image:
repository: my-registry/prefect-worker
tag: latest
Then your tst override file only needs:
yaml
worker:
image:
tag: tst
and deploy with the appropriate values file.
One thing to watch for with Prefect
Since you’re modifying the base job template for a Kubernetes worker, make sure the JSON field you’re updating matches the worker’s expected schema for your Prefect version. If you want, I can help you craft the exact baseJobTemplate.json snippet for Prefect 3.6.28 Kubernetes workers.
Useful Helm docs:
- Helm template functions
- Using the tpl function
- Accessing files inside templates
If you want, paste your current values.yaml and ConfigMap template and I’ll rewrite them into the cleanest Helm version.Russell Brooks
04/29/2026, 12:23 PMMarvin
04/29/2026, 12:23 PMMarvin
04/29/2026, 12:24 PMyaml
worker:
image:
repository: my-registry/prefect-worker
tag: 3.6.28
jobTemplate:
image:
repository: my-registry/my-business-logic
tag: tst
And in prod:
yaml
worker:
image:
repository: my-registry/prefect-worker
tag: 3.6.28
jobTemplate:
image:
repository: my-registry/my-business-logic
tag: latest
Then in the ConfigMap that contains your base job template JSON:
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prefect-base-job-template
data:
baseJobTemplate.json: |
{
"job_configuration": {
"image": "{{ .Values.jobTemplate.image.repository }}:{{ .Values.jobTemplate.image.tag }}"
}
}
So now:
- worker.image.* controls the prefect-worker deployment image
- jobTemplate.image.* controls the image used by jobs created by that worker
That separation is the cleanest model.
If your JSON is in a separate file
Same idea, just with `tpl`:
files/base-job-template.json
json
{
"job_configuration": {
"image": "{{ .Values.jobTemplate.image.repository }}:{{ .Values.jobTemplate.image.tag }}"
}
}
templates/configmap.yaml
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prefect-base-job-template
data:
baseJobTemplate.json: |
{{ tpl (.Files.Get "files/base-job-template.json") . | indent 4 }}
Why this is the right model for Prefect workers
In Prefect Kubernetes work pools / workers, the worker process is just the control plane agent that submits jobs. The image in the base job template is what the actual execution pod runs. So it’s perfectly reasonable — and common — to keep:
- a slim worker image
- a separate runtime image for flow execution
One more practical suggestion
If the business logic image name itself changes by environment, keep repository and tag separate as above.
If only the tag changes, you can simplify:
yaml
jobTemplate:
image:
repository: my-registry/my-business-logic
tag: tst
Then only override the tag in env-specific files.
Base values:
yaml
jobTemplate:
image:
repository: my-registry/my-business-logic
tag: latest
tst-values.yaml
yaml
jobTemplate:
image:
tag: tst
prd-values.yaml
yaml
jobTemplate:
image:
tag: latest
One subtle but important point
If this ConfigMap is used to create/update the Prefect work pool’s base job template, changing the ConfigMap alone does not always automatically update whatever Prefect object consumed it, depending on how you apply it in your setup.
So there are really two layers:
1. Helm renders the ConfigMap
2. Something uses that rendered JSON to configure the Prefect worker/work pool/job template
If you are mounting the ConfigMap directly into the worker and the worker reads it on startup, then a restart may be enough.
If instead you used the JSON once when creating the work pool, then you may need to re-apply that work pool configuration after changing the ConfigMap.
So the answer changes from “use worker.image.tag” to “use a separate values key like jobTemplate.image.tag”
Example final layout:
values.yaml
yaml
worker:
image:
repository: my-registry/prefect-worker
tag: 3.6.28
jobTemplate:
image:
repository: my-registry/my-business-logic
tag: latest
tst-values.yaml
yaml
jobTemplate:
image:
tag: tst
prd-values.yaml
yaml
jobTemplate:
image:
tag: latest
templates/configmap.yaml
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prefect-base-job-templateMarvin
04/29/2026, 12:24 PMimage field should be templated for your Prefect Kubernetes worker setup.