Containers, containers everywhere. — Photo © Lode Van de Velde

Getting Started with Kubernetes via Minikube

Kubernetes is an open-source production-grade container orchestration system for automating deployment, scaling, and management of containerized applications.

This tutorial is a simplified version of the Kubernetes Hello World Walkthrough, which uses minikube to run your service on a local Kubernetes cluster instead of Google Container Engine, so that you won’t need a cloud platform at all.

This tutorial uses Mac OS X, but the reader can easily follow on a different OS using the command flavors as noted in the various sections.

Prerequisites

  • Check that your system supports VT-x/AMD-v virtualization by running this command:
$ sysctl -a | grep machdep.cpu.features | grep VMX

if the command returns an output, you’re good to go. Here’s the output on my machine:

$ sysctl -a | grep machdep.cpu.features | grep VMX
machdep.cpu.features: FPU VME DE PSE TSC MSR PAE MCE CX8 APIC SEP MTRR PGE MCA CMOV PAT PSE36 CLFSH DS ACPI MMX FXSR SSE SSE2 SS HTT TM PBE SSE3 PCLMULQDQ DTES64 MON DSCPL VMX SMX EST TM2 SSSE3 CX16 TPR PDCM SSE4.1 SSE4.2 POPCNT AES PCID

If you’re on Linux, you would run instead:

$ cat /proc/cpuinfo | grep 'vmx\|svm'
$ ls /Applications | grep VirtualBox
VirtualBox.app
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.6.0/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
  • Install kubectl for your OS and architecture:
$ curl -Lo kubectl http://storage.googleapis.com/kubernetes-release/release/v1.3.0/bin/darwin/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/

Smoke test your minikube install

In order to validate our deployment and check that everything went well, let’s start the local Kubernetes cluster:

$ minikube start
Starting local Kubernetes cluster...
Kubernetes is available at https://192.168.99.100:8443.
Kubectl is now configured to use the cluster.

We can inspect the cluster for running pods:

$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system kube-addon-manager-minikubevm 1/1 Running 3 3d
kube-system kubernetes-dashboard-06y41 1/1 Running 3 3d

…and cluster nodes:

$ kubectl get nodes
NAME STATUS AGE
minikubevm Ready 3d

Install the hello-minikube pod

The minikube project on GitHub offers a quick start demo which uses a pre-built Docker image hello-minikube. Since we started the minikube cluster already, we can skip the first step:

$ minikube start
Starting local Kubernetes cluster...
Kubernetes is available at https://192.168.99.100:8443.
Kubectl is now configured to use the cluster.

Now, let’s run the built-in hello-minikube pod. This will create a deployment for the pod:

$ kubectl run hello-minikube --image=gcr.io/google_containers/echoserver:1.4 --port=8080
deployment "hello-minikube" created

We can inspect the pods and the deployments to verify these have been updated with the following commands:

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-minikube-2433534028-v8ojh 1/1 Running 0 1m
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
hello-minikube 1 1 1 1 2m

In order to access the hello-minikube service, we must first expose the deployment to an external IP via the command:

$ kubectl expose deployment hello-minikube --type=NodePort
service "hello-minikube" exposed

Note we must use the type=NodePort because minikube doesn’t support the LoadBalancer service. We can check if the service was exposed by listing services:

$ kubectl get services
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-minikube 10.0.0.228 <nodes> 8080/TCP 12s
kubernetes 10.0.0.1 <none> 443/TCP 3d

Now we can either curl the service from the CLI, or hit it via the browser. In order to figure out its external IP address and port, we can use the command:

$ minikube service hello-minikube --url
http://192.168.99.100:31226
$ curl $(minikube service hello-minikube --url)
CLIENT VALUES:
client_address=172.17.0.1
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://192.168.99.100:8080/
SERVER VALUES:
server_version=nginx: 1.10.0 - lua: 10001
HEADERS RECEIVED:
accept=*/*
host=192.168.99.100:31226
user-agent=curl/7.43.0
BODY:
-no body in request-%

Note you can figure out the IP address, which is mutable and controlled by VirtualBox, via the command minikube ip, or inspecting the output of ifconfig:

$ ifconfig
...
vboxnet0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
ether 0a:00:27:00:00:00
inet 192.168.99.1 netmask 0xffffff00 broadcast 192.168.99.255

Once we’re done with the hello-minikube service, we can delete its deployment and service, in order to free up resources, and verify they were in fact deleted:

$ kubectl delete service,deployment hello-minikube
service "hello-minikube" deleted
deployment "hello-minikube" deleted
$ kubectl get pods
$ kubectl get services
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.0.0.1 <none> 443/TCP 3d

Build and install a node service with Docker

This last example is a bit more complex and requires the creation of a small node server, build it into a Docker image with a Dockerfile, and run it in Kubernetes.

Let’s create a simple node project hello-node:

$ mkdir hello-node && cd hello-node && touch Dockerfile server.js
$ tree
.
├── Dockerfile
└── server.js

Let’s create a simple http server that returns a Hello World! response:

$ vi server.js
var http = require('http');
var handleRequest = function(request, response) {
response.writeHead(200);
response.end('Hello World!');
};
var helloServer = http.createServer(handleRequest);
helloServer.listen(8080);

Let’s edit the Dockerfile to declare this image will use node 4.4, and the container will run the service by executing the server.js file:

$ vi Dockerfile
FROM node:4.4
EXPOSE 8080
COPY server.js .
CMD node server.js

Before issuing any Docker commands, let’s set the Docker environment. Similarly to running eval $(docker-machine env), we generate Docker environment variables for the minikube runtime using the command minikube docker-env:

$ eval $(minikube docker-env)

Now, let’s build the image. This will take some time, as it will fetch images for dependencies like node 4.4 from the Docker hub. Once finished, you’ll have a new Docker image ready to deploy (note the trailing dot `.` in the command: this tells Docker to build the current directory):

$ docker build -t hello-node:v1 .
Sending build context to Docker daemon 6.144 kB
Step 1 : FROM node:4.4
---> abb6383ef5fe
Step 2 : EXPOSE 8080
---> Running in a4330e4790a7
---> a1f021471d1c
Removing intermediate container a4330e4790a7
Step 3 : COPY server.js .
---> 1b394ed6fbaf
Removing intermediate container 31c5e5e505bf
Step 4 : CMD node server.js
---> Running in 6e62fbd3174f
---> ff428ba5193c
Removing intermediate container 6e62fbd3174f
Successfully built ff428ba5193c
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-node v1 ff428ba5193c 20 seconds ago 656.9 MB
gcr.io/google_containers/kubernetes-dashboard-amd64 v1.1.0 d023c050c065 10 days ago 58.65 MB
node 4.4 abb6383ef5fe 3 weeks ago 656.9 MB
gcr.io/google_containers/echoserver 1.4 a90209bb39e3 8 weeks ago 140.4 MB
gcr.io/google-containers/kube-addon-manager-amd64 v2 a876fb07f9c2 9 weeks ago 231.1 MB
gcr.io/google_containers/pause-amd64 3.0 99e59f495ffa 11 weeks ago 746.9 kB

Now we can deploy the hello-node pod to our local Kubernetes cluster via kubectl:

$ kubectl run hello-node --image=hello-node:v1 --port=8080
deployment "hello-node" created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-node-2686040790-0t8q4 1/1 Running 0 1m
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
hello-node 1 1 1 1 1m

As before, we must expose the deployment to an external IP address and port in order to access it via curl:

$ kubectl expose deployment hello-node --type=NodePort
service "hello-node" exposed
$ kubectl get services
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-node 10.0.0.77 <nodes> 8080/TCP 12s
kubernetes 10.0.0.1 <none> 443/TCP 3d
$ curl $(minikube service hello-node --url)
Hello World!%

Victory! We have successfully written, built, and deployed a simple node service as Docker image to our local Kubernetes cluster :-)

This toy project is just a starter to become productive with Kubernetes locally, before you start publishing pods to your cloud platform environment and incur in charges. It allows you to make your first baby steps without fear of scaling down your credit, while you run your experiments.

Cleanup

Let’s not forget to delete the service and deployment for hello-node, and shut down the minikube cluster once finished:

$ kubectl delete service,deployment hello-node
service "hello-node" deleted
deployment "hello-node" deleted
$ minikube stop
Stopping local Kubernetes cluster...
Machine stopped.

Thanks for reading through this tutorial! Let me know if you found it useful in the comments ;-)