Configuring a Private Image Registry for Use with the Platform
For security and reliability, the recommended practice is to mirror the Zend Enterprise Web Platform container images and Helm charts into your own OCI-compatible registry, and to host your custom application images there as well. A private registry gives you control over what runs in your cluster, insulates you from upstream availability issues, and lets you scan and govern images centrally.
This section explains how to mirror the platform images, how to tell your Kubernetes cluster how to authenticate to your registry, and how to point the chart at it.
Why mirror images?
- Security and governance. You decide which image versions are permitted, and you can scan them before they reach your cluster.
- Availability. Your deployments don't depend on an external registry being reachable at deploy time.
- Performance. A registry close to your cluster pulls faster, which matters when scaling up or recovering from node failures.
You should mirror both the platform images (for example cr.zend.com/platform/*, cr.zend.com/zendhq, cr.zend.com/zendphp/*) and the platform Helm charts (cr.zend.com/charts/platform/umbrella), and you should publish your own custom application images into the same registry.
Mirroring images into your registry
Any OCI-compatible registry works — for example Zot, a self-hosted docker-registry, or a managed registry such as Amazon ECR, Azure Container Registry, Google Artifact Registry, or Harbor.
You can copy images between registries with a tool such as skopeo, oras, crane, or regctl. For example, using skopeo to mirror a ZendHQ image:
skopeo copy \
docker://cr.zend.com/zendhq:alpine-3.22 \
docker://registry.example.com/zend/zendhq:alpine-3.22
To mirror the Helm chart itself, pull it from the source registry and push it to your own:
helm pull oci://cr.zend.com/charts/platform/umbrella --version 1.2.3
helm push umbrella-1.2.3.tgz oci://registry.example.com/charts/platform
Telling Kubernetes how to authenticate to your registry
If your registry requires authentication, the cluster needs credentials to pull images. Kubernetes uses a special docker-registry Secret for this. Create one in each namespace you deploy into:
kubectl -n <namespace> create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=<username> \
--docker-password=<password> \
--docker-email=<email>
This produces a secret (here named regcred) of type kubernetes.io/dockerconfigjson. There are two ways to make Kubernetes use it.
Option A — reference the pull secret in the chart values (recommended)
Point the platform at your registry and pull secret through the global values. This applies the registry and credentials consistently across the composed subcharts:
global.imageRegistryis prepended to image references, so images you specify by repository/name are pulled from your registry.global.imagePullSecretslists thedocker-registrysecret(s) the pods should use to authenticate.
You can still refer to images by their full name including the registry (for example registry.example.com/platform/zendhq); doing so is explicit and unambiguous. Use global.imageRegistry when you want to switch registries without rewriting every image reference.
Option B — attach the pull secret to the namespace's default ServiceAccount
If you'd rather not set pull secrets per workload, you can attach the secret to the default ServiceAccount in the namespace, so every pod created there inherits it:
kubectl -n <namespace> patch serviceaccount default \
-p '{"imagePullSecrets": [{"name": "regcred"}]}'
This is convenient for a namespace dedicated to the platform, but it is less explicit than Option A — the dependency on the secret is no longer visible in your values files. Prefer Option A unless you have a specific reason to manage pull secrets at the ServiceAccount level.
Pointing the chart at your mirrored chart and images
Once your registry holds the mirrored chart and images, install from your registry rather than from cr.zend.com:
helm registry login -u <username> registry.example.com
helm upgrade --install \
-n <namespace> --create-namespace \
<release_name> \
oci://registry.example.com/charts/platform/umbrella \
--version 1.2.3 \
-f 00-infra.values.yaml
Combine this with the global.imageRegistry / global.imagePullSecrets values above so that the platform's service images, and your application images, are all pulled from your registry.
Remember that secrets — including docker-registry pull secrets — are namespace-scoped and must exist before the pods that need them are scheduled. Create the pull secret right after creating the namespace, alongside your other platform secrets.