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:

  1. A local image already available to the Kubernetes node

  2. A public container registry such as Docker Hub

  3. 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.

TypeWhere Image Comes FromCredentials?Main Method
LocalKubernetes nodeNominikube image load
PublicPublic registryUsually NoPull directly
PrivatePrivate registryYesimagePullSecret

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

Popular posts from this blog

Managing Amazon EBS Volumes and Snapshots Across Regions

Git for Beginners: Complete Guide from Installation to First Push on GitHub

AWS - Amazon Web Services