🌊

Docker + Rails 開発環境をつくる

に公開

本を参考にしながらdockerでrailsを使おうとしたのですが、おそらくバージョンが古くなってしまっていたため、うまく開かなかったので、関係していそうな記事を読んでは試し、試行錯誤していました💭

railsを導入できたときに参考にさせていただいた記事が、こちらになります。
https://qiita.com/crawling_cat/items/501fac2d7296f901f1f4

なぜ成功できたのか、学習をかねてchatgptに聞きながら備忘録を残したいと思います。

【使用環境・バージョン】
・Mac
・Ruby 3.3
・Rails 7.1.3
・MySQL 8.3

【完成系】
「ディレクトリ構成」
|- service # Railsプロジェクトを格納するディレクトリ
|- db_data # MySQLのボリュームディレクトリ
|- compose.yml
|- Dockerfile
|- Gemfile # Railsのパッケージバージョンを記載
|- Gemfile.lock

「Dockerfile」
FROM ruby:3.3

WORKDIR /service #Dockefileの命令ひとつで、コンテナ内のカレントディレクトリを指定するもの。
これ以降の命令(COPY や RUN など)が このディレクトリを基準に実行される。
例えば、COPY Gemfile* ./ と書いた場合、./ は /service を指すようになります。

COPY Gemfile* /service/

RUN bundle install

EXPOSE 3000

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

#CMDとは
Dockerfile で コンテナ起動時に実行するコマンド を指定する。
例えば CMD ["echo", "hello"] と書くと、コンテナ起動時に echo hello が実行される。
Dockerfile に複数 CMD があっても最後の1つだけが使われる。

#"rails", "server"
これは rails server コマンドを実行するという意味。
Rails アプリを 開発用サーバー(Pumaなど)で起動する。
デフォルトではポート 3000 で待機する。

#-b "0.0.0.0"
-b は bind の略で、サーバーをどの IP にバインドするか指定する。
"0.0.0.0" は 全てのネットワークインターフェース に対して待ち受ける、という意味。
Docker コンテナではこれを指定しないと コンテナ内部でしかアクセスできず、ホスト(PC)からアクセスできない ことがある。

まとめ
CMD ["rails", "server", "-b", "0.0.0.0"]

「コンテナ起動時に Rails サーバーを起動し、コンテナの外(ホストPCやネットワーク)からもアクセスできるように待機せよ」という意味。

【ステップ1】
・Gemfileでは何をしているの?
「公式RubyGemsからRails 7.1系をインストールして使います」
source…ライブラリはこのリポジトリからダウンロードしてね
~> … 互換性のあるバージョンなら更新OK

・Dockerfileでは何をしているの?
1.Ruby 3.3 の環境を準備
2.作業ディレクトリを作る
3.必要なGemをコピーしてインストール
4.Railsサーバーを起動できる状態にする

3 COPY Gemfile* /service/
ホストPCの Gemfile と Gemfile.lock をコンテナ内の /service/ にコピー。
Rails プロジェクトの依存関係(どのGemを使うか)をコンテナに渡すため。

【dockerファイル→コンテナ起動の流れ】

ホストPC (自分のPC)

├─ Dockerfile (設計図)

└─ docker build → イメージ作成


Docker イメージ
├─ Ruby 3.3
├─ 作業ディレクトリ /service
├─ Rails 必要なGem
└─ EXPOSE 3000


docker run → コンテナ起動


コンテナ内で
1. /service に移動 (WORKDIR)
2. Gemfile から Gem をインストール済み (bundle install)
3. Rails サーバー起動 (rails server -b 0.0.0.0)


コンテナのポート3000を外部に公開


ホストPCや他のネットワークから
http://localhost:3000 でアクセス可能

Dockerfile がコンテナの「設計図」となっている。

docker build で「設計図 → イメージ」

docker run / docker compose up で「イメージ → コンテナ」

コンテナ内で Rails サーバーが動き、外からアクセスできる

・compose.yml ではなにをしているの?
「build: .」
今いるディレクトリ(.)にある Dockerfile を使ってイメージを作る
=「このフォルダの Dockerfile を使って Web サービス用のコンテナを作れ」という意味

「ports: - '3000:3000'」
コンテナの 3000 番ポートを、ホストPCの 3000 番ポートに接続する
これで、ブラウザから http://localhost:3000 で Rails にアクセスできる

volumes(ボリューム)

  • type: bind
    source: ./service
    target: /service

バインドマウント(bind mount)を指定している
意味:
ホストPCの ./service ディレクトリを
コンテナ内の /service ディレクトリに「そのまま見えるように」する
こうすることで:
ホストPCでコードを編集すると、コンテナ内にも即座に反映される
Rails の再ビルドや再起動なしで開発が可能

source はホスト側のフォルダ
target はコンテナ側のフォルダ

「ホストのフォルダをコンテナ内に繋げるイメージ」と覚えるとわかりやすい

・config/database.ymlはなぜ変更したの?

Rails と MySQL を Docker コンテナで連携させるための変更

元の設定(AS-IS)
username: root
password:
host: localhost

root ユーザーで接続
パスワードは空
ホストは localhost(自分のコンピュータ内の MySQL を指す)
⚠️ このままだと Docker コンテナ内の Rails からは MySQL に接続できません。
Docker では Rails と MySQL は別のコンテナで動く ため、localhost では「自分のコンテナ内の MySQL」を探してしまうからです。

変更後(TO-BE)
username: <%= ENV['MYSQL_USER'] %>
password: <%= ENV['MYSQL_PASSWORD'] %>
host: <%= ENV['MYSQL_HOST'] %>

ENV['MYSQL_USER'] や ENV['MYSQL_PASSWORD'] は Docker Compose の環境変数から読み込む
例: compose.yml で MYSQL_USER: myapp と設定
host はコンテナ名(例えば db)を指定

Docker Compose 内ではサービス名がそのままホスト名として使える

?ENVとは
ENV は 環境変数(Environment Variables) のこと

環境変数は OSやコンテナに設定された値をプログラムから参照する仕組み。
Rails では <%= ENV['変数名'] %> という形でアクセスする。

✅ こうすることで:

Rails コンテナは MySQL コンテナの場所(ホスト名 db)を自動で参照できる
ユーザー名・パスワードもコンテナ間で共通化できる
コードに直接パスワードを書かなくて済む(セキュリティ的に安全)

最後のエラーの意味は?
Rails が指定したデータベースに接続できない という意味

docker compose run web rails db:create
コマンドの意味

docker compose run web

docker compose:Docker Compose を使って複数のコンテナを管理するときに使うコマンド

run:指定したサービスのコンテナを 一時的に起動してコマンドを実行する
終了するとコンテナも基本的に停止する

web:docker-compose.yml の中で定義した web サービスを指定

💡 要は「web サービスのコンテナを作って、ここでコマンドを実行する」という意味。

rails db:create

Rails のコマンド
db:create:database.yml に書かれた開発用(development)やテスト用(test)の データベースを作成する
実際には MySQL や PostgreSQL 上にデータベースを作ります

全体の意味

「Docker Compose の web コンテナを起動して、Rails の db:create を実行し、MySQL コンテナ上にデータベースを作れ」という命令

Discussion