kubernetesdeploy-rails-application-kubernetes-helm

Deploy a Rails Application on Kubernetes with Helm

Introduction

The Rails framework is a popular choice with developers who want to create web applications with ease. It is based on the Ruby language and it allows you to write less code with its predefined layout and additional libraries for simplifying the programming of web applications.

Rails is included in Bitnami’s catalog of development containers. Our Rails development container includes a full Rails environment and an SQL database (MariaDB) for creating web applications, so developers only need to focus on coding.

If you have chosen Docker as the platform for building your Rails application image, what could be the next step? Running your application in a production environment. Kubernetes is the best way for running application deployments across clusters of hosts. This solution allows you to automate the deployment, the scaling and management of application containers.

To more easily deploy and manage the application containers in a Kubernetes cluster, you can use Helm charts. In the same way that a Dockerfile contains instructions on how to build images in running containers, the charts define how the application will be deployed in Kubernetes. They specify the objects definitions, services, dependencies, number of pods, and so on.

This guide walks you through the process of running an example Rails application on a Kubernetes cluster. It uses a simple “Hello World!” Rails application based on the latest Bitnami Rails image. The next step is to create a Dockerfile and use it as a starting point for creating a custom Helm chart to automate the application deployment in a Kubernetes cluster. Once the application is deployed and working, this guide also explores how to modify the source code for publishing a new application release and how to perform rolling updates in Kubernetes using the Helm CLI.

Assumptions and prerequisites

This guide will show you how to deploy an example Rails application in a Kubernetes cluster running on Minikube. The example application is a typical “Hello World!” application.

This guide makes the following assumptions:

To create your own application in Rails and deploy it in a Kubernetes cluster using Helm you will typically follow these steps:

  • Step 1: Create the example application
  • Step 2: Create a Dockerfile
  • Step 3: Build the Docker image
  • Step 4: Publish the Docker image
  • Step 5: Create the Helm Chart
  • Step 6: Deploy the example application in Kubernetes
  • Step 7: Update the source code
  • Step 8: Rollout updates (and rollbacks)

Step 1: Create the example application

To get started, you need to have a Rails application. To do this, create a Rails project to obtain a boilerplate which provides all the needed resources you need to build a simple web application. Follow the steps below to create and configure the example application:

  • Run a Docker container using the latest Bitnami Rails image by executing the docker run command, as shown below:

    $ docker run --rm -v $(pwd):/app bitnami/rails:latest rails new my_app --database mysql
    

    This command generates a new container (that will be removed after the container is stopped thanks to the --rm option) using the Bitnami Rails Docker image. It mounts the current directory (retrieved by $(pwd)) as a volume inside the /app directory in the container. Then, it generates a new Rails application using the rails command.

  • Edit the my_app/config/database.yml file to specify the database configuration that will be used during the Helm chart creation. Change the default values as follows:

    default: &default
        adapter: mysql2
        encoding: utf8
        pool: 5
        username: root
        password: 
        host: 
    

    NOTE: This guide is for development environments. If you are working on a production environment, you need to remove the username, host and password values from the production configuration as follows:

    production:
      <<: *default
      database: my_app_production
    

Step 2: Create a Dockerfile

A Dockerfile is a text file that contains instructions on how to build a Docker image. Each line indicates a command or instruction for assembling all the pieces that comprise the image.

In the same directory where you ran the container, create a file named Dockerfile with the following content:

# This Dockerfile uses the latest version of the Bitnami Rails Docker image
FROM bitnami/rails:latest

# Copy app's source code to the /app directory
COPY my_app /app

# The following operations need to be executed as root
USER root

# We install the javascript environment needed by rails
RUN install_packages nodejs

# Actions will be performed by the user 'bitnami', so it's good practice
# to explicitly set the required permissions
RUN chown -R bitnami:bitnami /app /home/bitnami

# Change the effective UID from 'root' to 'bitnami'
# Never run application code as 'root'!
USER bitnami

# The application's directory will be the working directory
WORKDIR /app

# Install the application dependencies defined in the Gemfile
RUN bundle install

Step 3: Build the Docker image

Once you’ve created the Dockerfile, you can build the Docker image. Follow the instructions below to build the Docker image:

  • Run the docker run command in the same directory where the Dockerfile is. Add a tag to identify the current version of the application: 0.1.0. Remember to replace the USERNAME placeholder with your Docker ID.

    $ docker build -t USERNAME/my-rails-app:0.1.0 .
    

    You will see output like this during the build process:

    Build a Docker image

  • Check that the image has been created in your local repository by executing the command below:

    $ docker images | grep my-rails-app
    

    Check Docker image

Step 4: Publish the Docker image

Now that your Docker image is built and contains your application code, you can upload it into a public registry. This tutorial uses Docker Hub, but you can select one of your own choice such as:

To upload the image to Docker Hub, follow the steps below:

  • Log in to Docker Hub:

    $ docker login
    
  • Push the image to your Docker Hub account. Replace the DOCKER_USERNAME placeholder with your Docker ID:

    $ docker push USERNAME/my-rails-app:0.1.0
    

    You will see output like this during the publication process:

    Push Docker image to Docker Hub

  • Navigate to your Docker account. You should see the new repository in the repository list :

    Check Docker Hub repositories

Step 5: Create the Helm Chart

It is very easy to get started with Helm charts by using the helm create command. It creates a scaffold with sample files that you can modify to build your custom chart. The following instructions will take you through the process of creating a new chart and customizing it to include your Rails sample application.

  • In the same directory you are working in, execute the helm create command to create a new chart named my-rails-app:

    $ helm create my-rails-app
    
  • Change to my-rails-app directory:

    $ cd my-rails-app
    
  • Helm will have created a directory with the file structure shown below:

    my-rails-app
    |-- Chart.yaml
    |-- charts
    |-- templates
    |   |-- NOTES.txt
    |   |-- _helpers.tpl
    |   |-- deployment.yaml
    |   |-- ingress.yaml
    |   `-- service.yaml
    `-- values.yaml
    
  • Edit the values.yaml file and replace the existing values with the following:

    # Default values for my-rails-app.
    # This is a YAML-formatted file.
    # Declare variables to be passed into your templates.
    replicaCount: 1
    image:
    repository: USERNAME/my-rails-app
    tag: 0.1.0
    pullPolicy: IfNotPresent
    service:
    name: http
    type: NodePort
    externalPort: 80
    internalPort: 3000
    resources:
    limits:
        cpu: 100m
        memory: 128Mi
    requests:
        cpu: 100m
        memory: 128Mi
    
  • Edit the templates/deployment.yaml file to add the database environment variables as shown below:

    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
    name: {{ template "fullname" . }}
    labels:
        chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
    spec:
    replicas: {{ .Values.replicaCount }}
    template:
        metadata:
        labels:
            app: {{ template "fullname" . }}
        spec:
        containers:
        - name: {{ .Chart.Name }}
            image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
            imagePullPolicy: {{ .Values.image.pullPolicy }}
            ports:
            - containerPort: {{ .Values.service.internalPort }}
            env:
            - name: MARIADB_HOST
            value: {{ template "mariadb.fullname" . }}
            - name: SKIP_DB_WAIT
            value: "1"
            - name: MARIADB_PASSWORD
            valueFrom:
                secretKeyRef:
                name: {{ template "mariadb.fullname" . }}
                key: mariadb-root-password
            resources: {{ toYaml .Values.resources | indent 12 }}
            livenessProbe:
            httpGet:
                path: /
                port: {{ .Values.service.internalPort }}
            initialDelaySeconds: 180 # We need to wait for the database initialization
            timeoutSeconds: 5
            readinessProbe:
            httpGet:
                path: /
                port: {{ .Values.service.internalPort }}
            initialDelaySeconds: 60
            timeoutSeconds: 5
    

    NOTE: This guide is for development environments. If you are working on a production environment, you need to set the Rails environment variables as follows. These changes apply to all the environment variables present in the templates/deployment.yaml file.

    - name: RAILS_ENV
       value: "production"
    
  • Edit the templates/_helpers.tpl file and append these lines at the end of the file:

    {{/*
    Create a default fully qualified app name.
    We truncate at  63 | trimSuffix "-" chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
    */}}
    {{- define "mariadb.fullname" -}}
    {{- printf "%s-%s" .Release.Name "mariadb" | trunc  63 | trimSuffix "-" -}}
    {{- end -}}
    

    Your file should look like this:

    {{/* vim: set filetype=mustache: */}}
    {{/*
    Expand the name of the chart.
    */}}
    {{- define "name" -}}
    {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
    {{- end -}}
    
    {{/*
    Create a default fully qualified app name.
    We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
    */}}
    {{- define "fullname" -}}
    {{- $name := default .Chart.Name .Values.nameOverride -}}
    {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
    {{- end -}}
    {{/*
    Create a default fully qualified app name.
    We truncate at  63 | trimSuffix "-" chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
    */}}
    {{- define "mariadb.fullname" -}}
    {{- printf "%s-%s" .Release.Name "mariadb" | trunc  63 | trimSuffix "-" -}}
    {{- end -}}
    
  • In the my-rails-app/ parent folder, create a new file named requirements.yaml that includes the following content:

    dependencies:
    - name: mariadb
    version: 0.6.0
    repository: https://kubernetes-charts.storage.googleapis.com/
    
  • Install missing dependencies with helm dep. The Helm chart used in this guide includes MariaDB dependencies specified in the recently-created requirements.yaml file. So you need to download and install them before deploying the application. Execute the commands below to finish creating the chart:

    $ helm dep list
    $ helm dep update .
    

Install database dependencies

  • Test that the syntax of the files is correct by running the helm lint command:

    $ helm lint .
    

    If the lint process has been successful, you should see the following:

    Validate the chart

TIP: For detailed information about what Helm charts are and how to create a custom chart, take a look at the Helm chart tutorial.

Step 6: Deploy the example application in Kubernetes

At this point, you have built a Docker image, published it in a container registry and created your custom Helm chart. It’s now time to deploy the example Rails application within a Kubernetes cluster.

NOTE: Before performing the following steps, make sure you have a Kubernetes cluster running with Helm and Tiller installed. For detailed instructions, refer to our starter tutorial.

To deploy the example application using the current Helm chart, follow these steps:

  • First, make sure that you are able to connect to your Kubernetes cluster by executing the command below:

    $ kubectl cluster-info
    
  • Deploy the Helm chart with the helm install command. Both chart name and database password have been specified by adding the --name and --set options respectively. This will create two pods within the cluster, one for the Rails service and the other for the MariaDB service. DB-PASSWORD is a placeholder, replace it with the password of the root user used during the database creation.

    NOTE: In this example, the chart name is specified by adding the --name option. If you don’t add it, one will be assigned automatically.

    $ helm install --set mariadb.mariadbRootPassword=DB-PASSWORD --name my-rails-app .
    

Once the chart has been installed, you will see a lot of useful information about the deployment. The application won’t be available until database configuration is complete. Follow these instructions to check the database:

  • Run the kubectl get pods command to get a list of running pods:

    $ kubectl get pods
    

    Check pods

  • Check the logs of the application pod. APP-POD-NAME is a placeholder; remember to replace it with the right value.

    $ kubectl logs -f APP-POD-NAME
    

    Check pods logs

Once you’ve configured the database, you can access the application. To get the application URL, run the commands shown in the “Notes” section included in the information displayed when you executed the helm install command:

Application URL

If you are using Minikube, you can also check the application service to get the application’s URL:

$ minikube service my-rails-app --url
  • Enter the resulting URL in your default browser to access the application.

Rails application running on Kubernetes

Congratulations! Your Rails application has been successfully deployed on Kubernetes.

Step 7: Update the source code

As a developer, you’ll understand that your application may need new features or bug fixes in the future. To release a new Docker image, you only have to perform a few basic steps: change your application source code, rebuild and republish the image in your selected container registry. Follow these instructions to complete the source code update.

  • In the my_app/public directory, create a file named my_page.html. Add this welcome message to the file:

    Hello world
    

Save the file.

  • Change to the directory where the Dockerfile is and rebuild the image by running the docker build command. Add a tag to identify the current version of the application: 0.1.1. Replace the USERNAME placeholder with your Docker ID.

    $ docker build -t USERNAME/my-rails-app:0.1.1  .
    

    You will see output like this during the build process:

    Build a new Docker image

  • Check that the new image has been created in your local repository:

    $ docker images | grep my-rails-app
    

    Check new image

    NOTE: Before performing the next step, make sure that you are logged in Docker Hub. Run the docker login command to access your account (if applicable).

  • Push the image to your Docker Hub account. Replace the USERNAME placeholder with your Docker ID:

    $ docker push USERNAME/my-rails-app:0.1.1
    
  • Navigate to your Docker account. Select the USERNAME/my-rails-app repository to show the content. Find the application releases in the tag list:

    Application releases list

Step 8: Roll out updates (and rollbacks)

Rolling updates allow you to run the latest image of your application in a Kubernetes cluster. Any change that you have made will be reflected in your charts by executing the helm upgrade command. Rollbacks also have the advantage of allowing developers to go back to the previous version of their application in any moment. As with updates, you can perform a rollback just by running the helm rollback command. Here’s how to upgrade or rollback the deployment using the Helm CLI.

Update the Helm chart

To deploy a new application release in a Kubernetes cluster, follow the steps below:

  • Change to the my-rails-app directory, where you have the Helm chart files. Edit the values.yaml file to replace the current image tag with the new one:

Edit values.yaml

  • Run the helm upgrade command followed by the name of the chart. After that, you will see the information about the new deployment:

    $ helm upgrade my-rails-app .
    

Upgrade a Helm chart

  • See what revisions have been made to the chart by executing the helm history command:

    $ helm history my-rails-app
    

Helm history

  • Enter the application URL you found in step 6, followed by /my_page.html. You should see the welcome message for the new application release:

Hello world

Rollback the Helm chart

If you want to go back to a previous version of your Helm chart:

  • Bring up a list of the chart’s revisions by executing the helm history command:

    $ helm history my-rails-app
    

    Helm history

  • Execute the helm rollback command including the name of the chart and the revision number you want to go back to:

    $ helm rollback my-rails-app 1
    

    Rollback a Helm chart

  • Enter the application URL you were given in step 6, and you should see the default Rails welcome page again:

    Rails default welcome page

To learn more about the topics discussed in this guide, use the links below: