こんにちは!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は以下の手順を実行します:
- 新しいDockerイメージをビルドする。
- 新しいイメージからコンテナを起動する。
- 新しいコンテナが正常に動作しているかを検証する。
- Traefikを更新して、トラフィックを新しいコンテナにルーティングする。
- 古いコンテナを停止する。
特に注目すべき点は、ダウンタイムなしのデプロイメントを実現し、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
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
このコマンドは以下の処理を行います:
- SSHキーを使ってサーバーに接続。
- サーバーにDockerがインストールされていない場合は、get.docker.com を使ってDockerをインストール(SSH経由でrootアクセスが必要)。
- レジストリにローカルおよびリモートでログイン。
- アプリケーションのルートにある標準的なDockerfileを使用してDockerイメージをビルド。
- イメージをレジストリにプッシュ。
- レジストリからイメージをサーバーにプル。
- kamal-proxy がポート80および443でトラフィックを受け入れることを確認。
- 現在のGitバージョンのハッシュに一致するアプリケーションバージョンで新しいコンテナを起動。
- 新しいコンテナが GET /up リクエストに対して200 OKを返す場合、kamal-proxy にトラフィックを新しいコンテナにルーティングさせる。
- 前バージョンのアプリケーションを実行している古いコンテナを停止。
- 使用されていないイメージや停止したコンテナを削除して、サーバーの容量を確保。
デプロイが成功すると、次のような結果が表示されます。
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
次の手順で解決できます。
- サーバーにSSH接続します。
ssh ubuntu@18.182.197.19
- 以下のコマンドを実行して、現在のユーザーをDockerグループに追加します。
sudo usermod -aG docker $USER && newgrp docker
- 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
.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を使ったデプロイに挑戦してみてください!
株式会社エニグモ すべての求人一覧