Skip to content

[BUG] ALB Controller Helm chart injects a /public segment into the image path when a custom registry is used #5917

Description

Describe the bug

The alb-controller Helm chart hardcodes a /public path segment into the computed image reference whenever albController.image.registry does not start with mcr.microsoft.com. This makes it impossible to pull the controller images from any registry other than MCR unless that registry happens to expose the images under a public/ namespace.

The culprit is the albController.imagePathPrefix helper in templates/_helper.tpl:

{{/* Image path prefix based on the registry */}}
{{- define "albController.imagePathPrefix" -}}
{{- if hasPrefix "mcr.microsoft.com" .Values.albController.image.registry -}}
{{- printf "%s" .Values.albController.image.registry -}}
{{- else -}}
{{- printf "%s/public" .Values.albController.image.registry -}}
{{- end -}}
{{- end -}}

public/ looks like an internal MCR/ACR staging convention. It has no meaning in a customer registry, and the chart gives no way to opt out of it: neither albController.image.registry nor albController.image.name.* can express a final image reference without it, and values.schema.json sets additionalProperties: false, so no extra escape-hatch value can be passed either.

This also contradicts the documented value contract, where albController.image.registry is described simply as "Container image registry for alb-controller", with no mention of an injected path segment.

Requesting label: app-gateway-for-containers.

To Reproduce

Steps to reproduce the behavior:

  1. Pull the chart:

    helm pull oci://mcr.microsoft.com/application-lb/charts/alb-controller --version 1.11.3 --untar
  2. Render it against a custom registry, for example an Azure Container Registry fronting MCR through an artifact cache rule:

    helm template alb ./alb-controller \
      --set albController.podIdentity.clientID=00000000-0000-0000-0000-000000000000 \
      --set albController.image.registry=myregistry.azurecr.io/mcr.microsoft.com \
      | grep 'image:'
  3. Observed output (chart 1.11.3, identical on 1.10.28):

    image:  "myregistry.azurecr.io/mcr.microsoft.com/public/application-lb/images/alb-controller-bootstrap:1.11.3"
    image: "myregistry.azurecr.io/mcr.microsoft.com/public/application-lb/images/alb-controller-crds:1.11.3"
    image: "myregistry.azurecr.io/mcr.microsoft.com/public/application-lb/images/alb-controller:1.11.3"
    

    The repository mcr.microsoft.com/public/application-lb/images/... does not exist in the cache, so every pull fails with ImagePullBackOff.

    With the default registry, the same render correctly produces mcr.microsoft.com/application-lb/images/alb-controller:1.11.3.

Expected behavior

The rendered image reference should be exactly the registry, the image name and the tag, with no segment the operator did not ask for:

{{ .Values.albController.image.registry }}/{{ .Values.albController.image.name.controller }}:{{ include "albController.imageTag" . }}

which for the repro above gives:

myregistry.azurecr.io/mcr.microsoft.com/application-lb/images/alb-controller:1.11.3

Concretely, albController.imagePathPrefix can collapse to:

{{- define "albController.imagePathPrefix" -}}
{{- .Values.albController.image.registry -}}
{{- end -}}

The mcr.microsoft.com default in values.yaml is unchanged, so the default install renders exactly as it does today. Anyone who genuinely relies on the current behavior can restore it by appending /public to their own albController.image.registry value, which is one value change and is explicit rather than magic. If a hard break is not acceptable, an opt-out value (for example albController.image.registryPathPrefix, defaulting to public for non-MCR registries) would also unblock the scenario, though a verbatim registry is the behavior most Helm charts implement and the one the documentation already promises.

Screenshots

Not applicable.

Environment (please complete the following information):

  • Chart version: alb-controller 1.11.3 (latest on oci://mcr.microsoft.com/application-lb/charts/alb-controller as of 2026-08-12), also reproduced on 1.10.28
  • Helm CLI version: v4.2.3
  • Kubernetes version: not relevant, the defect is in chart templating and reproduces with helm template alone
  • CLI Version: not applicable
  • CLI Extension version: not applicable
  • Browser: not applicable

Additional context

Why this matters beyond "push the images yourself"

We front all upstream registries with a single Premium ACR configured with artifact cache rules, which is the Azure-recommended way to get private-network image pulls, rate-limit protection and availability-zone redundancy. Our MCR rule is registry-wide:

Source repository New ACR repository namespace
mcr.microsoft.com/* mcr.microsoft.com/*

Every MCR-hosted workload we run therefore just needs registry: myregistry.azurecr.io/mcr.microsoft.com. The ALB controller is the only chart that breaks under this scheme, because of the injected /public.

The obvious workaround, adding a bespoke cache rule from mcr.microsoft.com/application-lb/images/* to public/application-lb/images/*, is blocked by an ACR limitation documented on the same page: "Artifact cache rules can't overlap with other cache rules. In other words, if you have an artifact cache rule for a certain registry path, you can't add another cache rule that overlaps with it." Adding the application-lb rule would overlap with our mcr.microsoft.com/* rule, so accommodating this one chart means dismantling the registry-wide rule and enumerating every MCR repository we consume, one rule at a time, forever. That is a lot of permanent operational cost for a printf in a template.

Prior report

This was already reported in #5159, where Jack Stromberg (@JackStromberg) acknowledged the use case and stated the intent to remove the string in a future release:

Although the chart change is trivial, there's some indirect work needed to complete this change. While the change won't be included in our upcoming release, we do intend to remove the string in a future release.

That issue was then auto-closed by microsoft-github-policy-service[bot] on 2025-10-27 without the change landing, and the /public segment is still present in 1.11.3 (verified today). Reopening #5159 instead of tracking this one is perfectly fine by us; the goal is simply that the fix does not get lost to staleness a second time.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions