Rails 8 から新たに導入された「Kamal2」。
Docker コンテナを利用し、とても簡単にデプロイできるため、検証を兼ねて Rails 8で作成したアプリケーションをKamal 2を用いてデプロイしてみた。
本記事では、備忘録を兼ねて、その手順と気づきをアウトプットする。
前提条件
本記事における前提条件は以下のとおりだ。
アプリケーションのソースコードは、GitHub で管理している。
ローカル環境
- OS:Mac OS 15.6.1
- Ruby v3.4.7
- Rails v8.0.3
- データベース:SQLite3
- Kamal v2.7.0
- Docker v4.52.0
サーバー環境
- クラウド:さくらのVPS
- OS:AlmaLinux v10 x86_64
※SSHでログイン可能な状態に設定しておくこと
サーバーを準備する
VPSを準備する
VPSの準備については省略する。
「さくらのVPS」は以下リンク先から利用できる。プランは公開するアプリケーションの要件や用途に合ったものを選択する。

運用上の注意
セキュリティ面を考慮し、さくらの VPS の「パケットフィルター」機能を利用し、不要なポートを閉じ、通信制限を行うことを推奨する。
「パケットフィルター」機能の利用方法については、以下のマニュアルを参照。

サーバーにSSHで接続する
VPS に Mac 側で生成した SSH 公開鍵を登録し、サーバーへローカルから SSH で接続できるようにする。
手順は以下のマニュアルを参照。
https://manual.sakura.ad.jp/vps/controlpanel/ssh-keygen.html
公開鍵を追加した後、ターミナルから SSH でサーバーへ接続できることを確認する。
% ssh root@VPSのIPアドレス
以下のように表示されればOK。
[root@ホスト名 ~]#
サーバーにDockerをインストールする
以下のコマンドを実行。
# sudo dnf update -y && sudo dnf install -y dnf-plugins-core && sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo && sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin && sudo systemctl start docker && sudo systemctl enable docker
Dockerがインストールされたことを確認する。
バージョンが表示されれば成功だ。
# docker --version
Docker version 29.0.2, build 8108357
デプロイ用のユーザーを作成する
rootとは別に、デプロイ用のユーザーを作成する。(例:ユーザー名を「deploy」とする場合)
sudo useradd -m -s /bin/bash deploy && sudo usermod -aG docker deploy && echo "deploy ALL=(ALL) NOPASSWD: ALL" | sudo tee -a /etc/sudoers
作成したユーザーにパスワードを設定する。
sudo passwd deploy
作成したユーザーでSSH接続できることを確認する。
% ssh deploy@VPSのIPアドレス
deploy@VPSのIPアドレス's password:
Last login: ------
[deploy@ホスト名 ~]$
以上でサーバー側の準備は終了。
デプロイの準備をする
ローカルに Docker をインストールする
Kamal 2 によるデプロイでは Docker コンテナを利用するため、Docker が未インストールの場合は事前にインストールしておく。
※なお、記事作成時点では、アプリケーションの開発環境で Docker を利用していなくても問題なくデプロイできた。
インストールは以下リンク先を参照。
https://www.docker.com/ja-jp/
ローカルに Docker をインストールしない場合
デプロイ時に以下のエラーが出る。
ERROR (Kamal::Cli::DependencyError): Docker is not installed locally
config/deploy.ymlを編集する
config/deploy.yml には、Kamal 2 を用いてデプロイする際の設定を記入する。
なお、本ファイルはすべて小文字で記入すること。(大文字で記載するとエラーが出る)
# config/deploy.yml
service: リポジトリ名
image: GitHubユーザー名/アプリケーション名
servers:
web:
hosts:
- xxx.xxx.xxx.xxx # ← VPSのIPアドレス
registry:
server: ghcr.io
username: GitHubユーザー名 # ← GitHubユーザー名
password:
- KAMAL_REGISTRY_PASSWORD
ssh:
user: deploy # ← 作成したデプロイ用のユーザー名
env:
clear:
RAILS_ENV: production
secret:
- RAILS_MASTER_KEY
proxy:
ssl: true
host: ドメイン名 # ← 使用するドメインを入力する
builder:
arch: amd64
volumes:
- "storage:/rails/storage"
- "db:/rails/db"
asset_path: /rails/public/assets
ドメインを用いない場合
ステージング環境等で、ドメインを用いない場合は proxy の部分を以下のように記載する。
proxy:
ssl: false
host: xxx.xxx.xxx.xxx # ← VPSのIPアドレス
.kamal/secrets を編集する
前述の config/deploy.yml で使用する環境変数を .kamal/secrets に設定する。
GitHubで管理する場合、本ファイルは .gitignore に記載すること。
# GitHubのアクセストークン
KAMAL_REGISTRY_PASSWORD="ghp_xxxxxxxxxxxx"
# Rails Master Key
RAILS_MASTER_KEY=$(cat config/master.key)
# Secret Key Base
# rails secret で生成された値を貼り付ける
SECRET_KEY_BASE="yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
記載後、入力内容を読み込ませる。
% source .kamal/secrets
すべての環境変数が反映されていることを確認する。
echo $KAMAL_REGISTRY_PASSWORD
echo $RAILS_MASTER_KEY
echo $SECRET_KEY_BASE
GitHub アクセストークンの発行方法
以下リンク先から発行し、出力された値を上記ファイルへ貼り付ける。
権限は「write:packages」と「read:packages」にチェックを入れる。
https://github.com/settings/tokens
Kamal の設定を検証する
以下コマンドで、設定ファイルに問題がないか検証する。
エラーが出なければOK。
% kamal config
エラーの例
Builder が記載されていない
% kamal config
ERROR (Kamal::ConfigurationError): builder: Builder arch not set
Docker のメール認証が未実施
ERROR: failed to build: Error response from daemon: authentication required - email must be verified before using account
docker stderr: Nothing written
config/deploy.yml のリポジトリ名に大文字が含まれている
ERROR: failed to build: invalid tag "ghcr.io/GitHubユーザー名/アプリケーション名:fb3850f459c732813fb65f2613e4771be1a92ab4": repository name must be lowercase
docker stderr: Nothing written
サーバーを初期化する
デプロイ先サーバを Kamal が扱える状態に初期化する。
本手順を踏むことで「kamal deploy」や「kamal rollback」などのコマンドが使用できるようになる。
% kamal server bootstrap
デプロイをする
ここまでで準備完了。いよいよ初回デプロイを実施する。
初回セットアップ
以下コマンドで初回セットアップを実施。
本コマンドを実行時、完了まで約10分程度を要した。
% kamal setup
実行内容
1. Dockerイメージのビルド
2. GitHubにプッシュ
3. サーバーにデプロイ
4. データベースのセットアップ(SQLiteファイル作成)
5. マイグレーション実行
6. アセットのプリコンパイル
7. コンテナの起動
遭遇したエラー
初回実行時、以下のエラーに遭遇した。
ERROR (SSHKit::Command::Failed): Exception while executing on host VPSのIPアドレス: docker exit status: 1
docker stdout: Nothing written
docker stderr: Error: target failed to become healthy within configured timeout (30s)
以下コマンドでログを確認したところ、Rails 側に原因があった。
% kamal app logs --lines 100
原因を除去のうえ、再デプロイ。
エラーが出ずにデプロイできた。
アプリケーションの状態を確認する
以下のコマンドを実行し、特にエラーが出ていなければOK。
% kamal app logs
コンテナの一覧を確認する
本番環境でアプリケーションを起動しているコンテナを確認する。
% kamal app containers
INFO [029ed03d] Running docker container ls --all --filter label=service=アプリケーション名 --filter label=destination= on VPSのIPアドレス
デプロイが成功したことを確認する
ブラウザで ドメイン、または VPS の IP アドレスを実行し、アプリケーションが表示されることを確認する。
https://ドメイン名
http://VPSのIPアドレス
※ドメインを設定する場合、あらかじめゾーン設定を行っておくこと。( A レコードを VPS の IP アドレスに設定する)
リアルタイムでアプリケーションのログを確認する
アプリケーションが表示されたら、動作確認をする。
以下コマンドを実行し、エラーが出ないことを確認する。
% kamal app logs --follow
2 回目以降のデプロイ手順
2 回目以降は、変更を GitHub へ push した後、以下のコマンドを実行するのみでOK。
% kamal deploy
よく使うコマンド
アプリケーションの管理
デプロイ
% kamal deploy
ロールバック
% kamal rollback
再起動
% kamal app restart
停止
% kamal app stop
起動
% kamal app start
削除
% kamal app remove
Rails コンソールの起動
% kamal app exec --interactive --reuse "bin/rails console"
本番環境でのマイグレーション実行
% kamal app exec "bin/rails db:migrate"
本番環境でのロールバック
% kamal app exec "bin/rails db:rollback"
本番環境での seed 実行
% kamal app exec "bin/rails db:seed"
SQliteファイルのバックアップ
% kamal app exec "cat /rails/db/production.sqlite3" > backup_$(date +%Y%m%d_%H%M%S).sqlite3
バックアップからのリストア
cat backup_xxxxxx_yyyyyy.sqlite3 | kamal app exec --interactive "cat > /rails/db/production.sqlite3"
アプリケーションの状態確認
アプリケーションの状態
% kamal app details
コンテナの一覧
% kamal app containers
バージョン確認
% kamal app version
感想
従来のデプロイ方法(サーバ内部に Web サーバ、Ruby、Rails、データベースなどをインストールして行う方法)と比較すると、とても簡単にデプロイできた。
特に、複雑なセットアップ作業から解放され、アプリを動かすまでの手順が明確になったことで、デプロイに対する心理的ハードルが大きく下がった。Kamal 2 の利便性を実感できる良い経験になった。