Rails8がリリースされたので、標準仕様となったkamalを使ってAWSにデプロイしてみます。
事前準備
以下のアカウント登録をしておきます。
アプリケーションを新規作成
今回、DBはPostgreSQLを使います。
$ rails new kamal_deploy -d postgresql
$ cd kamal_deploy
$ rails db:migrate
bin/devコマンドでRailsアプリケーションを起動します。
$ bin/dev
http://localhost:3000 にアクセスして、Railsが起動していることを確認できたら、いったんコミットします。
$ git add .
$ git commit -m "Initial commit"
トップページ作成
config/routes.rbを編集して、以下のようにrootを設定します。
root "home#index"
HomeControllerを作成します。
class HomeController < ApplicationController
def index
end
end
Viewファイルを作成します。
<div>
<h1>ホーム</h1>
</div>
http://localhost:3000 にアクセスして、ホームと表示されることを確認できたら、いったんコミットします。
$ git add .
$ git commit -m "Add home"
.envファイル作成
あとでRDSの認証情報など記載するために、.env ファイルを作成します。
$ touch .env
このファイルはGitにコミットしないようにしてください。
(Rails8だとデフォルトで.gitignoreに記載されていました)
AWS準備
必要な構成
- EC2: アプリケーションサーバ
- RDS: データベースサーバ (PostgreSQL)
セキュリティグループの設定は必要に応じて適切に制限してください。
実運用では冗長化や監視設定も検討してください。
EC2設定
- マシンイメージ: Ubuntu Server 24.04
- インスタンスタイプ: t2.micro
- セキュリティグループ: SSH, HTTP を許可
- 固定 IP: EIP を使用
SSH接続
ローカルから EC2 に接続します。
$ ssh ubuntu@パブリックIP -i ~/.ssh/<pemファイル>
接続できたら、いったんローカルに戻ります。
pemファイルなしでSSH接続できるようにします。
ローカルで公開鍵をコピーします。
$ cat ~/.ssh/id_rsa.pub
ssh-rsa <your-public-key>
↑ 表示された内容をコピー
コピーしたら、再度EC2に接続します。
$ ssh ubuntu@パブリックIP -i ~/.ssh/<pemファイル>
ローカルでコピーした公開鍵をサーバーの ~/.ssh/authorized_keys ファイルに貼り付けます。
$ vi ~/.ssh/authorized_keys
# ファイルを編集して保存する
ローカルからpemファイルの指定なしでSSH接続できることを確認します。
$ ssh ubuntu@パブリックIP
RDS設定
- エンジン: PostgreSQL 14.10-R2
- インスタンスタイプ: db.t3.micro
- セキュリティグループ: インバウンドにEC2を許可
RDS のエンドポイントや認証情報を .env ファイルに記載します。
デプロイ準備
kamal設定
config/deploy.ymlを編集し、以下のように設定します。
<% require "dotenv"; Dotenv.load(".env") %>
# Name of your application. Used to uniquely configure containers.
service: kamal_deploy
# Name of the container image.
image: <DockerHubのアカウント名>/kamal_deploy
# Deploy to these servers.
servers:
web:
- <EC2のパブリックIP>
# job:
# hosts:
# - 192.168.0.1
# cmd: bin/jobs
# Enable SSL auto certification via Let's Encrypt and allow for multiple apps on a single web server.
# Remove this section when using multiple web servers and ensure you terminate SSL at your load balancer.
#
# Note: If using Cloudflare, set encryption mode in SSL/TLS setting to "Full" to enable CF-to-app encryption.
# proxy:
# ssl: true
# host: app.example.com
# Credentials for your image host.
registry:
# Specify the registry server, if you're not using Docker Hub
# server: registry.digitalocean.com / ghcr.io / ...
username: <DockerHubのアカウント名>
# Always use an access token rather than real password when possible.
password:
- KAMAL_REGISTRY_PASSWORD
# Inject ENV variables into containers (secrets come from .kamal/secrets).
env:
secret:
- RAILS_MASTER_KEY
- DATABASE_USERNAME
- DATABASE_PASSWORD
- DATABASE_HOST
clear:
# Run the Solid Queue Supervisor inside the web server's Puma process to do jobs.
# When you start using multiple servers, you should split out job processing to a dedicated machine.
SOLID_QUEUE_IN_PUMA: true
# Set number of processes dedicated to Solid Queue (default: 1)
# JOB_CONCURRENCY: 3
# Set number of cores available to the application on each server (default: 1).
# WEB_CONCURRENCY: 2
# Match this to any external database server to configure Active Record correctly
# Use kamal_deploy-db for a db accessory server on same machine via local kamal docker network.
# DB_HOST: 192.168.0.2
# Log everything from Rails
# RAILS_LOG_LEVEL: debug
# Aliases are triggered with "bin/kamal <alias>". You can overwrite arguments on invocation:
# "bin/kamal logs -r job" will tail logs from the first server in the job section.
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"
# Use a persistent storage volume for sqlite database files and local Active Storage files.
# Recommended to change this to a mounted volume path that is backed up off server.
volumes:
- "kamal_deploy_storage:/rails/storage"
# Bridge fingerprinted assets, like JS and CSS, between versions to avoid
# hitting 404 on in-flight requests. Combines all files from new and old
# version inside the asset_path.
asset_path: /rails/public/assets
# Configure the image builder.
builder:
arch: amd64
# # Build image via remote server (useful for faster amd64 builds on arm64 computers)
# remote: ssh://docker@docker-builder-server
#
# # Pass arguments and secrets to the Docker build process
# args:
# RUBY_VERSION: 3.3.6
# secrets:
# - GITHUB_TOKEN
# - RAILS_MASTER_KEY
# Use a different ssh user than root
ssh:
user: ubuntu
# Use accessory services (secrets come from .kamal/secrets).
# accessories:
# db:
# image: mysql:8.0
# host: 192.168.0.2
# # Change to 3306 to expose port to the world instead of just local network.
# port: "127.0.0.1:3306:3306"
# env:
# clear:
# MYSQL_ROOT_HOST: '%'
# secret:
# - MYSQL_ROOT_PASSWORD
# files:
# - config/mysql/production.cnf:/etc/mysql/my.cnf
# - db/production.sql:/docker-entrypoint-initdb.d/setup.sql
# directories:
# - data:/var/lib/mysql
# redis:
# image: redis:7.0
# host: 192.168.0.2
# port: 6379
# directories:
# - data:/data
.envを編集し、以下のように設定します。
KAMAL_REGISTRY_PASSWORD=<DockerHubのアクセストークン>
DATABASE_USERNAME=<RDSのマスターユーザー>
DATABASE_PASSWORD=<RDSのマスターパスワード>
DATABASE_HOST=<RDSのエンドポイント>
.kamal/secretsを編集し、以下のように設定します。
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
# Improve security by using a password manager. Never check config/master.key into git!
RAILS_MASTER_KEY=$(cat config/master.key)
DATABASE_USERNAME=$DATABASE_USERNAME
DATABASE_PASSWORD=$DATABASE_PASSWORD
DATABASE_HOST=$DATABASE_HOST
database.ymlを編集し、以下のように設定します。
productionのprimary部分のみ抜粋しています。
production:
primary: &primary_production
<<: *default
database: kamal_deploy_production
username: <%= ENV["DATABASE_USERNAME"] %>
password: <%= ENV["DATABASE_PASSWORD"] %>
host: <%= ENV["DATABASE_HOST"] %>
ここまでで、いったんコミットします。
$ git add .
$ git commit -m "Setup deploy"
デプロイ実行
以下のコマンドでデプロイを実行します。
$ bin/kamal setup
もしpermission deniedのエラーが出た場合は、EC2にSSHして以下のコマンドを実行します。
$ sudo usermod -aG docker $USER && newgrp docker
EC2 のパブリック IP にアクセスし、ホームが表示されることを確認します。
以上で、kamalを使ったAWSへのデプロイは完了です。
2回目以降、デプロイする場合は以下のコマンドでもOKです。
$ bin/kamal deploy
注意点
kamalはコミットされている内容をデプロイします。
そのため、例えばローカルで一時的に変更した内容をデプロイしたい場合でもコミットする必要があります。
このときGithubへのプッシュは不要です。
まとめ
kamalを使ったAWSへのデプロイを試してみました。
今回は、ローカルから実行しましたが実運用を考えるとGithub Actionsなどから実行できるようにしたほうが良さそうです。
個人的に気になったのは、.envの内容が自動的に読み込まれないようになっていることでした。
.kamal/secretsに秘匿情報を設定して、git管理しない方法もあるようです。
参考記事
https://kamal-deploy.org/docs/configuration/environment-variables/
https://kamal-deploy.org/docs/upgrading/secrets-changes/
スポンサーリンク