## TL;DR

Kubernetes cant pull from a private registry because it has no credentials, so create a docker-registry secret and reference it as an imagePullSecret in the pod. Most failed-to-pull-image errors are a missing or expired secret, or a typo in the image name. Fix the credentials, the pod pulls.

## The error

```text
Failed to pull image "registry.example.com/app:v1": rpc error: code = Unknown desc = failed to pull and unpack image: failed to resolve reference: pull access denied
```

Also: `ImagePullBackOff`, `ErrImagePull`, `unauthorized: authentication required`, `no basic auth credentials`.

## Use this when

- pod status is ImagePullBackOff or ErrImagePull
- describe pod shows `Failed to pull image` or `pull access denied`
- you just moved an image to a private registry
- registry credentials were rotated recently

## Not for

- image build errors (those happen before any pull)
- pods that pull fine and then crash (CrashLoopBackOff)
- DNS or network failures reaching the registry (test connectivity first)

## Steps

1. Get the exact failure:

```bash
kubectl describe pod [pod-name] -n [namespace]
```

Expected: Events show `Failed to pull image` with the registry's reason. `unauthorized` or `pull access denied` means credentials; `manifest unknown` or `not found` means the tag or repo name is wrong.

2. Check what the pod is trying to pull:

```bash
kubectl get pod [pod-name] -n [namespace] -o jsonpath='{.spec.containers[*].image}'
kubectl get pod [pod-name] -n [namespace] -o jsonpath='{.spec.imagePullSecrets}'
```

Expected: the full image path including registry host. If imagePullSecrets is empty and the registry is private, thats your problem.

3. Create the registry secret value ```bash
kubectl create secret docker-registry regcred \
  --docker-server=[registry-host] \
  --docker-username=[username] \
  --docker-password value [your value] \
  -n [namespace]
```

Expected: `secret/regcred created`. Use a token or robot account, not a personal password, so rotations dont break deploys.

4. Attach it to the workload:

```yaml
spec:
  imagePullSecrets:
    - name: regcred
  containers:
    - name: app
      image: registry.example.com/app:v1
```

Apply, then verify the pod pulls:

```bash
kubectl get pod [pod-name] -n [namespace] -w
```

Expected: pod moves from ImagePullBackOff to Running. If it still fails, the secret contents are wrong, not the wiring.

5. Verify the secret actually works by testing the credentials yourself:

```bash
docker login [registry-host] -u [username]
```

Expected: `Login Succeeded`. If login fails here, the credentials are bad at the registry, not in Kubernetes.

6. For a whole namespace, skip per-pod secrets:

```bash
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "regcred"}]}' -n [namespace]
```

Expected: every new pod in the namespace inherits the secret. Existing pods need a restart to pick it up.

### Variant: `manifest unknown` or `repository not found`

The tag doesnt exist or the repo name is misspelled. List tags at the registry and fix the image field. Credentials are fine in this case.

### Variant: works on Docker Hub but fails on a mirror or proxy

Point imagePullSecrets at the mirror's credentials and make sure the image path uses the mirror host. Also check the mirror actually has the tag cached.

### Variant: ECR, GCR, or ACR with expiring tokens

Cloud registry tokens expire (ECR: 12 hours). Use the cloud credential helper or an external-secrets sync that refreshes the secret, not a static token.

## Why it happens

The kubelet pulls images with no credentials by default. Public images work; anything private gets a 401 from the registry. imagePullSecrets are the only way to hand the kubelet credentials, and theyre per-namespace, so a secret in the wrong namespace silently does nothing.

## Edge cases

- Secrets are namespace-scoped: the secret and the pod must live in the same namespace.
- `imagePullPolicy: Always` with a private registry re-authenticates every pull; a rotated credential breaks running pods on reschedule.
- Some registries rate-limit anonymous pulls; even public images can need a secret to stay under the limit.
- On managed clusters, the nodes service account may already have pull rights to the cloud provider's registry; check that before adding secrets.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_9A0xt1e8rF6hDW0gximBzQ
