KamalでRailsアプリケーションを迅速にデプロイする方法

こんにちは!Webアプリケーションエンジニアのレミーです!

この記事はEnigmo Advent Calendar 2024の 8日目の記事です。

Ruby on Rails 8が新しくリリースされ、Kamalという迅速かつ便利なデプロイツールが統合されました。私はこれまでRuby on RailsアプリケーションのデプロイにCapistranoを使用していましたが、Kamalを試してみると、その便利さと簡単さに魅了されました。

この記事では、Kamalを使用してRuby on Rails 8アプリケーションをAWS EC2サーバーにデプロイする手順を詳しく説明します。

Kamalとは?

Kamalは37Signalsのチームによって開発された新しいデプロイメントツールです。このツールを使用すると、デプロイメントプロセスを1つのファイルで定義でき、複雑な手順を簡素化できます。ほとんどのアプリケーションで考慮する必要がない複雑な部分を省略することが可能です。Kamalは、DockerコンテナやTraefikなどのソフトウェアを組み合わせて動作します。セットアップ段階から包括的なソリューションを提供し、Railsアプリケーションを最短時間で本番環境にリリースできます。

Kamalはどのように動作するのか?

Kamalは、サーバー上でDockerコンテナ内にWebアプリケーションを実行し、Traefikを組み合わせてネットワークトラフィックを処理します。新しいバージョンをデプロイする際、Kamalは以下の手順を実行します:

  1. 新しいDockerイメージをビルドする。
  2. 新しいイメージからコンテナを起動する。
  3. 新しいコンテナが正常に動作しているかを検証する。
  4. Traefikを更新して、トラフィックを新しいコンテナにルーティングする。
  5. 古いコンテナを停止する。

特に注目すべき点は、ダウンタイムなしのデプロイメントを実現し、blue/greenデプロイメントをサポートしていることです。

Ruby on Railsアプリケーションのサーバーの準備

ここでは、AWS EC2でサーバーを準備します。

EC2インスタンスの作成

Ubuntu Server 24.04を選択します。

KeyペアはSSHとサーバーへのアクセスに使用します。

セキュリティグループでは、以下のポートを開放してください:

SSH権限の設定

まず、ローカルの公開鍵をコピーします。

cat ~/.ssh/id_rsa.pub

インスタンスを起動したら、先ほど作成したKeyペアを使って、ubuntuユーザーでサーバーにSSH接続します。IPアドレスは新しく作成したインスタンスのものを使用します。

ssh ubuntu@18.182.197.19 -i /path/to/key.pem

次に、ローカルでコピーした公開鍵をサーバーの ~/.ssh/authorized_keys ファイルに貼り付けます。

ssh-rsa AAAABEAAAADAQABAAABgQ...AAAAB3Nzac2EAAAADAQABA Yuto MacBook Pro

これでサーバーの準備は完了です。以降は以下のコマンドでサーバーにSSH接続できます。

ssh ubuntu@18.182.197.19

Ruby on Rails 8アプリケーションの作成

まず、kamaltest という名前でRuby on Rails 8アプリケーションを作成します。

rails new kamaltest

プロジェクトディレクトリに移動します。

cd kamaltest

このアプリケーションは、タイトルと内容を持つ簡単なブログになります。そのため、scaffoldを使用して構築します。

rails g scaffold article title content:text

データベースを作成します。

rake db:migrate

routes.rb ファイルでホームページを設定します。

  root "articles#index"

アプリケーションを起動します。

bin/dev

その後、http://localhost:3000 にアクセスすると、アプリケーションが起動していることが確認できます。

deploy.ymlファイルでKamalを設定する

Ruby on Rails 8ではKamalが既に統合されています。それ以前のプロジェクトにKamalを追加する場合は、Gemfileに kamal を追加し、以下のコマンドを実行します。

kamal init

このコマンドを実行すると、Kamalがアプリケーションをデプロイするための設定を含む config/deploy.yml ファイルが生成されます。

Kamalの基本設定

デプロイのための設定は以下のようになります。

image: yutoyasunaga/kamaltest

servers:
  web:
    - 18.182.197.19 # server IP

proxy:
  ssl: true
  host: kamaltest.sampleapp.net

registry:
  username: yutoyasunaga
  password:
    - KAMAL_REGISTRY_PASSWORD

ssh:
  user: ubuntu
  • image: Docker Hub上に保存されるDockerイメージの場所
  • servers
    • web: サーバーのIPv4アドレス
  • proxy
    • ssl: true に設定するとSSLが自動的に設定されます
    • host: 使用するドメイン
  • registry
    • username: Dockerアカウントのユーザー名
    • password: Dockerアカウントのログインパスワード。セキュリティのため、KAMAL_REGISTRY_PASSWORD シークレットを通じて取得します。
  • ssh
    • user: サーバーにSSH接続する際のユーザー

Kamalのシークレット

機密情報は .kamal/secrets ファイルに配置します。以下はその例です。

# 環境変数からレジストリパスワードを取得
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD

シークレットは環境変数から取得します。例えば、Dockerのパスワードが hogehoge の場合、以下のように設定します。

export KAMAL_REGISTRY_PASSWORD='hogehoge'

以下のコマンドで値を確認できます。

echo $KAMAL_REGISTRY_PASSWORD

Kamalでデプロイを開始

config/deploy.yml の設定が完了したら、以下のコマンドを使用して初回のデプロイを開始します。

kamal setup

このコマンドは以下の処理を行います:

  1. SSHキーを使ってサーバーに接続。
  2. サーバーにDockerがインストールされていない場合は、get.docker.com を使ってDockerをインストール(SSH経由でrootアクセスが必要)。
  3. レジストリにローカルおよびリモートでログイン。
  4. アプリケーションのルートにある標準的なDockerfileを使用してDockerイメージをビルド。
  5. イメージをレジストリにプッシュ。
  6. レジストリからイメージをサーバーにプル。
  7. kamal-proxy がポート80および443でトラフィックを受け入れることを確認。
  8. 現在のGitバージョンのハッシュに一致するアプリケーションバージョンで新しいコンテナを起動。
  9. 新しいコンテナが GET /up リクエストに対して200 OKを返す場合、kamal-proxy にトラフィックを新しいコンテナにルーティングさせる。
  10. 前バージョンのアプリケーションを実行している古いコンテナを停止。
  11. 使用されていないイメージや停止したコンテナを削除して、サーバーの容量を確保。

デプロイが成功すると、次のような結果が表示されます。

Finished all in 70.0 seconds

初回のデプロイは kamal setup を使用しますが、2回目以降のデプロイでは kamal deployのコマンドを使用します。

permission denied エラーの解決方法

初回のデプロイで以下のようなDockerに関連するエラーが発生した場合:

Releasing the deploy lock...
  Finished all in 47.9 seconds
  ERROR (SSHKit::Command::Failed): Exception while executing on host 54.250.243.158: docker exit status: 1
docker stdout: Nothing written
docker stderr: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post "http://%2Fvar%2Frun%2Fdocker.sock/v1.47/images/create?fromImage=yutoyasunaga%2Fkamaltest&tag=4985d03bae739286203ce1185efdd4b2c71f90a9": dial unix /var/run/docker.sock: connect: permission denied

次の手順で解決できます。

  1. サーバーにSSH接続します。
ssh ubuntu@18.182.197.19
  1. 以下のコマンドを実行して、現在のユーザーをDockerグループに追加します。
sudo usermod -aG docker $USER && newgrp docker
  1. Dockerが正常に動作するか確認します。
docker ps

以下のような出力が表示されれば成功です。

CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

デプロイ後の結果を確認

まず、 https://hub.docker.com にアクセスして、イメージがプッシュされていることを確認します。

Route53を使用してドメインを管理している場合、以下のようにホストゾーン内でレコードを作成し、ドメインをサーバーのIPに向けます。

設定が正しい場合、https://kamaltest.sampleapp.net にアクセスすると、アプリケーションの画面が表示されます。

このように、1分ほどでRuby on Railsアプリケーションをサーバーにデプロイし、ドメインSSLの設定まで完了しました。便利ですね! 🎉

よく使われるKamalコマンド

aliases:
  console: app exec --interactive --reuse "bin/rails console"
  shell: app exec --interactive --reuse "bash"
  logs: app logs -f
  dbc: app exec --interactive --reuse "bin/rails dbconsole"

デフォルトの deploy.yml ファイルでは、以下の4つの便利なコマンドが定義されています。

  • kamal console: Railsコンソールにアクセス
  • kamal shell: サーバー上のコンテナにアクセス
  • kamal logs: サーバーログを確認
  • kamal dbc: データベースコンソールにアクセス

Kamalでのアセットのデプロイ

RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile

Dockerfile にはすでにアセットをプリコンパイルするコマンドが定義されています。そのため、デプロイ時にアセットも自動的に処理されます。

Kamalでの環境変数(Environment Variable)

開発環境の環境変数の設定

開発環境では、dotenv gem を使用します。 公式リポジトリ: https://github.com/bkeepers/dotenv

Gemfileにdotenvを追加 以下のコードを Gemfile に記載します。

group :development, :test do
  gem 'dotenv'
end

環境変数を管理する .env ファイルを作成し、例は以下のように記載します。

TEST_ENV_CLEAR=env_clear_local
TEST_ENV_SECRET=env_secret_local

環境変数が正しくロードされているかをRailsコンソールで確認します。

ENV.select { |key, _| key.start_with?("TEST_ENV") }
=> {"TEST_ENV_CLEAR"=>"env_clear_local", "TEST_ENV_SECRET"=>"env_secret_local"}

本番環境の環境変数の設定

現時点では以下の方法を使用していますが、より良い方法が見つかれば変更する予定です。

本番環境用の環境変数を管理する .env.production ファイルを作成します。

TEST_ENV_SECRET=env_secret_prod

deploy.yml ファイルに環境変数を設定します。

env:
  secret:
    - TEST_ENV_SECRET
  clear:
    TEST_ENV_CLEAR: env_clear_prod
  • clear: deploy.yml ファイルに直接記載される環境変数
  • secret: 機密情報を含む環境変数で、.kamal/secrets ファイルから読み込まれます。

.kamal/secrets ファイルで環境変数を以下のように設定します。

TEST_ENV_SECRET=$(cat .env.production | grep TEST_ENV_SECRET | cut -d '=' -f 2)

上記の設定は、.env.production ファイルから情報を抽出します。 例えば、.env.production に以下の行が含まれている場合:

TEST_ENV_SECRET=env_secret_prod

コマンド cut -d '=' -f 2 によって env_secret_prod が抽出されます。

デプロイ後、Railsコンソールにアクセスして環境変数を確認できます。

kamal console
ENV.select { |key, _| key.start_with?("TEST_ENV") }
=> {"TEST_ENV_SECRET"=>"env_secret_prod", "TEST_ENV_CLEAR"=>"env_clear_prod"}

Kamalは、Ruby on Railsアプリケーションのデプロイを大幅に簡素化し、効率化する強力なツールです。ぜひKamalを使ったデプロイに挑戦してみてください!


株式会社エニグモ すべての求人一覧

hrmos.co