Running PostgreSQL on Kamal

PostgreSQL accessory

PostgreSQL can be added as any other accessory to the Kamal's configuration file. We'll just specify a PostgreSQL Docker image, the command to run, and the servers to run PostgreSQL on:

# config/deploy.yml
...
postgres:
  image: postgres:15
  roles:
    - web
  env:
    clear:
      POSTGRES_USER: "project"
      POSTGRES_DB: "project_production"
    secret:
      - POSTGRES_PASSWORD
  files:
    - config/init.sql:/docker-entrypoint-initdb.d/setup.sql
  directories:
    - data:/var/lib/postgresql/data

If we want to run an independent PostgreSQL server, we can provide a host IP address, otherwise we can tell Kamal which roles depend on it. Since PostgreSQL is a database we should mount a volume for data persistance across restarts. Here we are mounting a local data to the container's /var/lib/postgresql/data directory.

Providing ENVs

The PostgreSQL image requires some environment variables to be set, namely POSTGRES_USER, POSTGRES_DB, and POSTGRES_PASSWORD:

# config/deploy.yml
...
postgres:
  ...
  env:
    clear:
      POSTGRES_USER: "project"
      POSTGRES_DB: "project_production"
    secret:
      - POSTGRES_PASSWORD
  ...

The official Docker image will use these variables to create the database for you and you'll be able to connect to it with the following URL:

"postgres://POSTGRES_USER:POSTGRES_PASSWORD@DB_HOST/POSTGRES_DB"

Your DB_HOST will either be the IP address or the internal service name on the local Docker private network.

If you have created a private network called private, then add a network option:

service: myservice
...
postgres:
  ...
  options:
    network: "private"

Once added your DB_HOST will be myservice-postgres.

Initializing the database

Since the database cluster will be empty, we can initialize the database with a custom SQL file.

# config/deploy.yml
...
postgres:
  image: postgres:15
  ...
  files:
    - config/init.sql:/docker-entrypoint-initdb.d/setup.sql
  directories:
    - data:/var/lib/postgresql/data

Here the local config/init.sql will be used as a setup script. It can look like:

# config/init.sql
CREATE DATABASE myservice_production;

Deploying PostgreSQL

Once the configration is complete, we can instruct Kamal to boot PostgreSQL on the specified servers:

$ kamal accessory boot postgres