Hello Rok: Part 2, Rails on Kubernetes

This is a very simple Hello World guide for getting your Rails application running on Kubernetes.

In Part 1 we covered how to get Rails running on Docker. In Part 2, we are going to learn how to run Rails on K8s in our local machine. In Part 3, we are going to deploy our Kubernetes setup to the cloud.

Every step consists of a title, an explanation (in italic) and instructions. If you want the fastest setup possible, skip the explanations for now.

Code

If you want to skip this guide feel free to navigate through the code here. All running steps are pushed to Github. For Part 1, take a look at branch part_1.


1- Install a Hypervisor, kubectl, and Minikube.

All these pieces are necessary to get Kubernetes installed.

Hypervisor is an app that lets you run virtual machines. My favorite solution is VirtualBox.

Kubectl is a CLI for running commands against Kubernetes clusters.

Minikube is a tool made for running a single-node Kubernetes cluster inside a VM on your local machine.

For easy installation steps, follow instructions here.

2- Identify Components

As we learned in Part 1 of this guide, we used the docker-compose.yml file to define all of our application services/components. That was our first approach to orchestration. Having that, we don’t need to do the job of identifying the components again, we can go directly into translating our services into Kubernetes controllers.

Before defining those, let’s proceed to mount our already generated images into Docker containers inside our K8s cluster. You can also choose another container platform, but Docker is the most widely used.

If you completed this step in Part 1 of the tutorial, you can skip this step.

3- Run Docker container within Minikube

Because this tutorial uses Minikube, instead of pushing your Docker image to a registry (you can also so that), you can simply build the image using the same Docker host as the Minikube VM, so that the images are automatically present. To do so, make sure you are using the Minikube Docker daemon:

eval $(minikube docker-env)

Build your Docker image, using the Minikube Docker daemon (mind the trailing dot):

docker build -t iufuenza/hello-rok:v1 .

Or if you want, build the image with Docker Compose CLI:

docker-compose build app

4- Create and Run Kubernetes resources.

To get a better picture of K8s, there are many concepts you will have to learn. At the bottom of this guide, you will find a picture with a basic explanation of the key concepts that you will need to learn to the extent of having a better understanding of K8s. For now, we are going to assume you already did your research and will proceed with instructions on how to get our app running in K8s.

First, we have to start minikube:

minikube start --vm-driver=xhyve

a) Postgres DB service

Our DB service will need few controllers. We will need to create secrets for storing secure credentials. Then, we will use a Deployment alongside a ReplicaSet for running it. With that, we will define a service for exposing it to the internet, or in our case to our localhost. Finally, we will also need to create a persistent volume, to add the ability of saving data in a persistent storage so that it doesn’t disappear when a container is destroyed or moved.

First, we generate secrets:

kubectl create secret generic db-user-pass --from-literal=password=mypass
kubectl create secret generic db-user --from-literal=username=postgres

Now, we create the Deployment:

kubectl run db --image=postgres --port=5432 --env="PGUSER=postgres" --env="PGPASS=mypass" --env="PGDB=hellorok-db" --env="PGDATA=/var/lib/postgresql/data"

Alternatively, we can create YAML files, and generate our K8s pieces invoking kubectl create. For this tutorial, I added all the file that we need under a directory named “kube”. You can find them on Github. So, we can also generate our deployment as follows:

kubectl create -f kube/deployments/db.yaml

You should now be able to see your deployment:

kubectl get deployments

We can also list our newly generated ReplicaSet with:

kubectl get rs

And to list the all the Pods, and look at the one associated with our Deployment, we run:

kubectl get pods

If everything went well, the state of your Pod should be Running, and the number of restarts should be 0. In that scenario, we can assure our deployment is online. So the next step will be to expose it as a service:

kubectl expose deployment db

We can now take a look at our new service:

kubectl get services

b) Rails Application service

Our basic app will need few controllers. It will have the same configuration as the DB service, except that we won’t define a persistent storage. We will create a deployment and then a service associated with it.

Now, we can run the following command to create a deployment controller for our running container. It will also create a ReplicaSet and a Pod associated with it.

kubectl run hellorok --image=iufuenza/hello-rok:v1 --port=3000 --env="DATABASE_URL=postgres" --env="DATABASE_NAME=hellorok-db" --env="DATABASE_PORT=5432" --env="DATABASE_USER=postgres" --env="DATABASE_PASSWORD=mypass" --command -- rails s -p 3000 -b 0.0.0.0

Alternatively, we can create YAML files, and generate our K8s pieces invoking kubectl create. As previously mentioned, you can find it on GitHub under the ‘kube’ folder. So, we can generate our deployment as follows:

kubectl create -f kube/deployments/rails.yaml

Follow 4.a) to know how to list your newly created Deployment, ReplicaSet, and Pod.

Now that we have our Rails App running, we have to initialize our database. For that, we have to run the migrations inside the container, which is now running in a Pod. You will need the POD_NAME, which you can get from kubectl get pods. Having that, we run:

kubectl exec -it POD_NAME rails db:migrate

Next step will be to expose it as a service:

kubectl expose deployment hellorok --type=NodePort

5- Open your running application in your browser

At this point, you should have your Rails application with all its related services up and running inside a local Kubernetes cluster. Minikube will use a local IP on your local machine, and Kubernetes will map an internal port to the port you defined for your Rails application.

To see your application running on the browser, hit:

minikube service hellorok

Other resources