Kubernetes Pods: Public & Private Container Registries, Local Images, Authentication and Image Pulling
Kubernetes Pods: Public & Private Container Registries, Local Images, Authentication and Image Pulling
Complete Beginner-to-Practical Guide
When Kubernetes creates a Pod, it needs a container image.
That image can come from:
A local image already available to the Kubernetes node
A public container registry such as Docker Hub
A private container registry requiring authentication
Understanding this process helps us troubleshoot common Kubernetes errors such as:
ErrImagePull
ImagePullBackOff
1. First Understand Image → Container → Pod
The easiest way to remember the relationship is:
Container Image
↓
Container
↓
Pod
In Kubernetes terminology, the Pod is the Kubernetes unit that contains the container:
Pod
└── Container
└── Image
For example:
Pod
└── nginx container
└── nginx:latest image
Remember
Image = package/template
Container = running instance of the image
Pod = Kubernetes unit containing one or more containers
2. What Happens When We Create a Pod?
Suppose our YAML contains:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
We run:
kubectl apply -f pod.yaml
Kubernetes performs this process:
YAML
↓
kubectl apply
↓
Kubernetes API Server
↓
Scheduler
↓
Kubernetes Node
↓
Kubelet
↓
Check image
↓
Is image available on the node?
├── YES → Use local image
│
└── NO → Pull image from registry
↓
Image available
↓
Container created
↓
Container started
↓
Pod Running
3. Does the Image Have to Exist Locally?
No.
This is one of the most important concepts.
The image doesn't have to already exist locally.
It only needs to be accessible to the Kubernetes node.
There are two main possibilities.
Option 1 — Image already exists on Kubernetes node
Local Image
↓
Kubernetes Node
↓
Container
↓
Pod
Option 2 — Image doesn't exist on Kubernetes node
Container Registry
↓
Kubernetes Node
↓
Pull Image
↓
Container
↓
Pod
Therefore:
Kubernetes needs access to the image, not necessarily a pre-existing local copy.
4. If I Have a Local Image, Where Should I Keep It?
This is an extremely important question.
Suppose you build an image:
docker build -t myapp:v1 .
Now check:
docker images
You may see:
REPOSITORY TAG
myapp v1
The important question is:
Where is this image stored?
It is stored in the Docker image store of the Docker environment where you built it.
But Kubernetes needs the image to be available to the Kubernetes node.
These environments may be different.
5. Local Image with Minikube
Since we are using:
minikube start --driver=docker
we have:
Your Docker Environment
│
│
└── myapp:v1
Minikube Kubernetes Node
│
└── Does it have myapp:v1?
The image existing in your Docker environment does not automatically mean that the Minikube node has it.
Therefore, you can load the image into Minikube.
6. Step-by-Step: Use a Local Image in Minikube
Step 1 — Build the image
For example:
docker build -t myapp:v1 .
Check:
docker images
You should see:
REPOSITORY TAG
myapp v1
Step 2 — Load the image into Minikube
Run:
minikube image load myapp:v1
This transfers the image into the Minikube environment.
The flow is:
Local Docker
↓
myapp:v1
↓
minikube image load
↓
Minikube Node
↓
Kubernetes Pod
Step 3 — Verify the image
Run:
minikube image ls | grep myapp
If the image is listed, Minikube has access to it.
7. Create a Pod Using the Local Image
Create:
nano pod-local.yaml
Add:
apiVersion: v1
kind: Pod
metadata:
name: local-app
spec:
containers:
- name: myapp
image: myapp:v1
Apply:
kubectl apply -f pod-local.yaml
Check:
kubectl get pods
Expected:
NAME READY STATUS RESTARTS AGE
local-app 1/1 Running 0 ...
8. Important: imagePullPolicy for Local Images
There is one more important point.
When using a local image, Kubernetes must not unnecessarily try to pull it from a registry.
For predictable local-image behavior, you can specify:
imagePullPolicy: Never
Example:
apiVersion: v1
kind: Pod
metadata:
name: local-app
spec:
containers:
- name: myapp
image: myapp:v1
imagePullPolicy: Never
Now Kubernetes means:
Do not try to pull this image. Use the image already available on the node.
If the image is missing from the node, the Pod will fail.
This is useful for learning and local development.
9. Local Image — Complete Process
1. Build image
↓
docker build -t myapp:v1 .
↓
2. Image exists in local Docker
↓
docker images
↓
3. Load image into Minikube
↓
minikube image load myapp:v1
↓
4. Verify
↓
minikube image ls
↓
5. Pod YAML
↓
image: myapp:v1
↓
6. kubectl apply
↓
7. Kubernetes finds image
↓
8. Container created
↓
9. Pod Running
10. Public Registry
Now let's use an image from a public registry.
We'll use:
nginx:latest
This is publicly available on Docker Hub.
The flow is:
Docker Hub
↓
nginx:latest
↓
Kubernetes Node
↓
Pull Image
↓
Create Container
↓
Pod Running
11. Step-by-Step: Public Image
Step 1 — Create YAML
nano pod-public.yaml
Add:
apiVersion: v1
kind: Pod
metadata:
name: nginx-public
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
Step 2 — Create Pod
kubectl apply -f pod-public.yaml
Step 3 — Check Pod
kubectl get pods
Expected:
NAME READY STATUS RESTARTS AGE
nginx-public 1/1 Running 0 ...
12. How Does Kubernetes Know Where nginx Is?
When we write:
image: nginx:latest
Kubernetes/container runtime interprets this as the standard public registry image:
docker.io/library/nginx:latest
For a custom registry, we normally specify the registry explicitly:
image: registry.example.com/myteam/myapp:v1
13. How to Check Whether an Image Is Accessible
There are several useful checks.
Check 1 — Local Docker Images
docker images
Specific image:
docker images nginx
Check 2 — Test Registry Access
For a public image:
docker pull nginx:latest
Successful result:
Status: Image is up to date for nginx:latest
or:
Status: Downloaded newer image for nginx:latest
Check 3 — Check Minikube Images
minikube image ls
Search:
minikube image ls | grep nginx
Check 4 — Check What Image Kubernetes Is Using
kubectl describe pod nginx-public
Look under:
Containers:
You should see:
Image: nginx:latest
Check 5 — Check Kubernetes Events
kubectl describe pod nginx-public
At the bottom:
Events:
For successful pulling, you may see:
Pulling image "nginx:latest"
Successfully pulled image "nginx:latest"
Created container nginx
Started container nginx
14. Private Registry
Now let's move to a private registry.
Suppose our company has:
mycompany/myapp:v1
and the repository is private.
Kubernetes cannot pull it anonymously.
We need:
Private Registry
↓
Authentication
↓
Kubernetes Credentials
↓
Pull Image
↓
Create Container
↓
Pod Running
15. How Do We Give Credentials to Kubernetes?
This is the important part.
We normally create a Kubernetes Secret of type:
kubernetes.io/dockerconfigjson
The Secret contains the registry authentication information.
We then tell the Pod to use that Secret through:
imagePullSecrets:
So the relationship is:
Registry Username + Password
↓
Kubernetes Secret
↓
imagePullSecrets
↓
Pod specification
↓
Kubelet
↓
Private Registry
↓
Pull Image
16. Step-by-Step: Private Docker Hub Image
Assume we have:
docker.io/<USERNAME>/myapp:v1
and it is private.
Step 1 — Log in to Docker
On your machine:
docker login
Enter your Docker Hub credentials.
For Docker Hub, using a Personal Access Token instead of your account password is recommended.
Then test:
docker pull <USERNAME>/myapp:v1
If it succeeds, your Docker environment can access the private image.
17. Step 2 — Create Kubernetes Secret
Run:
kubectl create secret docker-registry regcred \
--docker-server=https://index.docker.io/v1/ \
--docker-username=<USERNAME> \
--docker-password=<PASSWORD_OR_TOKEN> \
--docker-email=<EMAIL>
For example:
USERNAME → your Docker Hub username
PASSWORD → password/token
EMAIL → your email
Do not put real credentials into a public blog or Git repository.
18. Step 3 — Verify the Secret
Run:
kubectl get secrets
You should see:
NAME TYPE DATA AGE
regcred kubernetes.io/dockerconfigjson 1 ...
You can also check:
kubectl describe secret regcred
Do not expect to see the actual password in plain text.
19. Step 4 — Use the Secret in the Pod
Create:
nano pod-private.yaml
Add:
apiVersion: v1
kind: Pod
metadata:
name: private-app
spec:
containers:
- name: myapp
image: docker.io/<USERNAME>/myapp:v1
imagePullSecrets:
- name: regcred
Replace:
<USERNAME>
with your Docker Hub username.
20. Step 5 — Create the Pod
Run:
kubectl apply -f pod-private.yaml
Then:
kubectl get pods
Expected:
NAME READY STATUS RESTARTS AGE
private-app 1/1 Running 0 ...
21. Private Registry Complete Flow
Docker Hub Private Repository
↓
Username + Token
↓
Kubernetes Secret
↓
imagePullSecrets
↓
Kubernetes Node
↓
Authenticate
↓
Pull Image
↓
Image Available
↓
Create Container
↓
Pod
↓
Running
22. What Happens If Credentials Are Wrong?
Suppose:
image: docker.io/<USERNAME>/myapp:v1
but the credentials are wrong or the Secret isn't configured correctly.
Run:
kubectl get pods
You may see:
private-app 0/1 ErrImagePull
Then:
kubectl describe pod private-app
Look at:
Events:
You may see:
unauthorized
or:
pull access denied
or another authentication-related error.
23. Public vs Private vs Local
Now we can compare all three.
| Type | Where Image Comes From | Credentials? | Main Method |
|---|---|---|---|
| Local | Kubernetes node | No | minikube image load |
| Public | Public registry | Usually No | Pull directly |
| Private | Private registry | Yes | imagePullSecret |
24. Three Complete Scenarios
Scenario A — Local Image
Build Image
↓
docker build
↓
Local Docker
↓
minikube image load
↓
Minikube Node
↓
Pod
↓
Running
Commands:
docker build -t myapp:v1 .
docker images
minikube image load myapp:v1
minikube image ls | grep myapp
kubectl apply -f pod-local.yaml
kubectl get pods
Scenario B — Public Registry
Public Registry
↓
Kubernetes Node
↓
Pull Image
↓
Container
↓
Pod
↓
Running
Commands:
docker pull nginx:latest
kubectl apply -f pod-public.yaml
kubectl get pods
kubectl describe pod nginx-public
The docker pull command is only a test from your Docker environment; Kubernetes itself can pull the image from the registry when creating the Pod.
Scenario C — Private Registry
Private Registry
↓
Authentication
↓
Kubernetes Secret
↓
imagePullSecrets
↓
Kubernetes Node
↓
Pull Image
↓
Container
↓
Pod
↓
Running
Commands:
docker login
docker pull <USERNAME>/myapp:v1
kubectl create secret docker-registry regcred \
--docker-server=https://index.docker.io/v1/ \
--docker-username=<USERNAME> \
--docker-password=<TOKEN> \
--docker-email=<EMAIL>
kubectl get secrets
kubectl apply -f pod-private.yaml
kubectl get pods
kubectl describe pod private-app
25. What Does imagePullPolicy Mean?
Kubernetes has an imagePullPolicy setting that controls when the image should be pulled.
Example:
imagePullPolicy: Always
means Kubernetes will attempt to pull the image whenever the container is started.
For a local-only image:
imagePullPolicy: Never
means:
Do not pull the image. It must already exist on the Kubernetes node.
Example:
apiVersion: v1
kind: Pod
metadata:
name: local-app
spec:
containers:
- name: myapp
image: myapp:v1
imagePullPolicy: Never
This is useful when you deliberately want to test a locally loaded image.
26. Important Difference Between docker pull and Kubernetes Pulling
This is a very common beginner confusion.
When you run:
docker pull nginx:latest
Docker pulls the image.
When you run:
kubectl apply -f pod.yaml
and the image isn't available on the Kubernetes node, the container runtime used by Kubernetes pulls the image.
Therefore:
docker pull
↓
Your Docker environment
while:
kubectl apply
↓
Kubernetes
↓
Kubernetes Node
↓
Container Runtime
↓
Registry
They are related, but they are not necessarily operating on the same image store.
27. Why Did We Get ErrImagePull Earlier?
We had this in our YAML:
image: g1:v1
Kubernetes tried:
g1:v1
The Events showed:
Failed to pull image "g1:v1"
and:
pull access denied for g1
repository does not exist
The actual problem was the image name.
We later successfully pulled:
docker pull nginx:latest
but Kubernetes was still trying to pull:
g1:v1
So the correct troubleshooting approach was:
kubectl describe pod nginx-pod
Then check:
Events:
This showed the exact image Kubernetes was trying to pull.
28. Complete Image Troubleshooting Process
Whenever you see:
ErrImagePull
or:
ImagePullBackOff
follow this exact process.
Step 1 — Check Pod
kubectl get pods
Step 2 — Find exact error
kubectl describe pod <pod-name>
Step 3 — Go to Events
Look for:
Failed to pull image
Step 4 — Check image name
cat pod.yaml
Confirm:
image: <correct-image>:<correct-tag>
Step 5 — Determine the image source
Ask:
Is it:
↓
Local?
Public registry?
Private registry?
Step 6 — If local
Make sure the image exists on the Kubernetes node:
minikube image ls
If necessary:
minikube image load <image>
Step 7 — If public
Test registry access:
docker pull <image>
Then inspect Kubernetes Events for network or registry errors.
Step 8 — If private
Check:
kubectl get secrets
Make sure the Pod contains:
imagePullSecrets:
- name: regcred
Step 9 — Recreate/check the Pod
kubectl delete pod <pod-name>
kubectl apply -f pod.yaml
kubectl get pods
29. Most Important Commands
Docker
docker images
docker pull <image>
docker build -t <image>:<tag> .
docker login
Minikube
minikube status
minikube image ls
minikube image load <image>
minikube ssh
Kubernetes
kubectl apply -f pod.yaml
kubectl get pods
kubectl describe pod <pod-name>
kubectl get events
kubectl logs <pod-name>
kubectl get secrets
30. Golden Rule
Remember:
Kubernetes does NOT require
every image to already exist locally.
Instead:
IMAGE
│
┌────────┴────────┐
↓ ↓
Local to Node Container Registry
│ │
│ ┌─────┴─────┐
│ ↓ ↓
│ Public Private
│ │ │
│ │ Authentication
│ │ │
└───────────┴───────────┘
↓
Kubernetes Node
↓
Container Created
↓
Pod
↓
Running
31. One-Line Memory Trick
Pod needs an image. If the image is already on the Kubernetes node, Kubernetes can use it. If it isn't, Kubernetes pulls it from a registry. Public images can usually be pulled directly; private images require authentication such as an
imagePullSecret.
32. Final Mental Model
Keep this picture in your mind:
CONTAINER IMAGE
│
┌──────────────┼──────────────┐
│ │ │
↓ ↓ ↓
LOCAL PUBLIC PRIVATE
IMAGE REGISTRY REGISTRY
│ │ │
│ │ Credentials
│ │ │
│ │ imagePullSecret
│ │ │
└──────────────┼──────────────┘
↓
KUBERNETES NODE
↓
IMAGE AVAILABLE
↓
CONTAINER CREATED
↓
CONTAINER STARTED
↓
POD
↓
RUNNING
And when something goes wrong:
Pod not Running
↓
kubectl get pods
↓
ErrImagePull?
↓
kubectl describe pod <pod>
↓
Events
↓
Check:
✓ Image name
✓ Tag
✓ Registry
✓ Network
✓ Authentication
✓ imagePullSecret
✓ Image on Kubernetes node
↓
Fix
↓
Pod Running
Conclusion
Before moving to ReplicaSets and Deployments, we should be comfortable with this complete Pod image lifecycle:
Image
↓
Where is the image?
├── Local Kubernetes node
├── Public registry
└── Private registry
↓
Authentication
↓
Image accessible
↓
Container created
↓
Container started
↓
Pod Running
Once this is clear, we can move to the next Kubernetes concept:
Pod → Why a Pod alone is not enough → ReplicaSet → automatic Pod replacement → maintaining the desired number of Pods.
Comments
Post a Comment