Working in technology, whether that be software development, DevOps, or system administration, you’ve undoubtedly heard of Kubernetes. It’s one of the fastest growing pieces of technology that I’ve ever seen and that’s for good reason. As a powerful tool, Kubernetes does have quite a learning curve. If you’re ready to start learning it, I think the best way is to use Minikube to run a Kubernetes cluster locally. In this post, we’ll take a look at how Minikube works and how we can use it to experiment with the concepts of Kubernetes.
What is Minikube?
Minikube is a tool developed by the Kubernetes team to allow you to spin up a full Kubernetes cluster on your workstation within a VM. This approach is a lot more cost effective than spinning up multiple servers in your cloud provider of choice, wiring them together, and then learning the basics of Kubernetes. Setting up a Kubernetes cluster from scratch can be quite the hurdle and would definitely stop many people from learning Kubernetes before ever getting to know the tool itself. This is the problem that Minikube solves.
To install Minikube, we need to make sure that we already have a hypervisor installed on our system so that we can run VMs. This does mean that we can’t work with Minikube from within a VM because nesting VMs is an issue. For most people, VirtualBox is a great, free hypervisor that you can install to use with Minikube.
Once you have a hypervisor installed, you’re ready to install Minikube. I’m going to assume that you’re using a Unix based workstation, but it is entirely possible to use Minikube from Windows. The easiest way to install Minikube is by following the official installation documentation. On the macOS machine that I’m going to use,I will download the latest static binary, make it executable, and put it into my $PATH:
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64 && chmod +x minikube && mv minikube /usr/local/bin/
Now I have access to the
minikube CLI. The last thing that we’ll need to install is the Kubernetes CLI:
kubectl. Our approach to installing
kubectl will be very similar to how we installed
minikube. You can look at the official documentation to see what you will modify if you’re using Linux or Windows:
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl && chmod +x kubectl && mv kubectl /usr/local/bin/
Now we have all of the tools that we need to start working with Kubernetes locally.
Starting Our Kubernetes Cluster
Starting our Kubernetes cluster couldn’t be much (if any) simpler than what Minikube has made it. To get our cluster running, we simply need to run
Note: This may take a little while.
$ minikube start minikube v0.34.1 on darwin (amd64) Creating virtualbox VM (CPUs=2, Memory=2048MB, Disk=20000MB) ... Downloading Minikube ISO ... 184.30 MB / 184.30 MB [============================================] 100.00% 0s "minikube" IP address is 192.168.99.100 Configuring Docker as the container runtime ... ✨ Preparing Kubernetes environment ... Downloading kubeadm v1.13.3 Downloading kubelet v1.13.3 Pulling images required by Kubernetes v1.13.3 ... Launching Kubernetes v1.13.3 using kubeadm ... Configuring cluster permissions ... Verifying component health ..... kubectl is now configured to use "minikube" Done! Thank you for using minikube!
It took quite a few steps to get our Kubernetes cluster up and running, but I want to call your attention to the second to last one:
kubectl is now configured to use "minikube"
kubectl tool can be used to connect with multiple clusters and the cluster that Minikube created is just like any other cluster. Running
minikube start not only created our cluster, but it also took the time to set the configuration values necessary for our
kubectl commands to interact with that cluster.
Now we’re ready to start using Kubernetes.
A Brief Overview of Kubernetes Terms
When first starting out with Kubernetes, there are going to be quite a few terms that get thrown around that don’t show up elsewhere. Let’s break down some of the terms so that we have a shared vocabulary for talking about Kubernetes:
- Pod: Pods are the atomic unit when working with Kubernetes. A pod consists of one or more containers and they’ll all be deployed on the same host. Pod definitions also include specifications for required resources and other things like volumes.
- Deployment: A deployment is a declarative specification for the desired end state of pods that need to be deployed together. Deployments are responsible for managing pods and the most common way that we go about creating pods.
- Service: A service declares how pods can be accessed. Conceptually, a service is similar to a reverse proxy for pods.
With these terms defined, we can create our first pod, deployment, and service.
Our First Deployment
For the remainder of this tutorial, we’ll use the
kubectl utility to create and work with Kubernetes objects. While pods are the smallest building block used for working with Kubernetes, we don’t often create them directly. A more common way to create a pod is to define and create a deployment. Let’s create a deployment that will start up an Nginx container. The best way to build things with Kubernetes is to use the declarative YAML approach. For our deployment, let’s create a file called
apiVersion: apps/v1 kind: Deployment metadata: name: webserver-deployment labels: app: webserver spec: replicas: 1 selector: matchLabels: app: webserver template: metadata: labels: app: webserver spec: containers: - name: nginx image: "nginx:1.15" ports: - containerPort: 80
There’s quite a bit going on in this file that’s just boilerplate, but the important details are the
spec.template.spec.containers. By specifying the
containers section, we’re effectively creating the pod. The syntax within the
containers section is similar to how you’d define a service in a Docker Compose file.
For creating and updating almost anything in Kubernetes, we can use the
kubectl apply -f command, passing in the file that defines the desired state. Let’s create our deployment doing this:
$ kubectl apply -f webserver-deployment.yml deployment.apps/webserver-deployment created
Now we have a deployment called
webserver-deployment. We can see all of the deployments that we have by using the
kubectl get command, passing in the type of object that we’d like to see. To see deployments, we’ll run this command:
$ kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE webserver-deployment 1/1 1 1 91s
The deployment manages our pod. We can see what pods exist by using
kubectl get pods:
$ kubectl get pods NAME READY STATUS RESTARTS AGE webserver-deployment-5558c6f6f6-v9rq2 1/1 Running 0 4m13s
A beautiful aspect of Kubernetes’ declarative nature is that we can change our
webserver-deployment.yml to require more than one replica of our container and run the same command that we used to originally deploy. Change the
replicas: 1 line to
replicas: 3 within the
Deploying this won’t show a lot of information, but digging deeper, we’ll see that 2 new containers were created:
$ kubectl apply -f webserver-deployment.yml deployment.apps/webserver-deployment configured $ kubectl get pods NAME READY STATUS RESTARTS AGE webserver-deployment-5558c6f6f6-glpm4 1/1 Running 0 4m33s webserver-deployment-5558c6f6f6-pwbdg 1/1 Running 0 41s webserver-deployment-5558c6f6f6-vnnhr 1/1 Running 0 41s
Notice that Kubernetes didn’t bother removing the original pod; it determined the difference between the current state and the desired state and took the minimum number of actions required to achieve that desired state.
Making Our Pod Accessible Using a Service
The last thing that we’re going to do is set up a “service” to expose our web server deployment and pods so that we can access them from our web browser. It is possible to set up a service using the YAML syntax, but we can also use an imperative approach by using the
kubectl expose command. Let’s expose our deployment behind a load-balancing service:
$ kubectl expose deployment webserver-deployment --type=LoadBalancer --port=80 service/webserver-deployment exposed
We want our service to expose port
80 from our deployment’s containers behind a load balancer and this command will achieve just that. Taking a look at our services using
kubectl get, we can see that the service has a type, an internal IP address, and port mappings:
kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1
443/TCP 19h webserver-deployment LoadBalancer 10.105.244.45 80:31133/TCP 2m1s
Since that IP address is internal to the cluster, we can’t actually connect to it. There is no external IP address because we’re running in a VM, so we’ll need to take one Minikube-specific step to figure out how to connect to this service. Run this command to get the URL for our service:
$ minikube service webserver-deployment --url http://192.168.99.101:31133
Your URL will be different, but if you paste that value into your web browser you should be met by the default Nginx index page. This has been a bit of a whirlwind tour, but I hope you’ve enjoyed taking your first steps with Kubernetes.
Learning More About Kubernetes
Minikube is a great tool for just getting started with Kubernetes, but if you want to start using Kubernetes in a production environment, then you likely have a lot to learn. Thankfully, we have some great courses around using container technologies like Docker and Kubernetes that can get you up to speed in no time. I’d encourage you to check these courses:
- Kubernetes Quick Start
- Kubernetes Essentials
- Essential Container Concepts
- Learn Microservices by Doing
- Kubernetes the Hard Way
If you’re looking for the learning path way to reach a particular goal, take a look at these: Learning Docker, Getting Started in Containers for the Absolute Beginner, Getting Started with Kubernetes, or Kubernetes Orchestration and Management
Good luck and happy learning!