How to deploy multi-environment(staging, production) application using Kamal (preivously MRSK)
Tags: kamal, rails, postgres
Published: 2023-04-11 00:36:58

---
title: How to deploy multi-environment(staging, production) application using Kamal (preivously MRSK)
published: true
date: 2023-04-09 08:45:00 UTC
tags: kamal,mrsk,rails,postgresql
canonical_url: https://www.kartikey.dev/2023/04/09/how-to-deploy-multi-environment-staging-production-application-using-mrsk.html
---

In the [previous post](https://dev.to/tannakartikey/deploy-rails-app-and-postgres-with-mrsk-on-single-digitalocean-server-7e3), I described how to host a Rails app and a database on a single server. This post will describe what if you want to host multiple environments i.e. staging, production of the same application using [Kamal](https://kamal-deploy.org/) - previously known as MRSK.

Kamal uses [Traefik](https://traefik.io/) as a reverse proxy. It means that any incoming request will be handled by Traefik. Traefik will handover the request to appropriate server and Docker container based on the configuration. For example, let’s assume that we have deployed the staging and the production version of our apps on the server. Then we have to configure Traefik in such a way that it points “staging.myapp.com” and “production.myapp.com” to the staging and the production Docker containers respectively.

Kamal uses Traefik with “docker” as a [provider](https://doc.traefik.io/traefik/providers/overview/). Traefik [rules](https://doc.traefik.io/traefik/routing/routers/#rule) are configured by providing certain lables to Docker containers. You can read more about it in their [docs](https://doc.traefik.io/traefik/providers/docker/).

Let’s start configuring Kamal. Kamal has a feature called [“destination”](https://github.com/basecamp/kamal/pull/71), we will use that to create two separate destinations - “staging” and “production”. First, we will create the `config/deploy.yml` file with common options like service name, image name, registry, common environment variables, and Postgresql database as acessory.

```
# config/deploy.yml
service: myapp
image: user/myapp

registry:
  username: user
  password:
    - KAMAL_REGISTRY_PASSWORD

env:
  clear:
    DB_HOST: 99.99.99.99
  secret:
    - RAILS_MASTER_KEY
    - POSTGRES_PASSWORD

accessories:
  db:
    image: postgres:15
    host: 99.99.99.99
    port: 5432
    env:
      clear:
        POSTGRES_USER: 'myapp_db_user'
      secret:
        - POSTGRES_PASSWORD
    directories:
      - data:/var/lib/postgresql/data

```

#### Staging config

Now, let’s create a destination named “staging” with the `config/deploy.staging.yml` file.

```
# config/deploy.staging.yml
servers:
  - 99.99.99.99

labels:
  traefik.http.routers.myapp-web-staging.rule: Host(`staging.myapp.com`)

env:
  clear:
    POSTGRES_DB: myapp_staging
    IS_STAGING: true

```

In this file we have declared the server for the staging environment, environment variable spcific to the environment and we have used the `labels` key that will attach the labels to the staging Docker container.

Let’s understand these rules with little more details. Kamal applies some default Traefik labels to each container in the “service-role-destination” format. With the help of these labels Traefik defines a [service](https://doc.traefik.io/traefik/routing/services/) (not to be confused with Kamal service). With the rule mentioned in the `deploy.staging.yml` file above, we are overriding the default labels. Since we have not specified any role, Kamal will assign the web role to the service. Anyways, there has to have one “web” role if we are specifying roles.

Don’t forget to replace “staging.myapp.com” with your domain. The domain should be configured to point to the IP of the server.

#### Production config

```
# config/deploy.production.yml
servers:
  - 99.99.99.99

labels:
  traefik.http.routers.myapp-web-production.rule: Host(`rails.myapp.com`)

env:
  clear:
    POSTGRES_DB: myapp_production

```

The `deploy.production.yml` is similar to the staging configuration. Since we are going to deploy both the staging and the production as well as Postgresql(the database) on the same server, the same IP is configured under the `hosts` key. Again, don’t forget to configure your domain.

That’s it! You should have both the staging and the production as well as the database deployed on the same or different server(s) and accessible from the domains you have set for each environment!