필사 모드: OTel's Kubernetes Attributes Are Stable Now — What to Do Before k8sattributes Flips Its Default
English- Introduction — The Stable Promotion Passed Quietly
- The Four-Month Promotion Timeline
- The 7 Things That Actually Break
- Two Feature Gates, and a Truth Table
- The RFC's 4-Stage Rollout — When Does the Default Actually Flip
- What to Do Now — While the Window Is Open
- The Honest Tradeoff — Dual Emission Isn't Free
- Who Is Actually Affected — And Who Isn't
- Closing
- References
Introduction — The Stable Promotion Passed Quietly
On June 12, 2026, semconv v1.42.0 shipped, and a batch of OpenTelemetry's Kubernetes attributes got promoted to stable. The changelog line reads — "Promote a selection of k8s and container registry attributes to stable".
And nothing happened.
More precisely, it is designed so that nothing happens. If you're running the Collector's k8sattributes processor, right now, at this very moment, you're still emitting the old schema (hereafter v0). As of the latest release, collector-contrib v0.156.0 (2026-07-07), the relevant feature gate is still alpha, and at alpha the default is v0.
This is a grace period, not an exemption. Per the rollout the Collector's RFC lays out, the moment the gate advances to beta, the default behavior flips to v1-only. And the nature of that change is nasty — it doesn't error. Dashboards just go empty.
This post lays out what actually changes, when it flips, and what to do in the window that's open right now. And at the end, I'll also make the case that this is a much narrower problem than it sounds.
The Four-Month Promotion Timeline
Let's lay out the facts in chronological order first. All of it is verifiable from the semconv repo's releases and merged PRs.
2026-02-19 semconv v1.40.0 k8s.pod.name, etc. -> stability: beta
2026-03-02 PR #3491 opened "Promote a selection of k8s/container attributes to RC"
2026-03-09 PR #3491 merged beta -> release_candidate
2026-03-16 Official blog post "Kubernetes attributes promoted to release candidate"
2026-04-28 semconv v1.41.0 42 attributes ship as release_candidate
2026-05-11 semconv v1.41.1 still release_candidate
2026-06-12 semconv v1.42.0 -> stable (changelog #3382)
2026-07-03 semconv v1.43.0 stays stable
2026-07-07 contrib v0.156.0 feature gate still alpha (since v0.145.0)
The body of PR #3491 states the intent clearly — that this is "the last intermediate-stage promotion before going stable, and a final call for feedback." The March 16 official blog post (Christos Markou/Elastic, David Ashpole/Google) likewise nailed down that "the time to give feedback is while it stays at release_candidate."
That window closed on June 12. The attributes are stable now.
The thing worth noting here is the gap between the last two lines. semconv declared stable on June 12, but the gate is still alpha in the July 7 Collector release. As we'll see below, the RFC states that "the gate is promoted to beta in the same Collector release as the one where semconv marks the convention stable." In other words, we're currently running behind the picture the RFC drew. I don't have material that lets me confirm why it's late, or exactly which release will flip it — so I won't make up a date. But the direction is set, and what you've been given is the time in between.
The 7 Things That Actually Break
The breaking changes between v0 and v1 are specified exactly, all 7 of them, in the k8sattributes processor README.
container.image.tag -> container.image.tags
k8s.pod.labels.KEY -> k8s.pod.label.KEY
k8s.pod.annotations.KEY -> k8s.pod.annotation.KEY
k8s.node.labels.KEY -> k8s.node.label.KEY
k8s.node.annotations.KEY -> k8s.node.annotation.KEY
k8s.namespace.labels.KEY -> k8s.namespace.label.KEY
k8s.namespace.annotations.KEY -> k8s.namespace.annotation.KEY
Six of them amount to nothing more than plural becoming singular. labels becomes label, annotations becomes annotation. In terms of the actual attribute names, it looks like this.
v0: k8s.pod.labels.app = "checkout"
v1: k8s.pod.label.app = "checkout"
One letter. And that's exactly what makes it dangerous. When a name changes completely, a query errors out or breaks visibly, but a query that filters on an attribute that no longer exists usually just quietly returns an empty result. Alerts don't fire (there's no time series matching the condition), dashboard panels show "No data," and nobody gets paged at 3am. It comes back days later as "wait, since when has this graph been empty?"
The seventh one is a different animal. Going from container.image.tag to container.image.tags isn't just a name change — the type changes too. Per the processor docs, the former is Any Str, the latter Any Slice. It's going from a single string to an array, so even after you fix the name, an equality filter like tag = "v1.2.3" won't behave the way you want against an array. This isn't a change you can finish with a string substitution — you have to rewrite the query itself.
Two Feature Gates, and a Truth Table
The Collector deliberately does not use the SDK-side OTEL_SEMCONV_STABILITY_OPT_IN environment-variable approach. To borrow the RFC's phrasing, that approach "doesn't feel Collector-native," and in particular it doesn't support rolling back to the previous behavior after an upgrade. Instead it uses a paired set of two feature gates. Both have existed since v0.145.0, and both are currently alpha.
processor.k8sattributes.EmitV1K8sConventions— when on, emits the new (stable) schema.processor.k8sattributes.DontEmitV0K8sConventions— when on, turns off the old (legacy) schema.
The key is that the two are independent. That gives four combinations, and the RFC defines the truth table like this.
| EmitV1 | DontEmitV0 | Resulting Behavior |
|---|---|---|
| off | off | v0 only (current default) |
| off | on | error at startup — because no telemetry would go out at all |
| on | off | emits both v0 and v1 (dual emission) |
| on | on | v1 only |
The third row is the point of this post. You don't need both on — turning on just EmitV1 makes both schemas go out at the same time. That means the old dashboard and the new dashboard can stay alive side by side during the migration period.
The second row is worth knowing too. The combination of "turn off the new one, turn off the old one" isn't silently ignored — it's a startup failure. That's a much better design than having telemetry silently vanish because of a config mistake.
Gates are turned on with a flag at Collector startup.
# Dual emission: emit v0 and v1 at the same time (for the migration period)
otelcol-contrib --config=config.yaml \
--feature-gates=+processor.k8sattributes.EmitV1K8sConventions
# Fully cut over: emit v1 only
otelcol-contrib --config=config.yaml \
--feature-gates=+processor.k8sattributes.EmitV1K8sConventions,+processor.k8sattributes.DontEmitV0K8sConventions
The RFC's 4-Stage Rollout — When Does the Default Actually Flip
The semconv-feature-gates RFC nails down the stages the gate pair will walk through like this. The two gates always move together, at the same pace.
- alpha — both off by default. Default behavior is v0 only. Users can opt in to dual emission or v1-only if they want. The RFC requires that at this stage, the component must log a warning at startup ("A warning message must be logged by the component at startup indicating the upcoming change").
- beta — once the release ships where semconv marks the convention stable, the gate is promoted to beta in that same Collector release. At this point, the default behavior flips to v1-only. Now, conversely, you have to opt out if you want v0.
- stable — after 4 minor releases at beta, it moves up to the stable stage. From this point on, only v1 is usable.
- removal — after 4 more minor releases from there, the gate itself disappears.
We're at stage 1 right now, and the semconv-side condition (v1.42.0's promotion to stable) has already been met. So stage 2 is a scheduled event. As I said above, the exact release number isn't confirmed, so I won't state one. But there are two facts you can plan around — the flip arrives the moment you upgrade the Collector, and after 8 minor releases past beta, the means to revert disappears entirely.
If you're auto-upgrading the Collector (you left the operator's image tag on latest, or you never pinned the rendered chart version), this flip arrives not on a day you chose, but on any day at all.
What to Do Now — While the Window Is Open
Order matters. This is exactly why the RFC bothered to build in a dual-emission stage.
1. First, check whether you're exposed. Look at the extract block of the k8sattributes processor in your Collector config. Is there a labels or annotations sub-item? Is container.image.tag in the metadata list? If neither — as explained below — this change doesn't apply to you.
2. Turn on dual emission. Turn on only EmitV1K8sConventions so v0 and v1 go out at the same time. From this point on, both names exist in the backend, so the old dashboard keeps working while you try out queries against the new name. It's also easy to revert.
3. Migrate your queries and dashboards. The six that go from plural to singular are close to a mechanical substitution. container.image.tag needs a manual look, because of the type change mentioned earlier.
4. Turn off v0. After confirming the new queries return data, turn on DontEmitV0K8sConventions. The behavior at this point is exactly what the future default will be, so you're essentially living the future early.
5. Only then, upgrade the Collector. If you're already running v1-only, nothing happens to you even when the gate flips to beta. That's the goal.
The key is decoupling step 2 from step 5. If you do nothing and then upgrade, the schema switch and the version upgrade collide on the same day at the same hour, and when something goes empty, you can't tell which of the two caused it.
The Honest Tradeoff — Dual Emission Isn't Free
I don't want to talk about the dual-emission stage as if "just leaving it on is safe." There's a cost.
Resource attributes double up. If you were extracting 5 labels, now 10 get attached. This rides along on the resource of every span, metric, and log, so it costs you on both network and storage. Exactly how many percent it grows by depends entirely on how many labels you're pulling, so I won't invent a number here — but measuring it on your own pipeline isn't hard.
For metrics, cardinality is the part that hurts more. On backends where resource attributes go into time-series identity, having an attribute with the same value exist under two names can affect the number of time series. How each backend handles resource attributes differs, so I can't make a blanket statement — it's safer to turn it on in one small namespace first before enabling dual emission everywhere, and look at the measured numbers.
So dual emission is a bridge, not a destination. The RFC's own rollout presupposes exactly that — the dual-emission combination disappears once the stable stage arrives. If you turn it on, you have to see it through to the end. "Turn it on and deal with it later" is the most expensive choice.
Who Is Actually Affected — And Who Isn't
This might be the single most important section in this post. Everything so far sounds like "K8s semantic conventions are breaking," but the blast radius is much narrower than the rumor.
The attributes you use every day don't change. k8s.pod.name, k8s.namespace.name, k8s.deployment.name, k8s.node.name, k8s.container.name, k8s.pod.uid — every one of them keeps its name. None of them are on the breaking-change list. Most dashboards are built on top of these attributes, and those dashboards feel nothing.
The only things that change are label/annotation extraction and container.image.tag. And even label extraction comes with a condition — per the processor README, the plural name is the default format used when you don't specify a tag_name. In other words, if your extract config has always given each label its own name via an explicit tag_name, that name is yours, and it's unaffected by this renaming. What's affected is configuration that was relying on the default format.
# When tag_name is specified — the attribute name is 'l2'. Unaffected by this change.
extract:
labels:
- tag_name: l2
key: label2
from: pod
# When tag_name is absent — it follows the default format, so it's affected.
# v0: k8s.pod.labels.label2 -> v1: k8s.pod.label.label2
extract:
labels:
- key: label2
from: pod
And what became stable is also just a "selection." If you parse the k8s registry of semconv v1.43.0, of 89 attributes, 42 are stable, the remaining 45 are still development, and 2 are experimental. The March blog post's own title said "a selection of." So you shouldn't read this as "K8s conventions are all settled now" — a good chunk of the workload-related ones are still sitting in a spot where they can change. The 42 that stabilized this time are the ones that Collector components aiming for stabilization — k8sattributes and resourcedetection, for example — were actually using.
To sum up:
When you need to move now
- You're pulling labels/annotations in
k8sattributes'sextractwithout atag_name. - You have queries that filter or group by
container.image.tag. - You auto-follow Collector upgrades, so you don't get to pick the upgrade moment.
When you don't need to care
- You use only things like
k8s.pod.name/k8s.namespace.name/k8s.deployment.name— this covers the majority. - You've always specified
tag_nameexplicitly for label extraction. - You pin the Collector version and plan upgrades deliberately — if so, this post is a note to attach to your next upgrade ticket.
Closing
The lesson of this story isn't "OTel changed names again." It's closer to the opposite. semconv walked beta → release_candidate → stable over four months, announced it at every step, and even attached a final call for feedback. On the Collector side, they designed a gate pair with a clear truth table, a dual-emission window, and a grace period spanning 8 minor releases. They've put in place pretty much everything you could, to prevent a quiet failure.
And yet, the point where a change like this actually hurts people is always the same — because the moment the default flips and the moment you hit upgrade are the same moment. Right now, we're in the unusual state where there's still time left between those two moments. semconv has already declared stable, and the Collector default hasn't flipped yet. This gap is exactly the right spot to turn on dual emission, migrate your queries, verify, and move on.
And again — if you check and it turns out there's no label in your extract block, that's the end of it. That's the most common ending to this post, and it takes five minutes to confirm.
References
- Kubernetes attributes promoted to release candidate in OTel Semantic Conventions (2026-03-16 official blog)
- semantic-conventions PR #3491 — k8s/container attribute RC promotion (merged 2026-03-09)
- semantic-conventions releases — stable promotion in v1.42.0 (2026-06-12)
- Collector RFC — Semantic conventions migrations in the Collector (truth table and the 4-stage rollout)
- k8sattributes processor README — Semantic Conventions Compatibility (the 7 breaking changes)
- k8sattributes processor documentation.md — feature gate stages and attribute types
- Collector Feature Gates documentation
- OpenTelemetry 2026 Deep Dive — OTLP, Semantic Conventions, the Collector Pipeline, and Auto-Instrumentation After the Standardization War (related post)
현재 단락 (1/99)
On June 12, 2026, [semconv v1.42.0](https://github.com/open-telemetry/semantic-conventions/releases)...