Dockerを使ってRailsのローカル環境構築

前提

githubにリポジトリを作成しておく
Dockerをインストールしている

Dockerを使う理由

progateやrailsチュートリアルのみをやられている方にとって、いきなりDockerを使って開発環境を構築していきましょうと言われてもキツイと思うので、詳しい説明は別のところで行うにしても、簡単になぜdockerを使いたいのか説明しておきます。

dockerは簡単にいうと、これから作ろうとしているアプリケーションが動作するための使い捨ての環境を用意するためのものです。

通常、railsをインストールして動作させるには、localhostにmysqlをインストールして起動しておき、gemfileに書かれたgemをPCにインストールして、場合によってはそれ以外にも必要なライブラリが出てくるかもしれません。一人で開発している場合でも、このアプリケーションでしか利用しないようなものを自分のPCにインストールするのはちょっと抵抗があるかと思います。また、複数人で開発しているような場合、この面倒な開発環境の構築は全員が一度はやる必要があり、それぞれがすでに入っているライブラリの状態に応じて実行するコマンドが一定ではなくなってしまいます。

dockerはこのような問題を解決してくれます。
コンテナと呼ばれる使い捨ての環境をコードによって自動的に作成することができ、その中にアプリケーションを展開することで、アプリケーションでしか利用しないようなライブラリを自分のPCに直接インストールする必要がなくなりますし、複数人で開発している場合でも、コンテナを立ち上げることで同じ環境が提供されるので、全員が同じ手順でアプリケーションを起動することができるようになります。

開発環境を構築する

Dockerをインストールされていない方はここでdockerをインストールしておきましょう。
Dockerのインストール方法についてはdockerの公式のサイトがわかりやすいので、こちらでよいとおもいます。
注意点はwindowsとmac(intelやappleシリコン)によってインストールするものが変わるので、それぞれのosにあったものを選択するようにしてください!

インストールが完了したら早速開発環境を構築していきましょう。

アプリケーションのディレクトリに移動してください。

cd ./techport-rails-nextjs

私は、このディレクトリ内にnextjsのアプリケーションも作成してrailsとnextjsを同じgithubリポジトリで管理するような構成で開発を進めていきたいと思います。そのため、railsのアプリケーション名はbackendとします。

まずはbackendディレクトリを作成します

mkdir backend

Dockerfileの準備

作成したbackendディレクトリにDockerfileを作成します。
その中身は下記の通りです。

FROM ruby:3.2

ENV LANG=C.UTF-8 \
    TZ=Asia/Tokyo

WORKDIR /app
RUN apt-get update -qq && apt-get install -y nodejs default-mysql-client vim
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install

CMD ["rails", "server", "-b", "0.0.0.0"]

簡単に書いてあることを説明しておきます

FROM ruby:3.2
→これはruby:3.2のdockerイメージベースにコンテナを作成するという意味です。ruby:3.2のイメージはdockerhubというところにデータが存在するのでそれを手元に用意してあげます

ENV LANG=C.UTF-8 \
TZ=Asia/Tokyo

→これはコンテナの環境変数に言語とタイムゾーンの設定をいれています。

WORKDIR /app
→これはコンテナの中にappというディレクトリを作成して、このディレクトリに移動してあげることを意味します。これによってコンテナ内部では/appディレクトリの中にrailsアプリケーションを構築していくことになります

RUN apt-get update -qq && apt-get install -y nodejs default-mysql-client vim
→これはrailsを起動させるにあたって必要だったりあると便利なライブラリをインストールしてあげています。

COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock

→これは左側に書かれているGemfileやGemfile.lockをコンテナ内に/app/Gemfileや/app/Gemfile.lockとして作成してあげることを意味します。GemfileやGemfile.lockはまだ作成していないので後で作成します

RUN bundle install
→コンテナ内でbundle installを実行します

CMD ["rails", "server", "-b", "0.0.0.0"]
→コンテナが起動するタイミングでrails server -b 0.0.0.0を実行します。

GemfileとGemfile.lockの準備

GemfileとGemfile.lockをbackendディレクトリ内に作成します。

Gemfile.lockはいずれ、rails newされるタイミングで自動的に書き込まれるので、空でよいです。

Gemfileにはrailsのgemをインストールする必要があるので

source 'https://rubygems.org'
gem "rails", "~> 7.0.8"

とだけ書いておいてください

docker-composeの準備

先に作成したDockerfileを起動したりrailsで利用するmysqlデータベースを用意し、それらのコネクションを確立させるためにdocker-compose.ymlを作成します。

docker-compose.ymlを作成してdocker composeのコマンドでコンテナを立ち上げることで、一つのコマンドで複数のコンテナを立ち上げ、さらに立ち上げたコンテナ同士が同一のネットワーク内に置かれるのでコネクションが便利になります

というわけで作成しましょう。

ここでは、後でnextjsもdocker composeで同時に立ち上げたいと思っているので、backendディレクトリではなく、アプリケーション直下にdocker-compose.ymlを置きます。
もし、nextjsを同時に立ち上げる予定がない場合は、Dockerfileと同じ階層においてあげるでよいです。
その場合、これから記載する相対パスが少し変わるので、その点だけ注意してください

cd ../
touch docker-compose.yml

作成したdocker-compose.ymlには下記の通り記載してください

version: "3.8.1"

services:
  db:
    image: mysql:8.1.0
    environment:
      - MYSQL_DATABASE=techport
      - MYSQL_ROOT_PASSWORD=password
    volumes:
      - mysql-db:/var/lib/mysql
    ports:
      - 3306:3306

  backend:
    tty: true
    stdin_open: true
    depends_on:
      - db
    build:
      context: ./backend/
      dockerfile: Dockerfile
    ports:
      - 3000:3000
    volumes:
      - ./backend:/app
    command: rails server -b 0.0.0.0

volumes:
  mysql-db:
    driver: local

分量が多いのでさらにざっくり解説していきます

version: "3.8.1"

docker-composeのバージョンです

services:
  db:
    image: mysql:8.1.0
    environment:
      - MYSQL_DATABASE=techport
      - MYSQL_ROOT_PASSWORD=password
    volumes:
      - mysql-db:/var/lib/mysql
    ports:
      - 3306:3306

railsが参照するデータベースのコンテナを用意します。
イメージにmysql:8.1.0を持ってきます。mysqlは一定の環境変数を入れておくことで、データベースを最初から作成したりDBにアクセスするためのアカウントの設定ができます。初期のデータベース名をtechport。rootユーザーのパスワードをpasswordにしています。
volumesはymlファイルの一番したのvolumes: …以下のところと関係します。これがあることで、使い捨てのコンテナではありますが、dbの中に作成されたデータたちはボリュームというところで管理されるようになり、コンテナを削除してもデータは残るので、また別でコンテナを作成してもデータが残っているような状態にできて非常に便利です。
portsでlocalhost:3306でアクセスできるようにします

  backend:
    tty: true
    stdin_open: true
    depends_on:
      - db
    build:
      context: ./backend/
      dockerfile: Dockerfile
    ports:
      - 3000:3000
    volumes:
      - ./backend:/app
    command: rails server -b 0.0.0.0

depends_onでdbが立ち上がった後にこのbackendのコンテナが立ち上がるようにします。contextとdockerfileの設定で./backend/Dockerfileを起動するようにしています。
3000番ポートでアクセスできるようにします

volumes:
  mysql-db:
    driver: local

ボリュームと呼ばれるデータの格納先を用意しています。mysqlのコンテナが削除されてもそのデータは残すための置き場所です

rails newする

ここまで準備ができたらrails newしていきます。
dockerを利用しているので、コマンドは通常よりも長めになります

docker compose run backend rails new . -d mysql

docker composeでbackendのサービスを起動しつつ、rails new . -d mysqlを実行しています。
-d mysqlはデータベースにmysqlを利用することの指定です

途中でOverwrite /app/Gemfile? (enter "h" for help) [Ynaqdhm] を聞かれたら、yを入れてenterでよいです

うまくいくと、非常に大量の新規ファイルが作成されると思います。

このまま、docker compose up –buildと、イメージを作成しつつ、コンテナを起動しようとすると、localhost:3000にはアクセスすることはできるのですが、railsのエラーになると思います。
Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

これは、mysqlのsocketというファイルが見当たらず、railsがうまくdbとコネクションできていないようです。
データベースとのコネクションについてはbackend/config/database.ymlファイルに設定があるので、これをいろいろと編集する必要があります。

最終的には

default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password
  host: db

development:
  <<: *default
  database: techport

このようになりました。

変更点は
passwordにpasswordを入れること
hostはlocalhostからdbにする
developmentのdatabseをtechport
にします。

データベースのパスワードはdocker-compose.ymlのMYSQL_ROOT_PASSWORDの値と合わせてください。また、hostはdocker-compose.ymlのservicesのデータベースの設定欄のキー名です


services:
  db: // ←ここ

databaseの値はMYSQL_DATABASEの値と合わせてください。

これでもう一度、コンテナとイメージを作成します。

docker compose up --build

localhost:3000にアクセスして、railsの画面は開くことができたでしょうか?

このように表示されていれば成功です!!

コメント

タイトルとURLをコピーしました