Kubernetes Tutorial: Running a Rails App in Kubernetes

  
kubernetes tutorial running rails in kubernetes

As stated on their website, "Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications." Here we'll take a Rails app, create an image using a Dockerfile, and let Kubernetes manage the containers for us.

We will discuss the following:

  • Secrets
  • Deployments
  • Services
  • Running locally via Minikube

Wanna run Rails in Kubernetes? This Kubernetes tutorial will show you how.


Secrets

We'll start by creating a Kubernetes secret. This secret contains the secret key base and database credentials required by the Rails application. To generate a secret key base, run

$ bundle exec rake secret
8d428e9d27e3323f1b1ec0089482017480224c9984fc10327f95b0990ec46175d43d756fd644c3bca3703a337a94ced69c868ab0470ac201cd1b6a80c3f89e4a


Encode the secret key base using base64.

$ echo -n "8d428e9d27e3323f1b1ec0089482017480224c9984fc10327f95b0990ec46175d43d756fd644c3bca3703a337a94ced69c868ab0470ac201cd1b6a80c3f89e4a" | base64
OGQ0MjhlOWQyN2UzMzIzZjFiMWVjMDA4OTQ4MjAxNzQ4MDIyNGM5OTg0ZmMxMDMyN2Y5NWIwOTkwZWM0NjE3NWQ0M2Q3NTZmZDY0NGMzYmNhMzcwM2EzMzdhOTRjZWQ2OWM4NjhhYjA0NzBhYzIwMWNkMWI2YTgwYzNmODllNGE=

Next, encode the database credentials. Use the format DB_ADAPTER://USER:PASSWORD@HOSTNAME/DB_NAME. If you are using mysql with a user 'deploy' and a password 'secret' on 127.0.0.1 and have a database railsapp, run

$ echo -n "mysql://deploy:secret@127.0.0.1/railsapp"
bXlzcWw6Ly9kZXBsb3k6c2VjcmV0QDEyNy4wLjAuMS90b2Rv


Create a YAML file of the secret and save it anywhere in your local machine. You can use any filename. Here we use railsapp_secrets.yaml.

apiVersion: v1
kind: Secret
metadata:
  name: railsapp-secrets
type: Opaque
data:
  secret-key-base: OGQ0MjhlOWQyN2UzMzIzZjFiMWVjMDA4OTQ4MjAxNzQ4MDIyNGM5OTg0ZmMxMDMyN2Y5NWIwOTkwZWM0NjE3NWQ0M2Q3NTZmZDY0NGMzYmNhMzcwM2EzMzdhOTRjZWQ2OWM4NjhhYjA0NzBhYzIwMWNkMWI2YTgwYzNmODllNGE=
  database-url: bXlzcWw6Ly9kZXBsb3k6c2VjcmV0QDEyNy4wLjAuMS90b2Rv

Deployments

After creating the secret, we next create a deployment. A deployment contains the name of the image of your Rails app and the number of containers you want Kubernetes to run.

Deployments are used to rollout a new version of your app, rollback to a previous version, and to scale your app by running more containers.

You only need to change the values of "replicas" and "image". Notice we use the secrets we created earlier as environment variables. You should not put your credentials on your image and instead use a secret.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: railsapp-deployment
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: railsapp
    spec:
      containers:
      - name: railsapp
        image: crigor/rails51:v6
        ports:
        - containerPort: 3000
        env:
          - name: DATABASE_URL
            valueFrom:
              secretKeyRef:
                name: railsapp-secrets
                key: database-url
          - name: SECRET_KEY_BASE
            valueFrom:
              secretKeyRef:
                name: railsapp-secrets
                key: secret-key-base

If you do not have a Docker image on Docker Hub yet, check out the Dockerfile on our blog post on Using Docker For Rails. It's important to set the app to log to standard out instead of a log file so that Kubernetes logging works.

You can name the yaml file railsapp_deployment.yaml.

Services

Lastly, you have to create a service to be able to access the app. We use the type NodePort on Minikube where Kubernetes will forward requests to a port on the Minikube VM to the application.

When using AWS I use the type LoadBalancer where Kubernetes will create an ELB that points to the 3 containers.

kind: Service
apiVersion: v1
metadata:
  name: railsapp-service
spec:
  selector:
    app: railsapp
  type: NodePort
  #type: LoadBalancer
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 3000

Name the file railsapp_service.yaml.

Minikube

The instructions used here are for the Mac. If you have a different operation system, please refer to the Minikube documentation.

Install a Hypervisor

I use VirtualBox which you can download for free here.

Install kubectl

Download the kubectl and move it to your path.

$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl

Install Minikube

Download Minikube and move it to your path.

$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.21.0/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/

Feel free to leave off the sudo mv minikube /usr/local/bin if you would like to add minikube to your path manually.

Start Minikube

$ minikube start
Starting local Kubernetes v1.7.0 cluster...
Starting VM...
Downloading Minikube ISO
97.80 MB / 97.80 MB [==============================================] 100.00% 0s
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Starting cluster components...
Connecting to cluster...
Setting up kubeconfig...
Kubectl is now configured to use the cluster.

Check that kubectl can connect to the cluster with kubectl version and kubectl cluster-info.


Create the Kubernetes Objects

Now create the secret, deployment, and service from above.

$ kubectl create -f railsapp_secrets.yaml
$ kubectl create -f railsapp_deployment.yaml
$ kubectl create -f railsapp_service.yaml

Check the status.

$ kubectl get secrets

NAME TYPE DATA AGE
default-token-9flwv kubernetes.io/service-account-token 3 2m
railsapp-secrets Opaque 2 45s

$ kubectl get deployments,pods

NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
railsapp-deployment 3 3 3 0 1m

NAME READY STATUS RESTARTS AGE
railsapp-deployment-1000337448-2qkpd 0/1 ContainerCreating 0 1m
railsapp-deployment-1000337448-9lrjc 0/1 ContainerCreating 0 1m
railsapp-deployment-1000337448-qnmlr 0/1 ContainerCreating 0 1m

You can see here that Kubernetes is still pulling the Docker image. When the image is ready and the containers are running you should see 3 under AVAILABLE on the deployment and Running under STATUS on the pods.

e $ kubectl get services

NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.0.0.1 <none> 443/TCP 12m
railsapp-service 10.0.0.186 <nodes> 80:31596/TCP 1s

Test the App

The app will be available on the Minkube IP and the node port of the service. To get the Minikube IP, run minikube ip. On my local machine, the app is available on 192.168.99.100:31596.

You can also run minikube service railsapp-service and Minikube will open the URL on your browser.

Conclusion

Kubernetes makes it easier to scale and manage applications. Kubernetes is a complex system but you can start with the basics - Secrets, Deployments, Services. With these 3, you can already start running your Rails application inside Kubernetes.

I've shown you how to run Rails on Kubernetes on your local machine via Minikube. In production, you can create a cluster say in AWS and still mostly the same Kubernetes secret (with different credentials), deployment, and service. We've only scratched the surface. If you want to hear more about Kubernetes and Rails, do let us know by leaving a comment.

Free Ebook:
Should I Hire DevOps or Outsource to a Provider?

You have to invest in your infrastructure: Do you hire DevOps for this critical function, assign it to your already overworked engineers, or outsource to a provider that offers full-stack capabilities?

Should I Hire DevOps?

Christopher Rigor

 
DevOps Support Manager, Asia-Pacific at Engine Yard. Organizer of @RubyConfPH. Speaker. Interested in automation, Kubernetes, Docker, Deis, ops, Ruby.
Find me on:

Comments

Subscribe Here!