knext

Private registries

Pulling your app image from OCIR, private GHCR, ECR, or any registry that requires credentials — the manual pull-secret path that works today, and what to expect from doctor.

Most real registries are private. OCIR, a private GitHub Container Registry package, and ECR all refuse anonymous pulls — so the first deploy of an app whose image lives on one of them fails in a specific, confusing way: the deploy applies cleanly, the service is created, and then the pod sits in ImagePullBackOff while the registry answers 401/403 (GHCR words it "Anonymous users are only allowed read access").

kn-next doctor checks for exactly this before it costs you a debugging session: for every deployed app it probes whether the image is anonymously pullable, and if it is not — and no pull credential is attached to the app's ServiceAccount — it warns and points here. A credential Secret that merely exists in the namespace is not enough (that case gets its own, more specific warning — see step 2).

This page documents the current, manual path: you create the credential and attach it yourself using standard Kubernetes objects. Attaching pull secrets is planned as a first-class knext config option, at which point this page becomes the long way around — the recipe below will keep working either way, because it only uses Kubernetes-native mechanics.

The recipe

Three steps, in order. The order matters — step 3 is not optional.

1. Create the registry credential

A kubernetes.io/dockerconfigjson Secret in the app's namespace (the namespace you deploy into):

kubectl create secret docker-registry regcred \
  --namespace <app-namespace> \
  --docker-server=<registry> \
  --docker-username=<username> \
  --docker-password=<password-or-token>

What goes in --docker-server and the credential fields differs per registry:

Registry--docker-serverCredential
GHCRghcr.ioa GitHub PAT with read:packages as the password
OCIR<region-key>.ocir.io (e.g. fra.ocir.io)username <tenancy-namespace>/<user>, an auth token as the password
ECR<account>.dkr.ecr.<region>.amazonaws.comusername AWS, aws ecr get-login-password output as the password — note ECR tokens expire after 12 hours, so this needs a refresh mechanism (e.g. a credential-helper CronJob)

2. Attach it to the app's ServiceAccount

Each app runs under a ServiceAccount named <app-name>-sa in its namespace. Pods resolve their pull secrets from that ServiceAccount, so that is where the credential attaches:

kubectl patch serviceaccount <app-name>-sa \
  --namespace <app-namespace> \
  --patch '{"imagePullSecrets": [{"name": "regcred"}]}'

This step is the one that actually takes effect — creating the Secret without attaching it here changes nothing, and kn-next doctor calls that case out specifically.

The patch replaces the whole imagePullSecrets list. If the ServiceAccount already lists a credential — a second registry, say — include every entry in the patch, not just the new one, or the existing one is silently dropped.

3. Redeploy

Pull secrets are resolved when a pod is created, not when the ServiceAccount changes. A revision that is already stuck in ImagePullBackOff was created without the credential and will not pick it up retroactively — patching the ServiceAccount alone rescues nothing you can see. Roll a new revision:

kn-next deploy

The new revision's pods resolve the credential at creation and pull cleanly.

Verifying

  • kn-next doctor — the "App image pullable" check turns from a warning into a pass once the credential is attached to the app's ServiceAccount. A Secret that exists but is not attached keeps a warning (with the attach command in the hint). Note what a pass verifies: attachment, not that the registry accepts the credential — an attached but wrong credential still fails at pod creation.
  • kubectl get pods -n <app-namespace> — a stuck pull shows ImagePullBackOff / ErrImagePull; kubectl describe pod <pod> shows the registry's actual error message in the events.

Caveats worth knowing

  • The ServiceAccount is managed by the operator. knext creates <app-name>-sa and reconciles it. Today a manually added imagePullSecrets list is preserved across reconciles — but it is a manual patch on a managed object, which is exactly why a first-class option is planned. Keep the patch in your cluster runbook so it is re-applied if the ServiceAccount is ever recreated.
  • One credential per namespace is usually enough. The Secret is namespace-scoped; every app in the namespace can reference the same one from its own ServiceAccount.
  • Never commit the credential. The Secret lives in the cluster only — not in your repository, not in kn-next.config.ts, not in the image.

On this page