Deploy Rails app with PostgreSQL, Redis and Sidekiq on Production and Staging using Kamal
Tags: rails, kamal
Published: 2024-03-07 08:13:09

**Step 1: Install Kamal**

Article is for those who already have installed kamal with ready to use servers but if you doesn't, just take a look on [Kamal gem](https://rubygems.org/gems/kamal) and make sure that is installed on your local machine:

```
gem install kamal
```

**Step 2: Configure Deployment Settings**

Move into the application directory and run:

```
kamal init
```
This process generates a deployment configuration file named **config/deploy.yml**, in addition to several other files. We will now delve into the different sections of the **deploy.yml** configuration file to understand their purposes and configurations.

deploy.yml
```
# Name of your application. Used to uniquely configure containers.
service: myrailapp

# Name of the container image.
image: mydockerhubuser/myrailapp


# Credentials for your image host.
registry:
  username: mydockerhubuser
  password:
    - KAMAL_REGISTRY_PASSWORD

# Inject ENV variables into containers (secrets come from .env).
# Remember to run `kamal env push` after making changes!
env:
  clear:
    RAILS_SERVE_STATIC_FILES: true
    DB_HOST: 10.0.0.6
  secret:
    - RAILS_MASTER_KEY
    - POSTGRES_PASSWORD

volumes:
  - "/storage:/rails/storage"

# Use accessory services (secrets come from .env).
accessories:
  db:
    image: postgres:15
    host: 66.100.100.10
    port: 5432
    env:
      clear:
        POSTGRES_ROOT_HOST: '%'
        POSTGRES_USER: 'db_us1_app'
      secret:
        - POSTGRES_PASSWORD
    directories:
      - data:/var/lib/postgresql/data
  redis:
    image: redis:latest
    host: 61.111.111.1
    port: 6379
    directories:
      - data:/var/lib/redis/data
```
In our example, we utilize [DockerHub](https://hub.docker.com/) and connect to it using the DockerHub username 'mydockeruser' and the repository name 'myrailapp' (which can be private). The password is configured via the `KAMAL_REGISTRY_PASSWORD` environment variable within the .env file, located in the root directory of the application. Additionally, it's crucial to remember to list .env files in the .gitignore to prevent them from being tracked and uploaded to version control systems.**DB_HOST** using local IP of the machine but you can use your public server address as well.

.env
```
KAMAL_REGISTRY_PASSWORD=dckr_pat_382391340045824911111
RAILS_MASTER_KEY=25345k34j543132432m5j4234
POSTGRES_PASSWORD=s0meR@andomPasw0rt
```

To separate the staging and production environments, we should create two additional files: **deploy.staging.yml** for staging and **deploy.production.yml** for production. In this scenario, the staging environment will be deployed on a single server, while the production environment will be deployed across two servers. Both environments will share a common server for the database and jobs (utilizing a Redis server), albeit with different databases to ensure separation of staging and production data.

deploy.staging.yml
```
servers:
  web:
    hosts:
      - 60.100.100.101
  job:
    hosts:
      - 61.111.111.1
    cmd: bundle exec sidekiq -e staging
env:
  clear:
    POSTGRES_DB: app_staging
    RAILS_ENV: staging
```

deploy.production.yml

```
servers:
  web:
    hosts:
      - 60.100.100.102
      - 60.100.100.103
  job:
    hosts:
      - 61.111.111.1
    cmd: bundle exec sidekiq -e production
env:
  clear:
    POSTGRES_DB: app_production
    RAILS_ENV: production
```

Do not forget to create **.env.staging** as well which can be a copy of the **.env** if the credentials are the same.

**Step 3: Deploy Application**

```
kamal setup
```

**Daily operations:**

```
kamal deploy -d staging
```
or 

```
kamal deploy -d production
```

Check [kamal docs](https://kamal-deploy.org/docs/commands) for more commands and use cases.