# Tenant Image Registry with Quay

The OpenShift internal image registry is not exposed to tenant namespaces on shared clusters. This means BuildConfig/ImageStream workflows that rely on a built-in registry will not work out of the box. To build, store, and pull container images, deploy your own Red Hat Quay registry instance inside your Namespace.

Quay is a full container registry with image storage, vulnerability scanning, RBAC, and replication. It runs as a tenant workload on IaaS resources you already pay for — no separate product, no additional fees beyond your existing CPU, RAM, and storage subscriptions.


# Prerequisites

  • An active Namespace on a Phoeniqs OpenShift cluster with the admin role
  • Sufficient resource quota in your Namespace for Quay components (see Sizing)
  • The oc CLI installed and logged in to your cluster — see Access Your OpenShift

# Sizing

Quay with all managed components requires a minimum footprint to run. The operator provisions PostgreSQL, Redis, Clair (vulnerability scanning), object storage, and the Quay app itself. Plan for the following within your Namespace quota:

Component CPU (request) Memory (request) Storage
Quay app 0.5 vCPU 1 GB —
PostgreSQL (Quay metadata) 100m 512 Mi 10 GB
PostgreSQL (Clair) 100m 512 Mi 10 GB
Redis (Quay cache) 100m 256 Mi —
Clair (vulnerability scanning) 0.25 vCPU 512 Mi —
Object storage (image blobs) — — 50 GB+ (depends on image volume)

Total minimum: approximately 1.5 vCPU, 3 GB RAM, 70 GB storage. Scale up replicas and storage based on your image volume and team size. Billing follows standard Resource Pricing.


# Deploy Quay

The Quay Operator is pre-installed on Phoeniqs shared clusters. You can create a QuayRegistry custom resource directly in your Namespace. The operator provisions and manages all components — PostgreSQL, Redis, Clair, object storage, TLS, routes, and the Quay application — using your Namespace quota.

# Step 1: Create the QuayRegistry

The following manifest has been tested on Phoeniqs shared clusters. All components are managed by the operator, with resource overrides applied to PostgreSQL and Clair PostgreSQL to keep the footprint within typical Namespace quotas:

apiVersion: quay.redhat.com/v1
kind: QuayRegistry
metadata:
  name: example-registry
  namespace: my-project
spec:
  components:
    - managed: true
      kind: clair
    - managed: true
      kind: postgres
      overrides:
        resources:
          requests:
            cpu: 100m
            memory: 512Mi
          limits:
            cpu: 500m
            memory: 600Mi
    - managed: true
      kind: objectstorage
    - managed: true
      kind: redis
    - managed: true
      kind: horizontalpodautoscaler
    - managed: true
      kind: route
    - managed: true
      kind: mirror
    - managed: true
      kind: monitoring
    - managed: true
      kind: tls
    - managed: true
      kind: quay
    - managed: true
      kind: clairpostgres
      overrides:
        resources:
          requests:
            cpu: 100m
            memory: 512Mi
          limits:
            cpu: 500m
            memory: 600Mi
oc apply -f quay-registry.yaml

# Step 2: Wait for Quay to be ready

oc wait quayregistry example-registry -n my-project --for=condition=Available=True --timeout=600s

Once ready, get the Quay UI route:

oc get route example-registry -n my-project

Open the URL in your browser to access the Quay web UI. The first user you create becomes the superuser.


# Use Quay with BuildConfig

Now that you have a registry, point your BuildConfig output at it instead of relying on the OpenShift internal registry.

# Step 1: Create a Quay repository

  1. Log in to the Quay web UI.
  2. Click New Repository.
  3. Name it (e.g. my-app), set it to Public or Private, and click Create.

# Step 2: Create a pull secret for your Namespace

  1. In Quay, go to your user settings → Docker Configuration.
  2. Download the .dockerconfigjson file.
  3. Create a Kubernetes secret in your Namespace:
oc create secret docker-registry quay-pull-secret \
  --docker-server=<quay-route-url> \
  --docker-username=<your-quay-username> \
  --docker-password=<your-quay-password> \
  --docker-email=<your-email>
  1. Link the secret to your service account so pods can pull images:
oc secrets link default quay-pull-secret --for=pull

# Step 3: Create a BuildConfig pointing to Quay

apiVersion: build.openshift.io/v1
kind: BuildConfig
metadata:
  name: my-app-build
  namespace: my-project
spec:
  source:
    binary: {}
  strategy:
    type: Docker
  output:
    to:
      kind: DockerImage
      name: <quay-route-url>/my-app:latest
  pushSecret:
    name: quay-pull-secret
oc apply -f buildconfig.yaml

# Step 4: Start a build

oc start-build my-app-build --from-dir=.

The build will push the resulting image to your Quay registry. Deployments referencing <quay-route-url>/my-app:latest will pull from Quay using the linked pull secret.


# Use Quay with standard Docker/Podman

You can also push images directly to Quay without BuildConfig:

docker login <quay-route-url>
docker tag my-image:latest <quay-route-url>/my-app:latest
docker push <quay-route-url>/my-app:latest

# Expose Quay outside the cluster

By default, the Quay Operator creates an OpenShift Route that makes the registry reachable from within the cluster. If you need to push or pull images from outside Phoeniqs (e.g. from a local machine or CI pipeline), the route is already publicly accessible via the cluster's wildcard DNS.

To expose Quay on a custom hostname, open a service ticket to request DNS configuration.


# Resource cleanup

If you no longer need Quay, remove it to free up Namespace quota:

oc delete quayregistry example-registry -n my-project
oc delete secret quay-pull-secret -n my-project

The operator automatically cleans up the PostgreSQL, Redis, Clair, and object storage PVCs it created when the QuayRegistry is deleted.


# Troubleshooting

Issue Resolution
QuayRegistry stays in Configuring state Check pod status with oc get pods -n my-project. Most often a storage or database connectivity issue.
Build fails with InvalidOutputReference Your BuildConfig output.to must point to your Quay route URL, not an ImageStream. Verify the route with oc get route example-registry.
Pods can't pull from Quay (ImagePullBackOff) Ensure the quay-pull-secret is linked to the default service account with --for=pull.
Quay UI not reachable Wait for the route to be created: oc get route example-registry -n my-project. If no route appears, check that the Quay Operator is healthy.
PVC creation pending Your Namespace storage quota may be exhausted. Check with oc describe resourcequota -n my-project and increase storage in the portal if needed.

# Notes


# Related Pages