Zot
Purpose
Zot is Lumie's private container registry. It is the required image source for cluster workloads, and it also mirrors selected upstream registries on demand so the rest of the platform can stay inside the zot.lumie-infra.com/* image policy enforced elsewhere in the stack.
This page is a reference document for developers changing registry auth, upstream mirror coverage, MinIO storage, or build and deploy image paths.
Source Paths
| Path | Role |
|---|---|
lumie-infra/bootstrap/zot/argocd.yaml | Argo CD application for Zot |
lumie-infra/bootstrap/zot/common-values.yaml | Vault-backed htpasswd, OIDC, and MinIO credential projection |
lumie-infra/bootstrap/zot/helm-values.yaml | Zot deployment, ingress, rendered config, mirror policy, and auth settings |
lumie-infra/bootstrap/minio/** | Object storage Zot uses for its S3 backend |
lumie-infra/applications/tekton/ci-cd/manifests/secrets/zot-registry-credentials.yaml | Tekton's push credential for zot.lumie-infra.com |
Public Surface
| Surface | Contract |
|---|---|
| External URL | https://zot.lumie-infra.com |
| In-cluster Service | Port 5000 exposed by the zot service |
| Storage backend | S3-compatible MinIO bucket zot at http://minio.minio.svc.cluster.local:9000 |
| Auth methods | htpasswd and Keycloak OIDC |
| Metrics | Prometheus endpoint at /metrics |
Repository access is intentionally asymmetric:
- anonymous users get read access;
adminsgroup members and theadminuser get create, update, and delete rights.
Runtime Flow
Configuration Highlights
The active config contract is rendered from a ConfigMap template plus a Vault-projected OIDC client secret:
"auth": {
"htpasswd": {
"path": "/etc/zot/htpasswd"
},
"openid": {
"providers": {
"oidc": {
"clientid": "zot",
"clientsecret": "__OIDC_CLIENT_SECRET__"
}
}
}
}
Important behavior from bootstrap/zot/helm-values.yaml:
- the init container renders
/etc/zot/config.jsonby substituting the live OIDC client secret into the template; - storage is S3-backed rather than PVC-backed;
- ingress is public on
zot.lumie-infra.comwith a cert-manager-issued TLS secret; - retention keeps only the most recently pushed tag while deleting referrers.
Upstream Mirror Policy
On-demand sync is enabled for specific registries and prefixes:
| Registry | Example prefixes |
|---|---|
| Docker Hub | library/**, bitnami/**, gitea/**, rabbitmqoperator/**, minio/**, timberio/** |
| GHCR | cloudnative-pg/**, kyverno/**, tektoncd/**, openclaw/**, kedacore/** |
| Quay | prometheus/**, thanos/**, prometheus-operator/**, keycloak/** |
| Public ECR | gravitational/** |
registry.k8s.io | kube-state-metrics/**, autoscaling/** |
gcr.io | kaniko-project/** |
If an upstream namespace is not listed, Zot will not mirror it on demand and downstream image pulls should be expected to fail policy checks elsewhere in the stack.
Secret And Dependency Flow
| Secret | Source path | Consumer |
|---|---|---|
zot-htpasswd | bootstrap/zot/common-values.yaml | Local htpasswd auth |
zot-oidc-secret | bootstrap/zot/common-values.yaml | Init-container render step |
minio-s3-credentials | bootstrap/zot/common-values.yaml | Main Zot container S3 client |
All three are materialized by VaultStaticSecret resources through the shared vault/vault-auth identity.
Failure Modes
| Failure point | Behavior |
|---|---|
Missing zot-oidc-secret | Init container cannot render config.json, so the pod never starts cleanly |
| MinIO outage | Registry reads and writes fail even if the Zot pod is healthy |
| Missing allowlisted prefix | On-demand pull fails because Zot refuses to mirror that upstream image path |
| TLS or ingress issue | External pulls from zot.lumie-infra.com fail even if the in-cluster service is healthy |
Verification
cd lumie-infra
rg -n "zot.lumie-infra.com|regionendpoint|onDemand|tektoncd/|clientsecret" \
bootstrap/zot applications/tekton/ci-cd
kubectl get application zot -n argocd -o yaml
kubectl get deploy,svc,ingress -n zot
kubectl get secret zot-htpasswd zot-oidc-secret minio-s3-credentials -n zot