Skip to content

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_upgrade is 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 - a helm rollback looking 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.