Minikube on a VPS from scratch
It’s not rocket science to set up a Kubernetes (
k8s) cluster on your local machine with minikube. On the other hand, It’s not straightforward when you want to set up minikube on a remote server. So, in this tutorial, I will share some learning after setting up my personal development environment in a VPS.
Configure access to the remote machine
By default, you will be provided with root credentials to access the machine. I hardly encourage you to perform the following 2 steps (and the 3rd is up to you)
- Add your user account to the Server. Visit the following link if you need some help https://www.cyberciti.biz/faq/add-new-user-account-with-admin-access-on-linux/
- Enable ssh key-based authentication for the user created in the previous step. It’s a properer access mechanism than using a user password. https://www.digitalocean.com/community/tutorials/how-to-configure-ssh-key-based-authentication-on-a-linux-server
- Create a subdomain (or a domain) for your remote machine. It’s always easier to recall a name than an IP with 12 digits. We just need to configure a custom DNS record of type A. See below my own configuration:
- Hostname: k8s.ivancorrales.com
- Type: A
- TTL: 1h
- Data: 173.249.xxx.xxx (The public IP of your server)
Once you have completed the above steps you should be able to login into the remote machine as below:
ssh <user>@subdomain.domain (-i path_to_private_key)
# You don't need to pass the arg -i when using
# the default key (~/.ssh/id_rsa)
# ssh firstname.lastname@example.org -
Install minikube on the remote machine
Follow the installation guide https://minikube.sigs.k8s.io/docs/start/
Let’s create our first cluster as shown below [replace k8s.ivancorrales.com with the name of your own server]
minikube start --memory 8192 --cpus 4 \
We will launch a private docker registry to push our docker images, which will be deployed onto our k8s cluster. That’s the reason why we pass the flag
Let’s install the addon
minikube addons enable registry
We will use the
registry addons to set up our private docker registry that will host the docker images that will be deployed in our k8s cluster.
Once minikube is running we can check the status of our cluster with
type: Control Plane
Install kubectl on both remote machines & local machine
Follow the instructions at https://kubernetes.io/docs/tasks/tools/
To minimize risks and avoid security risks we try to expose a less number of ports to the rest of the world. Therefore, we will use our ssh connection to create a tunnel to communicate with our k8s cluster that is running on the remote machine. From a simplistic point of view, we can sum up that a tunnel allows us to establish the connections that we could do from the remote machine.
If we run minikube with the docker driver (default behavior) we can run the command
docker ps to verify the ports that are exposed from the container.
127.0.0.1:49209->8443/tcp, # API Endpoint
To figure the cluster IP out we just need to run the following:
>> minikube ip
In this tutorial, we will exclusively focus on the port
8443 , the one that is used by the tools to communicate with a k8s cluster via API.
So we need to work out how to communicate with the private IP 192.168.49.2 on port 8443 from our local machine.
The following command creates a tunnel that enables us to access ports 8443 (
k8s API ) through port 18443 in our local machine
ssh -N -p 22 email@example.com \
-L 18443:192.168.49.2:8443 # k8s cluster
If we open https://localhost:18443 on our browser we will see a forbidden error message (Don’t panic, that error makes sense since this communication must be established using the certificates that we will download from the remote server in the following step.
The following image represents how the communication is established from our local machine to the k8s cluster through the tunnel
Set the k8s cluster connection
In our local machine, we need to edit the config file in path ~/.kube/config
- First of all, we need to download the minikube cluster certificates from the remote machines to our local machine. We can use the
scpcommand to copy the certificates from the server to our local machine. [Replace the values with tour our username and server name]
mkdir -p ~/k8s.ivancorrales.com
scp firstname.lastname@example.org:/home/icorrales/.minikube/ca.crt .
scp email@example.com:/home/icorrales/.minikube/profiles/minikube/client.crt .
scp firstname.lastname@example.org:/home/icorrales/.minikube/profiles/minikube/client.key .
- Secondly, we need to add the k8s configuration in the file ~/.kube/config. This file is used to manage different k8s clustered, so you could have already defined others. Let’s see only the
# This file continas 3 blocks: cluster , contexts and user..
# Path to the ca.crt downloaded previously from the server
# Port open in out local machine thorugh the tunnel
# The value of the property cluster must match
# one of the defined users in the above block clusters
# The value of the property user must match
# one of the defined users in the below block users
# Default context
- name: email@example.com
# Path to the client.crt downloaded previously from the server
# Path to the client.key downloaded previously from the server
Assuming that we have defined the value of.
current-context with the new context that we have defined, we can verify that everything is correctly configured using the
kubectl tool that we previously installed on our machine.
>> kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:18443
CoreDNS is running at https://127.0.0.1:18443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
Admin the cluster remotely
Now that we have correctly created the communication we can manage our k8s cluster from our local machine.
For instance, we can create a namespace in our cluster
>> kubectl create namespace demo
>> kubectl delete namespace demo
namespace "demo" deleted
To launch the k8s dashboard we need to run the below command from the remote machine
# From remote machine
and launch a proxy from the local machine
# local machine
kubectl proxy --address='0.0.0.0' --disable-filter=true
Starting to serve on [::]:8001
The address http://localhost:8001/ displays the different endpoints that we navigate to
The dashboard can be accessed by clicking on the link http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/
Publish a docker image
Build a Docker image
At the beginning of this article, we enabled the
Let’s tag any docker image that we want to display in the k8s cluster. Alternatively, you could use the docker
ivancorrales/hello-world:tutorial that launch an HTTP server on port 3030 that displays
hello world! when you access to
We need to tag the image to be hosted in our Docker registry.
docker tag ivancorrales/hello-world:tutorial \
Check the docker registry logs
The docker registry is a docker container that runs in the namespace
kube-system . We can check the logs as shown below
kubectl logs --namespace kube-system service/registry -f
Make the Docker registry accessible from your local machine
Run the following command from the remote machine
kubectl port-forward --namespace kube-system service/registry 5000:80 \
Let’s open the following URL (don’t forget to replace k8s.ivancorrales.com with your own subdomain) http://k8s.ivancorrales.com:5000/v2/_catalog and we can check the response from the registry
Before pushing any docker image we need to add the URL
k8s.ivancorrales.com:5000 as an insecure registry in our docker configuration.
Publish the docker image
We can publish the Docker image that we created previously.
docker push k8s.ivancorrales.com:5000/hello-world:0.0.1
Install our service with Helm
To complete this tutorial we will use Helm to deploy an application.
Install Helm in tour local machine
Follow the instructions here, https://helm.sh/docs/intro/install/
Write your Helm Chart
Learning to write a Helm Chart is out of the scope of this tutorial, so you can clone this repository and replace the values in the variables with the ones that work for you. The Chart is under folder
Install the application
If you decided to clone the repository, from the root directory you just need to run
helm install my-hello-worl-app hello-world --namespace minikube-demo \
and check that the chart was installed correctly.
>> helm list --namespace minikube-demo
>> kubectl logs deployment/myapp-deployment --namespace minikube-demo
> firstname.lastname@example.org start
> node index.js
Listening on port 3030
Check the service
We just need to port-forwarding the deployment port from our local machine
kubectl port-forward deployment/myapp-deployment \
--namespace minikube-demo 3030:3030
So let’s open http://localhost:3030 to check our beautiful