初心者でもできたDockerを活用したRailsの環境構築

## はじめに
現在、Railsを学習しているものです。プログラミング学習を始めて約5ヶ月が経ちました。その中で特に苦手意識があるのが環境構築です。今回は、Dockerを活用してRailsの環境構築を行ったので、その備忘録としてこの記事をまとめました。

自分のステータスは以下の通りです

- 仮想環境を使うと環境構築が楽になると記事で読んだことがある。
- Dockerという名前を聞いたことがあるが、実際に使ったことはない。

という状態で、ずっと学習したいと思っていましたが、なかなか手がつけられませんでした。

- RailsはProgateを3周し、基本を押さえたため、自分の手元で開発を進めたい。
- 環境構築でまた足踏みするのは避けたい。
- せっかくなのでDockerも合わせて勉強してみたい。

という考えで学習を始めました。ほぼ自分のメモ書きとして本記事を作成していますが、どなたかの参考になれば幸いです。

## 仮想環境とは
仮想環境とは、パソコンやサーバーなど1つのハードウェア上で、仮想的に構築された別の環境のことです。言い換えれば、コンピューターの中に「もう1つのコンピューター」を作り出すようなイメージです。

仮想環境を利用することで、開発環境を本体のPCとは独立して管理できるため、トラブルの原因を切り分けやすくなります。

## Docker
概要をとりまとめると以下の通りです。
- コンテナ型仮想環境を作成、実行、管理するためのプラットフォーム。
- Dockerのソフトウェアを使って素早くコンテナを起動し、色々なアプリケーションを実行することができる。
- Dockerの設定ファイルを共有すれば、異なる環境（PCやサーバー）で簡単に仮想環境を再現できる。

例えば、Rubyのアプリケーションを活用したい場合は、Rubyがインストールされたコンテナを起動すれば、即座にRubyアプリケーションを実行して動作を確認することができます。このように、用途に合わせてコンテナを起動すれば、様々なアプリケーションを実行できるのが特徴です。

### メリット

- プログラムの実行環境を素早く立ち上げることができる。
- PCで開発したプログラムを、サーバーで動かす場合も差異がうまれにくく、トラブルになりにくい。
- 設定ファイルを共有することで、メンバー間で同じ環境を立ち上げることができる。
- 仮想環境内にパッケージをインストールするだけなので、PCに直にインストールする必要がないため、PCの環境をごちゃごちゃ汚さずに済む。

### 用語
#### Dockerイメージ
Dockerコンテナを作成するための雛形となるものです。アプリケーションやライブラリなど、実行に必要なもの一式をまとめています。完成したアプリケーションをDockerイメージとして保存し、別のサーバーに移すことで、同じ環境を再現することができます。

#### Dockerコンテナ
Dockerイメージを元に作成される仮想環境のことです。単に「コンテナ」と呼ばれることもあります。イメージから何度でも同じコンテナを作成できるため、開発やテストの効率が向上します。

勉強になった記事を紹介します。

https://qiita.com/Sicut_study/items/4f301d000ecee98e78c9



## 環境構築
全体の流れは以下の通りです。
- Railsアプリケーションのベースを作成
- Railsアプリケーションを実行するためのDockerfileを作成
- docker composeで開発環境を構築
- docker composeコマンドによる環境の起動

### Railsアプリケーションのベースを作成
#### Ruby3.2.2がインストールされたコンテナを起動してシェルを起動
任意のディレクトリ(今回は`rails-practice`)に移動し、以下のコマンドを実行します。これはDockerを使用して Ruby の Alpine Linux ベースイメージをもとに、コンテナを作成しコマンド起動してます。
```bash:bash
docker run --rm -ti -v ./rails-practice:/app ruby:3.2.2-alpine sh
```
コマンド構成は下記の通りです。

`docker run`
新しい Docker コンテナを作成して実行します。

`--rm`
コンテナの実行が終了した際に、コンテナを自動的に削除します。一時的な作業に便利です。

`-ti`
インタラクティブモードを有効にし、標準入力を開いたままにします。これにより、コンテナ内でコマンドを入力して操作できます。

`-v ./rails-practice:/app`
ローカルディレクトリ `./rails-practice` をコンテナ内の /app ディレクトリにマウントします。これにより、ローカルのファイルとコンテナ内のファイルを同期させることが可能です。

`ruby:3.2.2-alpine`  
Ruby 3.2.2 を含む Alpine Linux ベースの軽量イメージを使用します。

`sh`
コンテナ内でシェル (sh) を起動します。この状態でコンテナ内を操作できます。

`#`（プロンプト）が表示されていると思います。これは、上記コマンドでシェルを起動しているため、現在コンテナに繋がっている状態です。コマンドを実行するとLinuxコンテナでのコマンド実行を意味します。

#### Railsでアプリケーションを作成する際に必要なパッケージのインストール
起動しているシェルに以下のコマンドを実行します。これは、Railsに必要なパッケージのインストールをしています。
```bash:bash
apk update
apk add git g++ make mysql-dev
```
#### Railsのインストール
RubyGemシステム（gemそのもの）のアップデートし、Railsのバージョンを指定しインストールします。
```bash:bash
gem update --system
gem install rails -v 7.0.6
```

#### プロジェクト作成
以下の通り Railsコマンドを実行し、入力したアプリケーション名と同名のフォルダが作成され、その中に開発に必要なフォルダやファイルが用意されます。
```bash:bash
rails new /app
```

```bash:bash
ls -la /app/
```
上記コマンドで、コンテナ内に作成されたフォルダ構成を確認することができます。 

また、このコンテナ内のフォルダと現在自分がいるカレントディレクトリ（`rails-practice`）は同期されています。これは、コンテナ作成時に`-v ./rails-practice:/app`を実行し、マウントしているためです。

ここまででRailsを動かすための土台部分が完成です。

### Railsアプリケーションを実行するためのDockerfileを作成
実は、手動で実装した上記コマンドは、`dockerfile`というものを作れば、今までの作業を全てスクリプト化し、セットアップすることが可能です。スクリプト化することにより、チーム内や別の環境で同じ構成を簡単に再現できます。

上記コマンドを`dockerfile`に書き直すと以下の通りです。

```dockerfile:dockerfile
# ベースとして使用するイメージ名（DockerHub：公式からダウンロードされる）
FROM ruby:3.2.2-alpine
 
# 利用可能なパッケージのリストを更新するコマンドを実行
RUN apk update
 
# パッケージをインストールするコマンドを実行
RUN apk add g++ make mysql-dev tzdata gcompat
 
# コンテナを起動した時の作業ディレクトリを/appにする
WORKDIR /app
 
# PC上のGemfile を .（/app）にコピー
COPY Gemfile .
COPY Gemfile.lock .
 
# bundle installでGemfileに記述されているgemをインストール
RUN bundle install
```
```ruby:Gemfile
source 'https://rubygems.org'
gem 'rails', '7.0.6'
```

`docker build`でイメージを作成し、`docker run`で命令（`FROM`,`RUN`など）が実行され、Railsの構築は完了です。 
ですが、まだRailを動かすことができません。なぜなら、RailsにDBが接続されていないためです。次回手順でDBと接続作業を実施します。

### docker composeで開発環境を構築
上述の通り、Railsのコンテナのみではアプリケーションとして成立していないため、DBとの接続が必要です。そこで活用するのが、`docker compose`です。

`docker compose`は、複数のDockerコンテナを定義、接続し、一括管理するツールです。
設定ファイル`docker-compose.yml`を用いることで、サービス、ネットワーク、マウントの設定を一元管理できます。

```docker-compose.yml
version: '3'
services:
  web:
    build: .
    command: sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/app
    ports:
      - 3000:3000
    depends_on:
      - db
  db:
    image: mysql:8.0
    volumes:
      - db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
volumes:
  db-volume:
```

上記は、RailsアプリケーションとMySQLデータベースの連携を簡単に管理する設定です。以下に各部分の説明を簡潔にまとめます。

1. バージョン指定
`version: '3'`
Docker Composeのバージョンを指定。
  
2. servicesセクション
```yml
web:
  build: .
  command: sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
  volumes:
    - .:/app
  ports:
    - 3000:3000
  depends_on:
    - db
```
`build: .`
現在のディレクトリにあるDockerfileを使ってRailsアプリ用のイメージをビルドします。

`command`
作成したコンテナに対して、どんなコマンドを実行するのか指定します。今回は、Railsサーバー起動コマンドを指定し、サーバーのPIDファイ（tmp/pids/server.pid）を削除してからサーバーを起動します。

`volumes.`
現在のディレクトリ（.）をコンテナの/appにマウントしてます。これにより、ローカルで編集したRailsコードが即座にコンテナ内で反映されます。

`ports`
コンテナのポート3000をホストのポート3000に公開。これにより、ブラウザからアクセスすることができます。

`depends_on`
dbサービス（MySQLコンテナ）に依存関係を持たせます。MySQLが準備される前にRailsが起動しないようにしております。


```yml
db:
  image: mysql:8.0
  volumes:
    - db-volume:/var/lib/mysql
  environment:
    MYSQL_ROOT_PASSWORD: password
```
`image`
MySQL 8.0の公式イメージを使用します。

`volumes`
db-volume:/var/lib/mysql:永続化ストレージを設定します。MySQLデータがコンテナ停止後も保持されます。

`environment`
環境変数でMySQLの設定を指定します。今回は、MySQLのルートユーザーのパスワードを指定。

3.`volumes`セクション
```yml
volumes:
  db-volume:
```
`db-volume`
コンテナ外にデータを保存したいため、ボリュームを新規作成します。これにより、Dockerの管理下のフォルダとして自動で作成されるため、コンテナを削除してもDBに影響を及ぼしません。

### docker composeコマンドによる環境の起動
以上より、Railsの環境構築をする準備がととのったため、環境の起動をします。
```bash:bash
docker compose build
```
これにより、docker-compose.ymlに定義したbuildの定義に基づいてDockerイメージがビルドされます。


```bash:bash
docker image ls
>>rails-practiceが作成
```
Dockerイメージのリストを表示します。特別名前を指定しない限り、イメージ名は、フォルダ名である”rails-practice”とサービス名である`web`という名前に基づいてイメージ名が自動的に決定されます。

```bash:bash
docker compose up
```
docker-compose.ymlに定義された内容に基づいて、コンテナを起動されました。ブラウザで`localhost:3000`を送信すると無事Railsの初期画面が表示されます。

以上より、`Gemfile``docekerfile``docker-compose.yml`があればRailsの環境構築は完了です。

![スクリーンショット 2024-11-23 22.43.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3838211/5874cb07-3107-e2e0-2c03-db70fc61b81d.png)

#### 補足
下記の通り、`config`フォルダにある`database.yml`ファイルのDB接続先を指定する必要があります。

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

```bash:bash
docker compose exec web rails db:create
```
 `web`サービスのコンテナ上でdbを作成するコマンドを実行します。

 ## 最後に
 今回、Dockerを使ってRailsの開発環境を構築する手順を学びました。仮想環境の概念からDockerの仕組み、そしてRailsとMySQLを組み合わせた環境を作り上げるプロセスを経験することで、これまで苦手だった環境構築に対する不安が少し解消されたように感じます。

特に、Dockerを活用することで「一度設定すれば、いつでもどこでも同じ環境を再現できる」便利さを実感しました。開発環境が安定することで、本来の目的であるアプリケーション開発に集中できるようになります。この学びを活かして、次は実際のアプリケーション開発に挑戦していきたいと思います。

この記事は私自身の備忘録としてまとめたものですが、同じように環境構築でつまずいている方や、Dockerを初めて学ぼうとされている方の一助になれば幸いです。

今後も学習を続け、さらに技術力を高めていきたいと思います。それでは、最後までお読みいただきありがとうございました！