Emit account_id and job metadata as Kubernetes pod labels#310
Emit account_id and job metadata as Kubernetes pod labels#310wesleyjellis wants to merge 3 commits into
Conversation
Rather than weaving the account_id job variable into the pod name (which risks the 63-char limit and OpsLevel-side naming conventions), stamp descriptive labels on the job pod for observability: app.kubernetes.io/name: opslevel-job opslevel.com/account-id: <account_id> (when the job sets it) opslevel.com/job-id: <job id> opslevel.com/mode: <faktory|api> These enable native DataDog filtering via podLabelsAsTags with no pod name parsing. Labels are added after building the PDB label selector so they stay out of the selector, which the instance label already makes unique. Adds a getRunnerJobVariable helper (named explicitly since a similar helper is anticipated for egress proxies). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3cc6b31 to
45b7d16
Compare
The OpsLevel API uppercases/sanitizes variable keys before sending them to the runner (RunnerJobType#format_key_as_valid_env_var_name), so the account id arrives as ACCOUNT_ID, not account_id. The previous lookup used the lowercase key and never matched, leaving opslevel.com/account-id always empty. Match the uppercase key instead. Also read a JOB_TYPE variable into an opslevel.com/job-type label so pods can be filtered by job kind (template). This is a no-op until the OpsLevel API emits JOB_TYPE as a derived variable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
archf
left a comment
There was a problem hiding this comment.
This is super cool, thanks a heap!
Let's also add a changie record and we're good to go!
| // name. Added after building the selector so they stay out of the PDB | ||
| // selector, which the instance label already makes unique. | ||
| labels["app.kubernetes.io/name"] = "opslevel-job" | ||
| labels["opslevel.com/job-id"] = id |
There was a problem hiding this comment.
can we 'dup' and add short form keys as well?
e.g.:
labels["accountiD"] = accountID ...
[...]That would be cool for a CLI speedrun instead of typing out the long form.
e.g. kubectl get pods -l accountID=XXX
There was a problem hiding this comment.
Do you want to dupe all or just accountID?
There was a problem hiding this comment.
I would do all (most?) in the shortest typeable form. It's not the most expensive thing and but it allows you to find/select pod(s) without any external grepping tool.
Omit whatever doesn't make sense. Worst case, we add them later if we wish we had them.
On the labels now that I look at them
I'm not certain what name means // how useful it is since they are all in the same job namespace already.
labels["app.kubernetes.io/name"] = "opslevel-job"
What is job-type? That seems very useful.
Maybe we don't need mode since it's inferred by the namespace?
We want labels that allow to select useful subsets of pods amongst all of them to tail logs or whatever and add useful tags in Datadog for metrics, monitors and dashboards.
There was a problem hiding this comment.
Ah, I saw in the PR description what these mean. Very cool!
For some it could be worthy of a code comment for the soul that looks at this later.
There was a problem hiding this comment.
mode separates faktory from legacy jobs, maybe not the most useful but I'd keep it
Addresses PR review: add a changelog entry for the pod-label feature and a short-form `accountID` label alias alongside `opslevel.com/account-id` for terse CLI filtering (e.g. `kubectl get pods -l accountID=XXX`). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Emit account/job metadata as Kubernetes pod labels rather than weaving it
into the pod name (which risks the 63-char limit and OpsLevel-side naming
conventions). This enables native DataDog filtering via
podLabelsAsTagswithno pod-name parsing. The pod/ConfigMap/PDB name is unchanged.
Labels stamped on each job pod:
app.kubernetes.io/nameopslevel-jobopslevel.com/modefaktory|apiopslevel.com/account-idopslevel.com/job-idopslevel.com/job-typeLabels are added after building the PDB label selector so they stay out of the
selector, which the
app.kubernetes.io/instancelabel already makes unique.Also adds a
getRunnerJobVariablehelper (named explicitly since a similarhelper is anticipated for egress proxies).
Fixes
ACCOUNT_IDlookup: the OpsLevel API uppercases/sanitizes variable keysbefore sending them (
RunnerJobType#format_key_as_valid_env_var_name), so theaccount id arrives as
ACCOUNT_ID, notaccount_id. The original lookup usedthe lowercase key and never matched, leaving the label always empty. Now
matches the uppercase key.
Requires a companion OpsLevel change
opslevel.com/job-typeis a no-op until the OpsLevel API emits aJOB_TYPEvariable. The job's kind is its template (
Runners::JobRun#template_name,~13 values) and is currently only carried by the DB
template_idcolumn — it isnever sent to the runner. To light up the label, add a derived variable in
app/models/runners/job_run.rb#derived_variables(alongsideJOB_ID/ACCOUNT_ID):Sending a clean slug from the server keeps the label value valid (raw
template_namecontains::, which is invalid in a k8s label value) andlow-cardinality.
Test plan
go build ./...go test ./pkgpassesTestGetRunnerJobVariable_*cover the helper, including a case-sensitivityguard for the
ACCOUNT_IDbug🤖 Generated with Claude Code