はじめに
今回はDockerを使ってRailsAPIの環境構築および簡単なアプリ開発を行い、ローカルで作成したDockerコンテナをHerokuに置いて本番反映する流れを解説していきます。
Railsの環境構築およびAPIの開発そして本番反映の流れを学びたい人はぜひ参考にしてみてください。
この記事の対象者
- Dockerを使ってRailsAPIの開発をしたい人
- Dockerで作成したアプリをHerokuを使って本番反映したい人
- ポートフォリオ開発をこれからしたいと思っている人
この記事でやらないこと
- Railsの細かい文法説明
- Dockerについての詳しい解説
- Herokuについて詳しい解説
上記において必要箇所は解説を都度入れますが、「そもそもdockerとは」といった細かい箇所の解説については参考記事を貼っているのでそちらを参考にしていただければと思います。
この記事の目標
- Dockerを使ったRailsAPIの開発
- Dockerで作成したコンテナをHerokuに反映し本番公開する
DockerでRailsの環境を構築する
まずはじめにDockerでRailsの環境構築を行い、簡単なCRUDのAPIを作成していきます。
こちらに関しては公式ドキュメントを元に進めていきます。
Dockerについて
Dockerについての解説はこちらの記事が概要を掴みやすいので参考にしてみてください。
今回dockerで作るアプリの流れは下記です。
- アプリコードの作成
- DockerFileを作成
- イメージを元にコンテナを作成
- コンテナを起動しアプリを表示
プロジェクトディレクトリを作成しDockerFileを準備
ディレクトリ名は任意ですが自分はrails_docker_heroku
という名前で作成しました。
該当のディレクトリで下記のコマンドを実行しDockerFileを作成します。
% touch Dockerfile
ファイル内は公式ドキュメントを参考に下記の記述を追記します。
行毎の解説(概要)はコメントにて付与しています。
# FROMでベースイメージを設定
# 今回はRubyのバージョン2.7をベースイメージとして設定
FROM ruby:2.7
# nodeやyarn等の必要なライブラリをインストール
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
# Railsアプリを配置するフォルダをコンテナ内に作成
RUN mkdir /myapp
# 作成したディレクトリをワークディレクトリとして設定
WORKDIR /myapp
# ルート配下のGemfileをコンテナ内のRailsアプリを配置場所にコピー
COPY Gemfile /myapp/Gemfile
# Gemfile.lockも同様にコンテナ内にコピーする
COPY Gemfile.lock /myapp/Gemfile.lock
# Gemfileの記述を元にbundle installを実行
RUN bundle install
COPY . /myapp
# ローカルで作成したentrypoint.shファイル(後で記述)を/usr/bin/へコピー
COPY entrypoint.sh /usr/bin/
# /usr/bin/entrypoint.shに対して実行権限を付与している(chmod +x)
# これによってシェルスクリプトファイルを実行可能にする
RUN chmod +x /usr/bin/entrypoint.sh
# exec形式でデフォルトで実行するコマンドラインの引数としてentrypoint.shを指定
ENTRYPOINT ["entrypoint.sh"]
# ネットワーク上のポートを指定する
EXPOSE 3000
# Railsサーバーを稼働させる
CMD ["rails", "server", "-b", "0.0.0.0"]
Gem関連のファイルを作成する
$ touch Gemfile
$ touch Gemfile.lock
Gemfile
には下記の記述を初期値として追加します。
source 'https://rubygems.org'
gem 'rails', '~> 6.0.5', '>= 6.0.5.1'
Gemfile.lock
ファイルには何も書かなくて大丈夫です。
これら2つのファイルに関しては後で実行するrails new
コマンド実行時に書き変わります。
docker-compose.ymlを作成する
$ touch docker-compose.yml
docker-compose
を使うことでWebサーバーとデータベースのコンテナを一括に管理することができます。
今回はWebサーバーとデータベースの複数コンテナの操作をするコードを書いていきます。
docker-composeについての詳しい解説はこちらの記述を参考にしてみてください。
公式ドキュメントを参考にファイルを記述していきます。
こちらも同様にコメントにてコードの解説は付与しています。
# docker-composeで使用するバージョンの設定
# CIツールは2系以上から使える
version: "3"
# アプリケーションを動かすための各要素をserviceとしている
# dbとwebというサービスが今回は登録されている
services:
# データベースの設定
db:
# psqlのデータベースを設定
image: postgres
# volumeseでマウントを設定ファイルのパスを指定
volumes:
- postgresql-data:/var/lib/postgresql/data
# Dockerコンテナ内での環境変数を定義
# Rails側のdatabase.ymlに下記の情報を入れることで連携ができる(後述)
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
# DBのDockerイメージを立ち上げる際のポート番号
ports:
- "5432:5432"
# webサービス(今回でいうRailsアプリ)についての設定
web:
# 同じディレクトリにあるdockerFileを参照
build: .
# Railsのサーバーを起動している
# 立ち上げる毎にserver.pidのファイルを削除(エラー回避用)
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/myapp
ports:
- "3000:3000"
# webはdbに依存していることを明示
# 接続先をdbと記載するだけで使える
depends_on:
- db
volumes:
postgresql-data:
driver: local
entrypoint.shを作成
先ほど作成したDockerfile
内で読み込んでいたentrypoint.sh
を作成します。
こちらに書いた記述は初回起動時のみに実行することができます。
$ touch entrypoint.sh
#!/bin/bash
set -e
# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid
# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
以上でDocker関連のファイルへの記述は完了しました。
DockerでRailsの環境を構築する
今まで作成してきたdocker-compose.yml
とDockerfile
を元にRailsの環境を構築していきます。
Railsの環境を構築する
まずは先ほど作成したディレクトリ(rails_docker_heroku
)上で下記のコマンドを実行し、Docker上にRailsの環境を構築する。
$ docker-compose run web rails new . --api --force --no-deps --database=postgresql
- RailsのAPIモードで開発をするため
--api
のオプションをつけています - データベースはpsqlを使うので
database=postgresql
を付与しています。
なおdocker-composeコマンドについてのより詳しい解説は公式ドキュメントを参考にしてください。
これによってイメージが作成されたのでビルドします。
$ docker-compose build
CRUDのAPIを作成する
下記のscafoold
コマンドを実行することで記事(Post)のCRUDを自動生成してくれます。
$ docker-compose run --rm web rails generate scaffold Post title:string
scafooldについての詳しい解説は公式ドキュメントを参照してみてください。
ルーター、コントローラー、モデル他が自動で作成されています。
ファイルを確認します。
Rails.application.routes.draw do
resources :posts
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
class Post < ApplicationRecord
end
下記のファイルのみpost_params
の部分を書き換えています。
class PostsController < ApplicationController
before_action :set_post, only: [:show, :update, :destroy]
# GET /posts
def index
@posts = Post.all
render json: @posts
end
# GET /posts/1
def show
render json: @post
end
# POST /posts
def create
@post = Post.new(post_params)
if @post.save
render json: @post, status: :created, location: @post
else
render json: @post.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /posts/1
def update
if @post.update(post_params)
render json: @post
else
render json: @post.errors, status: :unprocessable_entity
end
end
# DELETE /posts/1
def destroy
@post.destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
@post = Post.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def post_params
params.permit(:title)
end
end
データベースの設定
docker-compose.yml
で設定したデータベースの内容をRailsアプリ側のconfig/database.yml
に記述する。
default:
の部分のみ下記のように書き換える。
default: &default
adapter: postgresql
encoding: unicode
host: db
username: postgres
password: password
pool: 5
development:
<<: *default
database: myapp_development
test:
<<: *default
database: myapp_test
production:
<<: *default
database: myapp_production
username: myapp
password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>
こちらの記述はDockerfile
内で記述した下記の箇所に対応している。
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
なおHerokuで使う本番環境用の設定は後で記述します。
変更を反映させるためにビルドコマンドを実行します。
# ビルドコマンド
$ docker-compose build
# データベース作成
$ docker-compose run web rails db:create
# マイグレーション
$ docker-compose run web rails db:migrate
コンテナの作成と起動
下記のコマンドを実行し作成したイメージからコンテナを立ち上げます。
docker-compose up
立ち上がったら下記にアクセスして表示が確認できれば無事成功です。
http://localhost:3000/
APIの動作確認
ここからPostmanを利用してAPIの動作確認をしていきます。
Postmanの準備については下記の記事を参考にまだやってない人は進めてください。
Postman上でプロジェクトを作り、Bodyを選択し先ほど作成したAPIに送信するデータ(title)を入れます。
リクエストはPOSTに設定します。
その上で右側のsendを押すとAPIのリクエストが送信されます。
下記のようなレスポンスが返ってくれば成功です。
次にGETを選択し今登録したデータが保存されているかを確認します。
削除(DELETE)と更新(PUT)も同様に確認できるので試してみてください。
Herokuにデプロイし本番反映する
ここまででローカルでのDockerの環境構築および、RailsAPIの動作確認が完了したのでHerokuを使って本番反映をしていきます。
Herokuはクラウド上にあるサーバーの一種で、簡単にサーバーを立てWebアプリを公開することができます。
Herokuの準備
まだHerokuを登録していない人は下記から登録を進めてください。
またDBを利用するためにクレジットカードの登録も済ませておいてください。なお今回やるアプリは無料で作成できます。
登録が完了したら下記のサイトの手順に従ってHerokuのCLIをインストールします。
これによってコマンドでHerokuを操作することができるようになります。
Heroku上でアプリの作成およびデータベースの登録
Herokuを使う準備ができたのでいよいよ先ほど作成したDockerイメージをHerokuへデプロイしていきます。
流れとしてはHeroku上にDockerコンテナを起動させてアプリを本番環境に公開していく。
まずはHerokuにログインします。コマンドを実行してユーザー名とパスワードを入力します。
$ heroku login
次にherokuのコンテナレジストリにログインします。先ほど作成したディレクトリ(rails_docker_heroku
上)で実行します。
$ heroku container:login
heroku上でアプリを作成します。任意にアプリ名は空欄にしておくと自動でheroku側で名前をつけてくれます。
すでに重複したアプリ名があると登録できないので注意してください。
$ heroku create 任意のアプリ名
postgresqlアドオンの無料プランを追加します。
$ heroku addons:create heroku-postgresql:hobby-dev
Heroku上でアプリの作成およびデータベースの登録
Herokuで作成したデータベースとRailsアプリで設定するデータベースの連携をしていきます。
環境変数の登録
まず先ほどHerokuで作成したデータベースの情報を取得します
$ heroku config
こちらのコマンドを実行すると下記のような値が返ってきます。
>> CLEARDB_DATABASE_URL: postgres://[ユーザー名]:[パスワード]@[ホスト名]/[データベース名]
ここから取得できる
- ユーザー名
- パスワード
- ホスト名
- データベース名
をHerokuの環境変数として登録をします。
# データベース名の登録
$ heroku config:add APP_DATABASE='データベース名' -a アプリ名
# ユーザー名の登録
$ heroku config:add APP_DATABASE_USERNAME='ユーザー名' -a アプリ名
# パスワードの登録
$ heroku config:add APP_DATABASE_PASSWORD='パスワード' -a アプリ名
# ホスト名の登録
$ heroku config:add APP_DATABASE_HOST='ホスト名' -a アプリ名
上記を登録した上で再度下記のコマンドを実行します。
$ heroku config
登録した環境変数が出てきたら成功です。
database.ymlの書き換え
次に今登録したHerokuの環境変数をdatabase.yml
に反映します。
本番設定のproduction
の記述を下記のように変更します。
default: &default
adapter: postgresql
encoding: unicode
host: db
username: postgres
password: password
pool: 5
# For details on connection pooling, see Rails configuration guide
# https://guides.rubyonrails.org/configuring.html#database-pooling
development:
<<: *default
database: myapp_development
test:
<<: *default
database: myapp_test
host: db
# 変更箇所
production:
<<: *default
database: <%= ENV['APP_DATABASE'] %>
username: <%= ENV['APP_DATABASE_USERNAME'] %>
password: <%= ENV['APP_DATABASE_PASSWORD'] %>
host: <%= ENV['APP_DATABASE_HOST'] %>
以上でHeroku側のデータベースと連携する作業は完了しました。
この段階で一度ローカル環境のdockerは停止します。
$ docker-compose down
そしたら下記のコマンドを実行します。
# イメージの作成
$ docker-compose build
# heroku側にイメージの作成
$ heroku container:push web
# マイグレーション
$ heroku run rails db:migrate
# イメージをherokuへデプロイ
$ heroku container:release web
最後に下記のコマンドを入力して実際にアプリが表示されるかを確認します。
$ heroku open
ここでセキュリティーのエラーが出てきたら下記のコードを追加します。
config.hosts << "herokuにデプロイしたアプリのURL"
再度こちらのコマンドを実行します。
# イメージの作成
$ heroku container:push web
# イメージをherokuへデプロイ
$ heroku container:release web
これで無事にDockerで作成したコンテナをHerokuに反映し本番反映ができました。
APIの動作確認もPostmanで確認することができます。
最後に
今回はDockerでRailsAPIを開発しHerokuに本番反映する流れを備忘録として残しました。
ぜひポートフォリオを作成する方やこれからDockerを使ってアプリ開発をする方は参考にしていただければなと思います。
他にもいろいろな記事を出しているので合わせて読んでいただけると嬉しいです。