Deploying Rails application with Kamal and MySQL

2 minute read

This article assumes the file exists with sqlite config:

For complete config visit Kamal Config Generator

Pro Tip:

Run the following command to switch the database from sqlite to mysql2:

rails db:system:change --to=mysql

Verify the changes and then you can jump to step 4.

1. Gemfile

First, update the Gemfile to use mysql2 as the database for Active Record.

-# Use sqlite3 as the database for Active Record
-gem "sqlite3", ">= 2.1"
+# Use mysql2 as the database for Active Record
+gem "mysql2", "~> 0.5"

2. Dockerfile

Next, update the Dockerfile to install the default-mysql-client and default-libmysqlclient-dev packages.

 # Install base packages
 RUN apt-get update -qq && \
-    apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && \
+    apt-get install --no-install-recommends -y curl default-mysql-client libjemalloc2 libvips && \
     rm -rf /var/lib/apt/lists /var/cache/apt/archives


 # Install packages needed to build gems
 RUN apt-get update -qq && \
-    apt-get install --no-install-recommends -y build-essential git pkg-config && \
+    apt-get install --no-install-recommends -y build-essential default-libmysqlclient-dev git pkg-config && \
     rm -rf /var/lib/apt/lists /var/cache/apt/archives

3. config/database.yml

Update the config/database.yml to use mysql2 as the adapter.

Note: Make sure to replace the password in production block to <%= ENV["MYSQL_ROOT_PASSWORD"] %>

default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  host: <%= ENV.fetch("DB_HOST") { "127.0.0.1" } %>

development:
  <<: *default
  database: kamal_demo_development

test:
  <<: *default
  database: kamal_demo_test

production:
  primary: &primary_production
    <<: *default
    database: kamal_demo_production
    password: <%= ENV["MYSQL_ROOT_PASSWORD"] %>
  cache:
    <<: *primary_production
    database: kamal_demo_production_cache
    migrations_paths: db/cache_migrate
  queue:
    <<: *primary_production
    database: kamal_demo_production_queue
    migrations_paths: db/queue_migrate
  cable:
    <<: *primary_production
    database: kamal_demo_production_cable
    migrations_paths: db/cable_migrate

4. config/deploy.yml

Update the config/deploy.yml to add environment variables the db accessory.

<% require "dotenv"; Dotenv.load(".env") %>

service: kamal-demo
image: yourregistryusername/kamal-demo
servers:
  web:
    - 12.34.56.78

proxy:
  ssl: true
  host: example.com

registry:
  username: yourregistryusername
  password:
    - KAMAL_REGISTRY_PASSWORD

env:
  secret:
    - RAILS_MASTER_KEY
    - MYSQL_ROOT_PASSWORD
  clear:
    DB_HOST: kamal-demo-db
    SOLID_QUEUE_IN_PUMA: true

volumes:
  - 'kamal_demo_storage:/rails/storage'

asset_path: /rails/public/assets

builder:
  arch: amd64

accessories:
  db:
    image: mysql:8.0
    host: 12.34.56.78
    port: "127.0.0.1:3306:3306"
    env:
      clear:
        MYSQL_ROOT_HOST: '%'
      secret:
        - MYSQL_ROOT_PASSWORD
    files:
      - db/production.sql:/docker-entrypoint-initdb.d/setup.sql
    directories:
      - data:/var/lib/mysql

5. .env

Add the MYSQL_ROOT_PASSWORD to the .env file.

KAMAL_REGISTRY_PASSWORD=dckr_pat_*******************o
MYSQL_ROOT_PASSWORD=mysql_*******************_password

6. .kamal/secrets

Add the MYSQL_ROOT_PASSWORD to the .kamal/secrets file.

KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD

RAILS_MASTER_KEY=$(cat config/master.key)

7. Deploy

Once done you should be able to deploy your Rails application with Kamal.

kamal deploy

If you get an error saying the service app-name-db already exists you can remove the service using the following command and then re-deploy.:

kamal accessory remove db
kamal deploy

Tags:

Categories:

Updated: