In most of the projects I contributed to, the deployment workflow looked like this :
We got a Preprod application that lets us experiment and do some QA. Preprod is an application that I can break without impacting users. Once I know that my Preprod application is working correctly, I can then deploy my application to the Production environment and expose new features to users.
Usually, I used Heroku for both Preprod and Prod. Butβ¦ come on, weβre in 2024 right ? Heroku is old school, now weβre using Kamal π
Today Iβll share with you how I manage the deployment of multienvironment application using Kamal 2 in a step-by-step guide.
I wonβt go that deep on how to configure kamal, Iβll just share the specificities of handling 2 environments deployment. If you need more details about a certain part, I linked useful resources that helped me and will help you for sure in the conclusion.
Prepare your Preprod environment
Before toying with Kamal, we need to create the Preprod environment.
To do so, I only need to create a new file in my environments folder
$ cp config/environments/production.rb config/environments/preprod.rb
I want my Preprod environment to be as close as possible to my Prod environment, so I wonβt edit the file.
Now that Rails knows my Preprod environment, I need to create a master.key
for this environment
$ rails credentials:edit -e preprod
One last thing, we need a dedicated Dockerfile to handle this specific environment when building the Docker image.
For the sake of this article, I will take the default Dockerfile provided by Rails when youβre using rails new
, and create a dedicated one for Preprod environment :
$ cp Dockerfile Dockerfile.preprod
The only thing I will edit will be the ENV variables set by Dockerfile.preprod
:
# Dockerfile.preprod L20
ENV RAILS_ENV="preprod" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development"
Thatβs it, now weβre good to explore Kamal !!
Your folder architecture will look like this :
.
βββ Dockerfile
βββ Dockerfile.preprod
βββ config
βββ credentials
βΒ Β βββ preprod.key
βΒ Β βββ preprod.yml.enc
βββ credentials.yml.enc
βββ environments
βΒ Β βββ preprod.rb
βΒ Β βββ production.rb
βββ master.key
Install Kamal
Kamal is not a gem that you add to your Gemfile, but you can install it using gem
:
$ gem install kamal
Once itβs done, you have access to Kamal. You can use the following command to bootstrap your Kamal configuration :
$ kamal init
kamal init
will create a config/deploy.yml
file and a .kamal
folder containing a hooks directory and a secrets
file
Setup Prod
I will keep my config/deploy.yml
as simple as possible, here is what I write :
# config/deploy.yml
service: my-app
image: docker-username/my-app
servers:
web:
- 190.0.0.0
proxy:
ssl: true
host: mydomain.com
app_port: 3000
registry:
username: docker-username
password:
- KAMAL_REGISTRY_PASSWORD
builder:
arch: arm64
local: true
dockerfile: Dockerfile.production
context: "."
env:
secret:
- RAILS_MASTER_KEY
ssh:
user: ubuntu
Letβs dive into each parameter :
- service: The name of your application
- image: The name of the image you will use for your registry (Iβll use a public docker registry here)
- servers: The addresses of the servers you will deploy your application. Here I have a single host for my production. I can also add a dedicated process for jobs handling if I need to process job.
- proxy: handle SSL certificate and point to the right domain name
- registry: where your Docker image will be pushed / pulled
- builder: Use Dockerfile.production and build it locally when deploying to the server. I use arm64 architecture because Iβm using a macBook.
- env: Itβs a way of passing secrets to the machine. Weβll talk about it just after
-
ssh: Kamal will connect to the servers using the
ubuntu
user
To provide secrets, Kamal introduces it own secrets mechanism. You need to edit .kamal/secrets
to add the RAILS_MASTER_KEY
environment variable.
# .kamal/secrets
RAILS_MASTER_KEY=$(cat config/master.key)
KAMAL_REGISTRY_PASSWORD=mysuperpassword
Once itβs done, youβre good to either setup your server or deploy your application.
$ kamal setup
$ kamal deploy # if you want to deploy only
And now your application is running in production and fully accessible at your domain π
At this stage, your folder architecture will look like this :
.
βββ .kamal
βΒ Β βββ secrets
βββ Dockerfile
βββ Dockerfile.preprod
βββ config
βββ credentials
βΒ Β βββ preprod.key
βΒ Β βββ preprod.yml.enc
βββ credentials.yml.enc
βββ deploy.yml
βββ environments
βΒ Β βββ preprod.rb
βΒ Β βββ production.rb
βββ master.key
Letβs see how to setup Preprod deployment now !
Setup Preprod
To configure Preprod deployment, we need to replicate what we did for Production, and essentially add .preprod
everywhere:
$ cp .kamal/secrets .kamal/secrets.preprod
$ cp config/deploy.yml config/deploy.preprod.yml
And then in the config/deploy.preprod.yml
:
# config/deploy.preprod.yml
image: docker-username/my-app-preprod
servers:
web:
- 190.0.0.1
proxy:
host: preprod.mydomain.com
builder:
dockerfile: Dockerfile.preprod
And β¦ thatβs it.
Kamal will read the βprimaryβ config (deploy.yml
) as a fallback for missing value in our deploy.preprod.yml
. Weβre just saying to Kamal that it must take the Dockerfile.preprod
and set the SSL certificate will point to preprod.mydomain.com
The last thing to do before deploying is to edit the secrets :
# .kamal/secrets.preprod
RAILS_MASTER_KEY=$(cat config/credentials/preprod.key)
KAMAL_REGISTRY_PASSWORD=mysuperpassword
And then youβre good to go :
$ kamal setup -d preprod
$ kamal deploy -d preprod # if you want to deploy only
Your application can be accessed at preprod.mydomain.com
!
Your folder architecture will look like this :
.
βββ .kamal
βΒ Β βββ secrets
βΒ Β βββ secrets.preprod
βββ Dockerfile
βββ Dockerfile.preprod
βββ config
βββ credentials
βΒ Β βββ preprod.key
βΒ Β βββ preprod.yml.enc
βββ credentials.yml.enc
βββ deploy.preprod.yml
βββ deploy.yml
βββ environments
βΒ Β βββ preprod.rb
βΒ Β βββ production.rb
βββ master.key
Ressources
Conclusion
I took a lot of shortcuts here, but the point is that itβs very easy and painless to deploy multienvironment applications using Kamal.
So far, I only have good experience using Kamal. I've never had any difficult stages while debugging / monitoring, so itβs a very positive thing.
Top comments (0)