Labels and Rollouts
What every object m2p creates is labelled with, where each label lives, who reads it, and which changes replace a pod. Since 3.2.0 the chart draws one line through its labels: a label on an object describes it; a label on a pod template decides when the part rolls.
Two label sets
Kubernetes replaces the pods of a Deployment (or the next Job of a CronJob) whenever
anything in spec.template changes, labels included. So the chart keeps two sets:
| Helper | Where it is rendered | What it carries | Changing it |
|---|---|---|---|
m2p.labels |
metadata.labels of every object: Deployment, CronJob, Service, Secret, ConfigMap, PVC, IngressRoute, Middleware, Certificate, user manifests |
the six labels below | updates the object in place, replaces nothing |
m2p.podTemplateLabels |
spec.template.metadata.labels of a Deployment, jobTemplate.spec.template.metadata.labels of a CronJob |
the selector labels + the image tag | replaces the pods of that part |
Both sets also carry app.kubernetes.io/component: <part name>, added by the template
that renders the part.
The labels, one by one
| Label | Value | On objects | On pod templates | Who reads it |
|---|---|---|---|---|
app.kubernetes.io/name |
package_release.app_name (the profile's App) |
yes | yes (selector) | the selector; Muppy stores it as the object's app label |
app.kubernetes.io/instance |
.Release.Name, which is the Muppy Release name |
yes | yes (selector) | the selector; Muppy links an object to its Release through it |
app.kubernetes.io/component |
the part name | yes | yes | Muppy's dashboards; kubectl -l component=… |
app.kubernetes.io/version |
on an object: package_release.app_version (the profile's version). On a pod template: the tag of the image that part runs |
yes | yes | Kubernetes, as the roll trigger of the part |
helm.sh/chart |
mpy-metapackage-<chart version> |
yes | no | humans and tooling: which chart produced the object |
app.kubernetes.io/managed-by |
Helm |
yes | no | Helm ownership |
muppy.io/package-release |
package_release.name |
yes | no | Muppy, as a second key to the Release (same value as instance today) |
The selector of a Deployment is app.kubernetes.io/name + app.kubernetes.io/instance +
app.kubernetes.io/component. It is immutable on a deployed Release: a chart that
changed it would not roll anything, it would make helm upgrade fail on every Release
already installed. tests/render_test.py asserts it stays as it is.
What replaces a pod
| Change | Parts replaced |
|---|---|
the Release image (values.docker_image, a new application tag) |
every part running that image; a part with its own docker_image is left alone |
a part's own docker_image tag |
that part only |
a Secret a part follows through env_change_trigger |
the parts that follow it |
a part's command, args, env_vars, resources, probes, volumes |
that part (its template changed) |
the profile's app_version alone |
nothing: it is on the object, not on the template |
a new chart version (helm.sh/chart) |
nothing, from 3.2.0 on |
the Release-wide envfile Secret ({app}-env-{qualifier}) |
the parts declaring env_change_trigger: secrets_env_file; nobody else |
| a migration Job | the parts with stop_before_upgrade (the default), stopped then restarted; the others are untouched |
Two consequences worth reading twice:
- Image tags must be immutable. Two images pushed under one tag are one version to
Kubernetes: the template is unchanged and the part is not replaced. A part pinned on a
moving tag (
stable,latest) never rolls by itself; bringing a new image into use is then a deliberate restart, or a pinned tag. - The first upgrade from 3.1.0 to 3.2.0 replaces every pod, once: every pod template changes shape. After it, only the table above applies.
- The migration Job line is Muppy's, not the chart's.
stop_before_upgradeis read by Muppy (Parts Reference), which renders the flagged parts with 0 replica, runs the Job, then restores them on the new image; the chart only ever sees the replica count. The stop is one extra Helm revision, and it is a state nothing should be rolled back to - ahelm rollbacklooking for the Release as it ran must skip it and target the revision before it. Muppy marks that revision in its config journal.
env_change_trigger
envFrom is read when a container starts and never again, so a part reading its
configuration from a Secret must be replaced when that Secret changes. Before 3.2.0 the
hash of the Release envfile sat in common_env_vars, on every part: an edit of that Secret
rolled parts that never read it. Now a part opts in and names what it follows:
parts:
gui:
type: server
env_change_trigger: app-config # a vault object, by the name used in envFrom
envFrom:
- name: app-config
secretRef:
wrkr:
type: worker
env_change_trigger: secrets_env_file # the Release-wide {app}-env-{qualifier} envfile
holder:
type: worker # follows nothing: never rolled by an env change
The part receives MPY_ENV_CHANGE_TRIGGER=<sha256 of what it follows> in its environment.
The hash comes from the values Muppy renders: secrets_env_file_sha256 for the envfile,
vault_objects.<name>.sha256 for a vault object (Muppy publishes both from m2p 3.2.0 on).
Naming something the values do not carry fails the render, with the part and the name
in the message: a trigger that silently resolves to nothing is a part that never rolls
again, and nobody would notice.
Reading a Release from the labels
# every object of a Release
kubectl -n <ns> get all -l app.kubernetes.io/instance=<release name>
# the pods of one part, and the image tag they were rolled for
kubectl -n <ns> get pods -l app.kubernetes.io/component=gui \
-L app.kubernetes.io/version
# which chart version produced the Deployments
kubectl -n <ns> get deploy -L helm.sh/chart
On the Muppy side, Kubernetes ▸ Objects shows the same thing: the Release column comes
from app.kubernetes.io/instance (and muppy.io/package-release where present), the
component from app.kubernetes.io/component.