.coreweave.app.
OCI conformanceCoreWeave has tested that the Zot registry passes the OCI Distribution Specification conformance suite, validating its compliance with the Open Container Initiative standards on the CoreWeave cloud. The conformance suite tests core registry operations including push and pull workflows, content discovery, and content management. This certification confirms that Zot works reliably with OCI-compatible tooling and clients across the container ecosystem.
What you’ll use
This tutorial uses:- Zot: Container registry built for OCI.
- CoreWeave AI Object Storage: S3-compatible object storage for image layers.
- LOTA: Local Object Transport Accelerator for in-cluster performance.
- cert-manager: Automatic TLS certificate management.
- Public LoadBalancer Service: Direct external exposure with a public FQDN under
.coreweave.app.
What you’ll do
In this tutorial, you:- Install cert-manager to issue a TLS certificate for the registry.
- Create registry credentials for authenticating with the registry.
- Issue a TLS certificate for the registry hostname.
- Deploy Zot using Helm with S3-backed storage through LOTA, a public LoadBalancer Service, and the TLS certificate mounted into the Pod.
- Push and pull a container image to verify the registry.
Prerequisites
Before you start, you must have:- A working CKS cluster.
- Access Key and Secret Key with permissions to use a CoreWeave AI Object Storage bucket.
- kubectl installed and configured for your cluster.
- Helm version 3.8+.
- Docker or another OCI-compatible client.
Verify cluster access
Before installing anything, confirm thatkubectl is configured for the right cluster and that the cluster has the Node types this tutorial requires.
Verify that you can access your cluster with kubectl:
cpu in the CLASS column:
Install cert-manager
This tutorial uses the CoreWeave cert-manager Helm chart to issue a TLS certificate for the registry. Add the CoreWeave Helm repository:cert-manager:
ClusterIssuers:
ClusterIssuers are ready:
Determine the registry hostname
You need the registry’s public hostname before you can issue a TLS certificate or push and pull images, so determine it now and reuse it in the steps that follow. CoreWeave’s External Hostname Controller allocates an FQDN under.coreweave.app for any public LoadBalancer Service annotated with service.beta.kubernetes.io/external-hostname. For more details, see Create a public DNS name.
Your registry hostname follows this pattern:
[ORG-ID]with your organization ID.[CLUSTER-NAME]with the name of the target CKS cluster.
abc123 and your cluster is named prod, your registry hostname is registry.abc123-prod.coreweave.app. Note this hostname for the following steps.
Create a storage bucket
Zot uses an AI Object Storage bucket as its backing store for image layers and manifests. Create an AI Object Storage bucket in the Cloud Console. Note the bucket name for later use.Generate access credentials
Zot authenticates to the bucket with an S3-compatible Access Key. Create an Access Key for the bucket in the Cloud Console. Save the Access Key ID and Secret Key. You’ll need both when configuring Zot’s storage driver.Create registry credentials
These credentials control who can push and pull images through the registry itself, separate from the bucket credentials in the previous step. Generate a bcrypt-hashed password for the registry admin user. Replace[USERNAME] and [PASSWORD] with your chosen credentials:
If
htpasswd is not installed, install it with apt-get install apache2-utils on Debian/Ubuntu or brew install httpd on macOS.This tutorial uses
htpasswd for simplicity. Zot also supports LDAP, mutual TLS, bearer token (OAuth2), and OpenID Connect with providers like GitHub, Google, and GitLab.htpasswd file:
Issue a TLS certificate
Create aCertificate resource so cert-manager issues a TLS certificate for your registry hostname using the bundled letsencrypt-prod ClusterIssuer.
Save the following as registry-cert.yaml. Replace registry.[ORG-ID]-[CLUSTER-NAME].coreweave.app with the hostname from the previous step:
registry-cert.yaml
tls.crt and tls.key keys, which you’ll mount into the Zot Pod in the next step.
Deploy Zot
With the certificate, bucket, and credentials in place, you can now install Zot itself. The following Helm values wire together the storage bucket through LOTA, thehtpasswd Secret for authentication, the cert-manager-issued TLS Secret, and the public LoadBalancer Service annotations.
Add the Zot Helm repository:
zot-values.yaml file. Replace the placeholder values with your own:
zot-values.yaml
| Placeholder | Value |
|---|---|
[REGION] | The region of your AI Object Storage bucket (for example, us-east-14a) |
[BUCKET-NAME] | Your AI Object Storage bucket name |
[ACCESS-KEY-ID] | Your AI Object Storage Access Key ID |
[SECRET-KEY] | Your AI Object Storage Secret Key |
[USERNAME] | The registry admin username from the credentials step |
[HTPASSWD-STRING] | The $HTPASSWD value generated in the credentials step |
- The
serviceblock creates a publicLoadBalancerService. Theexternal-hostname: registryannotation instructs the External Hostname Controller to allocateregistry.[ORG-ID]-[CLUSTER-NAME].coreweave.appfor the Service. Thecoreweave-load-balancer-type: publicannotation provisions a public IP. The Service listens on port 443 and forwards to the container’szotnamed port, which is set byhttpGet.port(described in the following item). - The
ingress.enabled: falsefield disables the chart’s Ingress resource. External clients connect directly to the LoadBalancer Service, so no ingress controller is required. - The
httpGetblock sets the probe scheme toHTTPSand the container port to5000. The chart uses these values for its startup probe and to name the container port that the Service targets. The scheme must beHTTPSbecause Zot terminates TLS on this port. Probing withHTTPfails. - The
extraVolumesandextraVolumeMountsfields mount theregistry-certSecret (created bycert-managerin the previous step) at/tlsinside the Zot container. Thehttp.tlsblock in the Zot config points totls.crtandtls.keyin that directory, so Zot terminates TLS directly. - The
regionmust match where your AI Object Storage bucket was created. Find this in the Cloud Console on the bucket details page. - The
regionendpointis set tohttp://cwlota.com, the LOTA endpoint. LOTA caches object storage reads on local Node disks for faster access. Thesecurefield isfalsebecause LOTA uses HTTP within the cluster. To access the bucket from outside a CKS cluster, usehttps://cwobject.comas the endpoint and setsecuretotrue. - The
compat: ["docker2s2"]field enables Docker v2 manifest support. Without this,docker pushfails because Zot rejects Docker v2 manifests by default. Remove this field if your workflow exclusively uses OCI-format images.
cert-manager renews the registry-cert Secret automatically before expiry. Because the Secret is mounted into the Zot Pod, the updated certificate is available on disk after rotation. Restart the Zot Pod to pick up the renewed certificate if Zot does not reload it automatically.EXTERNAL-IP column shows a public IP address, and the second command prints registry.[ORG-ID]-[CLUSTER-NAME].coreweave.app. DNS propagation typically completes within one to two minutes.
Verify the registry
Confirm that the registry is reachable, that authentication works, and that the S3-backed storage driver is wired up correctly by pushing and pulling a small test image. Log in to your registry using Docker. Replace[ORG-ID] and [CLUSTER-NAME] with the values for your cluster, and use the username and password you created in the Create registry credentials step:
REGISTRY_PASS in the Create registry credentials section (or use -p $REGISTRY_PASS to provide it directly).
Push a test image:
Enable the web UI (optional)
Zot ships with an optional web UI that lets you browse repositories, tags, and image manifests in a browser. The UI is deactivated by default. To turn it on, enable theui and search Zot extensions in the Zot config. Both are required because the UI depends on the search extension for catalog data.
Add the following extensions block to the http object in zot-values.yaml. Place it as a sibling of log:
zot-values.yaml: configFiles.config.json additions
helm upgrade:
Retrieving the login passwordZot stores only the bcrypt hash of the password in the If Update the Sign in with the new credentials.
registry-htpasswd Secret, so you can’t read the plaintext password back from the cluster. If your shell still has the $REGISTRY_PASS environment variable from the Create registry credentials step, print it with:$REGISTRY_PASS is no longer set, use the plaintext password you chose when you generated the htpasswd entry. If you’ve lost the password, rotate it by generating a new htpasswd entry and applying it through helm upgrade:secretFiles.htpasswd field in zot-values.yaml with the new $HTPASSWD value, then:What you’ve deployed
You now have a Zot container registry running on CKS withhtpasswd authentication, S3-backed storage through LOTA, a Let’s Encrypt TLS certificate issued through a DNS01 challenge, and a public FQDN under the .coreweave.app domain.
External clients connect directly to the Zot LoadBalancer Service on port 443. Zot terminates TLS inside the Pod using the mounted registry-cert Secret, and no ingress controller sits in the request path. cert-manager renews the certificate automatically before expiry.
To pull images from this registry in your CKS workloads, create an imagePullSecret with the same credentials you used in the Create registry credentials step.
Clean up
If you no longer need the registry, remove it and the supporting resources so they don’t continue to consume cluster and storage resources. To remove the registry and all resources installed in this tutorial:Uninstalling
cert-manager leaves its Custom Resource Definitions (CRDs) in the cluster. To remove them: