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:
-
Pull the chart:
helm pull oci://mcr.microsoft.com/application-lb/charts/alb-controller --version 1.11.3 --untar
-
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:'
-
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.
Describe the bug
The
alb-controllerHelm chart hardcodes a/publicpath segment into the computed image reference wheneveralbController.image.registrydoes not start withmcr.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 apublic/namespace.The culprit is the
albController.imagePathPrefixhelper intemplates/_helper.tpl: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: neitheralbController.image.registrynoralbController.image.name.*can express a final image reference without it, andvalues.schema.jsonsetsadditionalProperties: false, so no extra escape-hatch value can be passed either.This also contradicts the documented value contract, where
albController.image.registryis described simply as "Container image registry foralb-controller", with no mention of an injected path segment.Requesting label:
app-gateway-for-containers.To Reproduce
Steps to reproduce the behavior:
Pull the chart:
Render it against a custom registry, for example an Azure Container Registry fronting MCR through an artifact cache rule:
Observed output (chart
1.11.3, identical on1.10.28):The repository
mcr.microsoft.com/public/application-lb/images/...does not exist in the cache, so every pull fails withImagePullBackOff.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:
which for the repro above gives:
Concretely,
albController.imagePathPrefixcan collapse to:The
mcr.microsoft.comdefault invalues.yamlis unchanged, so the default install renders exactly as it does today. Anyone who genuinely relies on the current behavior can restore it by appending/publicto their ownalbController.image.registryvalue, which is one value change and is explicit rather than magic. If a hard break is not acceptable, an opt-out value (for examplealbController.image.registryPathPrefix, defaulting topublicfor 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):
alb-controller1.11.3(latest onoci://mcr.microsoft.com/application-lb/charts/alb-controlleras of 2026-08-12), also reproduced on1.10.28v4.2.3helm templatealoneAdditional 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:
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/*topublic/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 theapplication-lbrule would overlap with ourmcr.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 aprintfin 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:
That issue was then auto-closed by
microsoft-github-policy-service[bot]on 2025-10-27 without the change landing, and the/publicsegment is still present in1.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.