Optimized Development and Deployment Workflow

For Ruby on Rails on Kubernetes

Rails is a powerful framework that comes with batteries loaded. One thing that is not available out of the box is a simple way of deploying Rails projects to Kubernetes and a time-saving method for iteratively developing Rails projects on top of Kubernetes.

In this tutorial, we are taking DevOps to the next level by showing how developers can build Rails applications using Kubernetes. This tutorial is great for Kubernetes beginners but also for advanced users that want to streamline their development and deployment workflow for Rails on Kubernetes.

This tutorial works with any Kubernetes cluster (minikube, Docker Kubernetes, GKE, EKS, AKS etc.) but if you don’t have a cluster at hand, you can still do the tutorial with one of the free and fully managed Kubernetes namespaces sponsored by DevSpace.

1. Create Rails Project

Obviously, you can skip this step if you already have a Rails project that you want to use for the purpose of this tutorial.

Before creating a Rails project, let’s define a variable with the directory that we want our Rails project to be located in:

PROJECT_DIR=/c/Users/[username]/rails-project # for win (git-bash)

PROJECT_DIR=/home/[username]/rails-project # for mac, linux (bash)

If you are using Docker Toolbox , your $PROJECT_DIR needs to be inside your user's home directory, e.g. /c/Users/[username] . If you are using the newer Docker Desktop on Windows, make sure the drive that your project should be on is marked as Shared Drive in the Docker settings.

Now, let’s also create a variable for the name of our Rails project:

PROJECT_NAME=app

If you don’t have a Rails app at hand, this code snippet is a great way to leverage Docker for creating a Rails project super quickly:

mkdir $PROJECT_DIR docker run --rm -v /$PROJECT_DIR:/app -w //app ruby:2.6-alpine sh -c "apk add build-base nodejs yarn tzdata sqlite-dev postgresql-client postgresql-dev && gem install pg rails && rails new $PROJECT_NAME --database=postgresql" cd $PROJECT_DIR/$PROJECT_NAME

This command may take quite some time but if you are familiar with Ruby on Rails, you probably already know that.

As you can see in the code snippet, we are using the --database=postgresql because we want to add a PostgreSQL database later on (of course you can skip this if that's not what you need).

2. Containerize Project

So, let’s containerize our Rails project. To do this in a quick and easy way, we are using DevSpace, an open-source dev tool for Kubernetes. DevSpace is a client-only CLI tool for containerizing projects and it is the fastest tool for interactively deploying applications to Kubernetes.

There is no Ruby gem for DevSpace but you can easily install DevSpace via npm:

npm install -g devspace

For more install options, take a look at the GitHub repo.

After installing DevSpace, containerizing a project is pretty straight forward. Just run this command:

devspace init

When DevSpace asks you which port the application is listening on, type in 3000 and hit Enter . The remaining questions should be easy to answer. You can always hit Enter to just select the default option if you are unsure.

After the init process is done, you’re ready to deploy the project to Kubernetes. However, if you need a database, it is smart to add it before deploying the project.

Bonus: Add Postgres Database

Open the file devspace.yaml (which was created by devspace init ) and change the deployments section from:

deployments:

- name: app

helm:

componentChart: true

values:

containers:

- image: dscr.io/${DEVSPACE_USERNAME}/app

service:

ports:

- port: 3000

to:



- name: database

helm:

chart:

name: stable/postgresql

values:

postgresqlDatabase: "db_app"

postgresqlUsername: "db_user"

postgresqlPassword: ${DB_PASSWORD}

- name: app

helm:

componentChart: true

values:

containers:

- image: dscr.io/${DEVSPACE_USERNAME}/app

env:

- name: DATABASE_URL

value: "postgres://db_user:${DB_PASSWORD}

service:

ports:

- port: 3000 deployments:- name: databasehelm:chart:name: stable/postgresqlvalues:postgresqlDatabase: "db_app"postgresqlUsername: "db_user"postgresqlPassword: ${DB_PASSWORD}- name: apphelm:componentChart: truevalues:containers:- image: dscr.io/${DEVSPACE_USERNAME}/appenv:- name: DATABASE_URLvalue: "postgres://db_user:${DB_PASSWORD} @database -postgresql/db_app"service:ports:- port: 3000

Done! That’s it, now you can deploy this Ruby project and will immediately have a PostgreSQL database ready to be used by the application.

3. Choose Kubernetes Cluster

If you don’t have a Kubernetes cluster or want to use a Heroku-like service for hosted Kubernetes namespace, run the following command to get a free namespace in DevSpace Cloud:

devspace create space ruby-app

You can think of DevSpace Cloud as a kind of Heroku for Kubernetes but without limitations regarding tech stack, portability, and scalability. So, you can deploy any container and you can easily move your application to another Kubernetes cluster with just a single command.

DevSpace will automatically add the kube-context for the space you are creating in DevSpace Cloud, so that you can also use tools like kubectl, helm and others.

If you already have a Kubernetes cluster, it is even easier: Just tell DevSpace which namespace to use (will be created during deployment if not existing):

devspace use namespace [my-namespace]

4. Develop Project

Before we deploy this Rails project, we need to establish a workflow for developing the project as efficiently as possible. DevSpace provides a command for this workflow:

devspace dev

The first time you run this command, DevSpace will ask you to define a database password that is used for the variable DB_PASSWORD .

Running this for the first time may take a while but will be much quicker the second time.

This command essentially builds the Docker image from the Dockerfile, tags it and pushes it to a registry. Then, DevSpace deploys the project according to the deployments section of the devspace.yaml and starts the development services (port-forwarding for localhost access, log streaming and file sync for hot reloading).

If everything is up and running as expected, you should be able to see the Rails logs in the terminal and the browser will open showing the famous Rails welcome page on localhost:3000 .

Ruby on Rails Welcome Page — Every Rails developer’s favorite page to see.

Generate Index Route

Now that the project is running inside the Kubernetes cluster, we can start developing the actual business logic. Of course, you can also run the usual rails commands locally, but in this tutorial, I will show you how to run these commands directly inside the running container.

Make sure devspace dev is still running before continuing with this part of the tutorial. Just leave it running or start it again and open a second terminal to run the following commands.

To generate a controller for a “Hello World” index page, run the following command:

devspace enter -- rails generate controller Welcome index

As you can see we are executing a regular rails command. By adding the prefix devspace enter -- , we tell DevSpace to run this rails command inside a container within Kubernetes instead of executing it on the local machine. You could also run any other rails , rake , npm or bundle command within the container by just adding devspace enter -- before the command.

Then, as usual change the config/routes.rb on your local filesystem from:



# For details on the DSL available within this file, see

end Rails.application.routes.draw do# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html end

to:



get 'welcome/index'

root 'welcome#index'

# For details on the DSL available within this file, see

end Rails.application.routes.draw doget 'welcome/index'root 'welcome#index'# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html end

DevSpace makes sure that any file changes on the remote system will be reflected on the local filesystem and vice versa. That is the fastest way to iteratively build Kubernetes-based applications.

You can see how quick this is if you just edit a single file. Go ahead and try it:

Replace “Welcome#index” with “Hello World!” inside the file app/views/welcome/index.html.erb Reload the browser to see the changes and also take a look at the logs of the devspace dev command which are streamed in real-time from the container inside the Kubernetes cluster.

Extra: Add Posts

We wouldn’t need a database if we didn’t have any data to persist. So, for the purpose of this tutorial, let’s generate a Rails scaffold for blog posts:

devspace enter -- rails generate scaffold Post title:string body:text

After creating the scaffold, we need to invoke rake for a database migration:

devspace enter -- rake db:migrate

That’s it! Everything is already live:

Go to this URL: http://localhost:3000/posts Add posts and see how they are persisted to the database. Observe the logs streamed via devspace dev while you add new posts.

5. Deploy Project

If you reached this part of the tutorial, you got the hang of the development flow. Now, it’s time to deploy the application for good. In most cases, you may want to create another space using devspace create space myapp-prod or run devspace use namespace [prod-namespace] to separate dev and production. You can always switch back to the development workspace using the devspace use space/namespace command.

Once you’re in the right kube-context and namespace, you can deploy your project with the following command:

devspace deploy

Before you can access the deployed Rails project, you need to wait until the database migrations run through and the app starts listening. You can check the status of this process by streaming the logs of the app container using this command:

devspace logs -f

After you see the following log line:

* Listening on tcp://0.0.0.0:3000

you can access your deployed Rails app with this command:

devspace open

DevSpace can either start a private port-forwarding session for you (for localhost access similar to devspace dev ) or it can create a Kubernetes ingress for you to make your project publicly available on a domain.

What’s next?

There is so much more to show in terms of better productivity for Kubernetes and Rails. That’s why I see this post as the start of a blog series. If you are interested in the next article (most likely about getting Rails apps production-ready and (auto-)scalable on Kubernetes), subscribe and you’ll get a short email as soon as my next article is out (probably in 3–4 weeks).

If this is helpful to you or you have any questions or ideas what might be interesting to blog about next, reach out via twitter @LukasGentele or email: lg AT devspace.cloud

Looking forward to hearing from you!