minikube provides DevOps teams with a local development Kubernetes cluster. Developing Kubernetes applications locally often entails building and deploying local Docker images. While minikube will download any Docker images hosted on an external Docker registry, exposing locally built images requires loading the images into the minikube cluster and being aware of some edge cases that throw unhelpful error messages.
In this post, I show you how to deploy locally built Docker images to minikube.
Read our white paper: A leader's guide to Kubernetes CD at scale
Learn how to overcome technical hurdles and business challenges and successfully implement Kubernetes.
Get the white paperBuilding the Docker images
The Octopus underwater sample app provides a simple Docker image for testing. Run the following command to clone the git repo:
git clone https://github.com/OctopusSamples/octopus-underwater-app.git
Enter the project directory:
cd octopus-underwater-app
Then build the image with the command:
docker build . -t underwater
Finally, run the Docker image with the command:
docker run -p 5000:80 underwater
The sample web app is then available at http://localhost:5000
.
Pushing images to minikube
Pushing local images to minikube is a straightforward process with the command:
minikube image load underwater
Deploying the image
To deploy the image, save the following YAML to a file called underwater.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: underwater
labels:
app: web
spec:
selector:
matchLabels:
app: web
replicas: 1
strategy:
type: RollingUpdate
template:
metadata:
labels:
app: web
spec:
containers:
- name: underwater
image: underwater
imagePullPolicy: Never
ports:
- containerPort: 80
Then deploy the app with the command:
kubectl apply -f underwater.yaml
The application is then successfully deployed to the minikube cluster.
It's important to note that the Docker image has no tag, which means it has the default tag of latest
. So the image
property in the YAML above could be replaced with the following text, as the 2 image references are equivalent:
image: underwater:latest
Using images with the latest
tag has special implications which require setting the imagePullPolicy
to Never
(or IfNotPresent
). To understand why, you need to understand the default image pull policy.
Using latest images
The Kubernetes documentation provides this advice on the default image pull policy:
- if you omit the imagePullPolicy field, and the tag for the container image is :latest, imagePullPolicy is automatically set to Always;
- if you omit the imagePullPolicy field, and you don't specify the tag for the container image, imagePullPolicy is automatically set to Always;
- if you omit the imagePullPolicy field, and you specify the tag for the container image that isn't :latest, the imagePullPolicy is automatically set to IfNotPresent.
To understand why this is important, deploy the following YAML with no imagePullPolicy
value set:
apiVersion: apps/v1
kind: Deployment
metadata:
name: underwater
labels:
app: web
spec:
selector:
matchLabels:
app: web
replicas: 1
strategy:
type: RollingUpdate
template:
metadata:
labels:
app: web
spec:
containers:
- name: underwater
image: underwater
ports:
- containerPort: 80
View the status of the pods created by this deployment with the command:
kubectl get pods
You see that the status is ImagePullBackOff
:
NAME READY STATUS RESTARTS AGE
underwater-847d6f9646-pvzxb 0/1 ImagePullBackOff 0 15m
This is because you deployed an image with the latest
tag and didn't specify the imagePullPolicy
, meaning the default value of Always
is used. This in turn means minikube attempts to download the image docker.io/underwater:latest
, because images with no registry in their name default to docker.io
. The image docker.io/underwater:latest
does not exist, hence the ImagePullBackOff
error.
There are 2 ways around this:
- Set
imagePullPolicy
toNever
orIfNotPresent
- Add a tag to the image, for example,
docker build . -t underwaterapp:0.0.1
andminikube image load underwater:0.0.1
Conclusion
Using locally built Docker images in minikube is an easy process, but you need to be aware of the rules surrounding the image pull policy to ensure Kubernetes doesn't attempt to download a non-existent image from the default Docker registry.
Happy deployments!