Ruby on Rails has always been at the forefront of developer productivity, and building robust, highly interactive web applications has never been easier. Rails has been accurately described as the one-person framework. However, building your app is only half the battle. The other half is publishing it for others to use. Unfortunately, being able to deploy your application has always been an afterthought for most developers. The "one-person framework" doesn't carry through when it comes to deployment and operations unless you have specialized knowledge of building out infrastructure or pay others large sums of money to do it for you—until now. With the release of Kamal, the "one-person framework" idea completes the stack from end to end, allowing a single developer to do more with fewer resources.
Kamal is a new deployment tool created by the folks at 37Signals. It allows you to codify the deployment process into a single file and abstract many complicated bits that most applications don't need to worry about. It does this by using a combination of software like Docker containers and Traefik. Out of the box, along with Rails, you get a complete package that will get you production-ready in no time.
How it works
Kamal runs your web application in a Docker container on a server. It then uses a web server called Traefik to handle the network traffic between the Docker container and the internet.
The neat thing is that whenever you deploy a new version of your application, Kamal will do the following:
- Build a new version of a Docker image.
- Start a new container of that image.
- Ensure that the new container is healthy.
- Tell Traefik to start directing traffic to the new container.
- Stop the old container.
The benefit is that you can theoretically have zero downtime and blue/green deploys.
Kamal can also help scale your application horizontally by deploying your containers to multiple servers—but you'll need to load balance the servers yourself.
Setup
Install the Kamal gem on your local computer:
gem install kamal
Then, in your Rails application, initialize the setup:
kamal init
The kamal init
command will create two files. config/deploy.yml
contains everything Kamal will use to deploy your app, and .env
has secret environment variables used to configure your app (and should not get committed to your repo).
Acquire a VPS
Before configuring Kamal, let's discuss where we'll host our web app. There are lots of great options to choose from. An excellent cost-effective choice is a Virtual Private Server (VPS). A VPS is cost-effective because you are essentially sharing hardware with other customers. Although completely isolated from each other access-wise, you may have to contend with others for resources, which means some CPU bandwidth, memory, and storage limitations. A VPS should be fine for most applications, especially for this tutorial.
When choosing a VPS hosting provider, find one with a data center closest to you for faster response times. When selecting the level of resources, at a minimum, I'd recommend something with at least 1GB of memory for Rails applications. Also, choose a Debian-based Linux for the OS, as it's a popular choice, and it will be easy to find help if you run into trouble. Make sure that you have SSH access to the VPS. After creating your VPS, make a note of the published IP Address.
Acquire a domain name
If you plan to enable TLS/SSL for your application, you'll need to register a domain name and configure the DNS with a CNAME record to point to the IP address of your VPS.
Docker image registry
Kamal uses Docker containers for deployment. It takes your Dockerfile
and builds an image that will be used on your server. This image must be uploaded to a "registry." However, there are many free options to choose from, such as DockerHub, GitHub, or DigitalOcean. You'll need to sign up for one of these services and note the username and password you'll use to log in (or access tokens if applicable).
Configuration
Now that you have your VPS and registry login credentials, we can start configuring the deployment. At a minimum, your config/deploy.yml
file should look like this:
service: my-app
image: <your-registry-username>/my-app
servers:
web:
hosts:
- <your vps ip address>
registry:
username:
- <your-registry-username>
password:
- KAMAL_REGISTRY_PASSWORD
# If you use another service like DigitalOcean:
# registry:
# server: registry.digitalocean.com
# username:
# - <your-registry-username>
# password:
# - KAMAL_REGISTRY_PASSWORD
env:
secret:
- RAILS_MASTER_KEY
Fill in the required values as needed. Two environment variables will need our attention: KAMAL_REGISTRY_PASSWORD
and RAILS_MASTER_KEY
. These get populated by the .env
file upon deployment. Edit your .env
file to look something like this:
KAMAL_REGISTRY_PASSWORD=<your-registry-password-or-token>
RAILS_MASTER_KEY=<your-rails-production.key-value>
These values can be safely stored here as they shouldn't be committed to your repo, and they get securely transferred to the VPS when deployed. The RAILS_MASTER_KEY
can be found in config/credentials/production.key
. If it doesn't exist, you can create it by running the following:
rails credentials:edit --environment=production
Deployment
The first thing you'll want to do is run the server bootstrap command:
kamal server bootstrap
This command will SSH into your VPS and set up and install everything necessary for Kamal to run your application. It's a good idea to run this separately first in case of any failures; if there are any, they'll be easier to spot and diagnose. It only needs to be run once.
Next, we can start the deploy:
kamal deploy
The deploy
command will start the Docker build process locally and then push the image to your registry. Next, Kamal will boot a Traefik container on your server. Kamal will then start the healthcheck process container to ensure it boots and runs without issues. If successful, it'll start a permanent container that Traefik will see and begin directing traffic to it. If everything goes well, your Rails application should be available on port 80 of your VPS. Of course, Rails requires SSL by default for newer applications and will redirect you if you try to access it.
TLS/SSL
In production, you'll want to set up your web application with TLS/SSL to protect your users' privacy. Luckily, the Traefik server has built-in functionality to help us do that! We'll need to make a few modifications to config/deploy.yml
. First, tell Kamal that our Traefik server requires TLS/SSL. Add the following to deploy.yml
.
traefik:
options:
publish:
- 443:443
volume:
- "letsencrypt:/letsencrypt"
args:
entrypoints.web.address: ':80'
entrypoints.websecure.address: ':443'
certificatesResolvers.letsencrypt.acme.httpchallenge: true
certificatesResolvers.letsencrypt.acme.httpchallenge.entrypoint: web
certificatesResolvers.letsencrypt.acme.email: <your email address here>
certificatesResolvers.letsencrypt.acme.storage: /letsencrypt/acme.json
This config tells Traefik to use LetsEncrypt to acquire an SSL certificate and store it in a mounted volume. A mounted volume is crucial because it allows the certificate to persist if the container or server restarts. Port 443
is the default SSL port. All traffic that arrives via SSL can be tagged as coming from the websecure
entry point.
Next, we need to tell Traefik where to send this SSL traffic. Modify the servers part of the deploy.yml
:
servers:
web:
hosts:
- <your vps ip address>
labels:
traefik.http.routers.maildown-web.rule: 'Host(`<your domain name>`)'
traefik.http.routers.maildown-web.entrypoints: websecure
traefik.http.routers.maildown-web.tls.certresolver: letsencrypt
By adding these Docker labels to your application container, Traefik will act as an SSL termination point and direct all websecure
traffic to the application. Let's deploy these changes:
First, we reboot Traefik to pick up the new configuration:
kamal traefik reboot
Then, we redeploy our application to pick up the new labels:
kamal deploy
If everything goes well, you can now access your web app via https://
Where to go from here
I hope that you've found this introduction to Kamal useful. There is a lot more we can do with Kamal. Look for more blog posts about Kamal coming soon. In the meantime, check out some of these links for other Kamal features: