In my previous post, I wrote a go application that displays the GPS location of any IP address. Here in this post, I’ll explain how to deploy the same in minikube.
- Desired Deployment State
- Step 1: start minikube
- Step 2: create secrets
- Step 3: create a redis cluster
- Step 4: create configmap
- Step 5: create deployment and service
- Step 6: check your cluster
- Step 7: expose service
- Next steps
- understanding of kubernetes components (pods, deployment, etc.)
- minikube installed in your laptop
If you are new to kubernetes and want to learn, I recommend this youtube playlist.
Minikube is a tool that makes it easy to run Kubernetes locally. Minikube runs a single-node Kubernetes cluster inside a Virtual Machine (VM) on your laptop for users looking to try out Kubernetes or develop with it day-to-day.
if you don’t have minikube installed in your laptop, you can do it by following the instructions here.
Desired Deployment State
- 2 instances of our web application.
- a load balancer that balances the load on our two web application instances.
- a redis cluster with a master-slave replication.
|desired deployment state|
I’m going to list down 7 steps I did to get to the above shown desired state. I hope you can replicate what I did very easily in your own minikube environment.
Step 1: start minikube
you should receive an output like this
MacBook-Pro-2:Desktop jeshocarmel$ minikube start 😄 minikube v1.12.3 on Darwin 10.14.3 ✨ Using the hyperkit driver based on existing profile 👍 Starting control plane node minikube in cluster minikube 🏃 Updating the running hyperkit "minikube" VM ... 🐳 Preparing Kubernetes v1.18.3 on Docker 19.03.12 ... 🔎 Verifying Kubernetes components... 🌟 Enabled addons: default-storageclass, storage-provisioner 🏄 Done! kubectl is now configured to use "minikube"
To ensure minikube has started successfully, run the command below
and you should receive an output like this.
MacBook-Pro-2:Desktop jeshocarmel$ minikube status minikube type: Control Plane host: Running kubelet: Running apiserver: Running kubeconfig: Configured
Before we proceed further, clone the repo (if you don’t have it already) and navigate to the project folder in command line / terminal.
Step 2: create secrets
A Secret is an object that contains a small amount of sensitive data such as a password, a token, or a key. To use a secret, a Pod needs to reference the secret.
We need two secrets for our application setup.
- The apikey for ipstack.com
- A password for our redis cluster.
The password will be used by the redis-cluster when it is setup and it will also be needed in the web app to authenticate with the redis host
First, use a base64 encoding tool to convert your apikey and the intended redis password for your redis cluster to a base64 representation. Here’s an example using the commonly available base64 program:
echo -n 'hello world' | base64
Do the base64 encoding for your apikey and your intended password.
echo -n '2c8dceb807df3f5de79cec85d7255998' | base64 # api key from ipstack.com echo -n 'sOmE_sEcUrE_pAsS' | base64 # redis password
Create a app-secret.yaml file as below.
Replace the value for
redis-password with the your base64 encoded values.
Run the command below to create the secrets in your kubernetes cluster.
kubectl apply -f app-secret.yaml
You should get an output like this.
MacBook-Pro-2:app jeshocarmel$ kubectl apply -f app-secret.yaml secret/app-secret created
Step 3: create a redis cluster
To create my redis cluster, I used Helm. Helm is a tool that streamlines installing and managing Kubernetes applications. Think of it like Apt/Yum/Homebrew for K8S. To know more about Helm and Helm charts, I recommend this video.
Run the below command to add the bitnami chart to your helm repo.
helm repo add bitnami https://charts.bitnami.com/bitnami
Create a redis cluster with a single command using helm
helm install my-release bitnami/redis --values minikube_files/values-minikube.yml
The above command creates a redis cluster named ‘my-release’ with configuration parameters mentioned in the file values-minikube.yml.
Run the below command to verify redis-cluster has started successfully.
kubectl get all
You should get an output as below.
MacBook-Pro-2:app jeshocarmel$ kubectl get all NAME READY STATUS RESTARTS AGE pod/my-release-redis-master-0 2/2 Running 0 2m6s pod/my-release-redis-slave-0 2/2 Running 0 2m6s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3m12s service/my-release-redis-headless ClusterIP None <none> 6379/TCP 2m6s service/my-release-redis-master ClusterIP 10.100.3.103 <none> 6379/TCP 2m6s service/my-release-redis-metrics ClusterIP 10.103.110.30 <none> 9121/TCP 2m6s service/my-release-redis-slave ClusterIP 10.97.70.41 <none> 6379/TCP 2m6s NAME READY AGE statefulset.apps/my-release-redis-master 1/1 2m6s statefulset.apps/my-release-redis-slave 1/1 2m6s
Kindly wait for a while if Pods are shown as ‘ContainerCreating’
Any pod in the kubernetes cluster can connect to the redis cluster we just created by mentioning the service ‘service/my-release-redis-master’
configuration file explained
The recommended production configuration file by bitnami is available here. I’ve customized this file to accommodate the redis cluster on minikube. The changes that I made are listed here with comments.
slaveCount: 1 # downgraded slaveCount from '3' to '1' networkPolicy: enabled: false # change networkPolicy enabled to 'false' from 'true'. This enables the app to discover the cluster easily. allowExternal: true # changed networkPolicy allowExternal from 'false' to 'true'. password: existingSecret: app-secret # mentioned app-secret to retrieve the redis-password we had initially created in step 2 existingSecretPasswordKey: redis-password # mentioned the key which hold the base64 encoded hash of the password. persistence: enabled: false # changed persistence enabled to false. minikube doesn't support persistence for redis.
Step 4: create configmap
A ConfigMap is an API object used to store non-confidential data in key-value pairs. Pods can consume ConfigMaps as environment variables.
We need a configmap now to mention our redis host to the pods that are going to deploy the app.
Run the below command to create the configmap.
kubectl apply -f app-configmap.yaml
You should get an output like this.
MacBook-Pro-2:app jeshocarmel$ kubectl apply -f app-configmap.yaml configmap/app-configmap created
Step 5: create deployment and service
Now, create a file
app-deployment.yaml and copy the contents from below. The comments on each line mention their intent.
Run the below command to create the deployment and service.
kubectl apply -f app-deployment.yaml
You should get an output like this
MacBook-Pro-2:app jeshocarmel$ kubectl apply -f app-deployment.yaml deployment.apps/go-app created service/go-app-service created
This step has created a deployment with 2 pods that run the app and a service on top of it to redirect incoming requests to the 2 pods.
Step 6: check your cluster
Check your cluster by running
kubectl get all. I’ve copied my output here for your reference.
MacBook-Pro-2:app jeshocarmel$ kubectl get all NAME READY STATUS RESTARTS AGE pod/go-app-75d844c66b-ds8h9 1/1 Running 0 5m24s pod/go-app-75d844c66b-z2279 1/1 Running 0 5m24s pod/my-release-redis-master-0 2/2 Running 0 6m58s pod/my-release-redis-slave-0 2/2 Running 0 6m58s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/go-app-service NodePort 10.109.157.15 <none> 80:30000/TCP 5m24s service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7m49s service/my-release-redis-headless ClusterIP None <none> 6379/TCP 6m58s service/my-release-redis-master ClusterIP 10.98.39.117 <none> 6379/TCP 6m58s service/my-release-redis-metrics ClusterIP 10.102.102.65 <none> 9121/TCP 6m58s service/my-release-redis-slave ClusterIP 10.109.163.218 <none> 6379/TCP 6m58s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/go-app 2/2 2 2 5m24s NAME DESIRED CURRENT READY AGE replicaset.apps/go-app-75d844c66b 2 2 2 5m24s NAME READY AGE statefulset.apps/my-release-redis-master 1/1 6m58s statefulset.apps/my-release-redis-slave 1/1 6m58s
Kindly wait for a while until the pods are shown as ‘running’
Step 7: expose service
The service we created in step 5 is a NodePort service. A NodePort service is the most primitive way to get external traffic directly to your service. If you are interested to learn more about different services available in kubernetes, I recommend this article.
It’s time now to expose our service. Run the below command.
minikube service go-app-service
I’ve copied my output below. You can observe that the port 30000 is the same port we mentioned for NodePort in step 5.
MacBook-Pro-2:app jeshocarmel$ minikube service go-app-service |-----------|----------------|-------------|----------------------------| | NAMESPACE | NAME | TARGET PORT | URL | |-----------|----------------|-------------|----------------------------| | default | go-app-service | http/80 | http://192.168.64.23:30000 | |-----------|----------------|-------------|----------------------------| 🎉 Opening service default/go-app-service in default browser...
Copy the URL and paste in your browser. You should be able to see the app now.
|app loaded on my browser|
|illustration of how a NodePort works (reference)|
To summarize, this article demonstrates how to create the following in a minikube kubernetes cluster.
- a redis cluster using helm
- an app deployment
- a service that exposes the app
As an icing on the top, lets see how to scale our app deployment to 5 replicas.
kubectl scale --replicas 5 deployment/go-app
MacBook-Pro-2:app jeshocarmel$ kubectl scale --replicas 5 deployment/go-app deployment.apps/go-app scaled
Checking pods after scaling.
MacBook-Pro-2:app jeshocarmel$ kubectl get pods NAME READY STATUS RESTARTS AGE go-app-69754f67b8-9w7s8 1/1 Running 0 66s go-app-69754f67b8-b892x 1/1 Running 0 66s go-app-69754f67b8-hqv2q 1/1 Running 0 42m go-app-69754f67b8-lrm2r 1/1 Running 0 66s go-app-69754f67b8-w8xb6 1/1 Running 0 42m my-release-redis-master-0 2/2 Running 0 78m my-release-redis-slave-0 2/2 Running 0 78m
The app has been scaled from 2 replicas to 5 replicase in a single command. That’s as simple as it gets. Thanks for your time. Hope you learnt something.
In the next post, I’ll write on how to deploy this application in a cloud environment with Linode Kubernetes Engine (LKE). See ya.