LoginSignup
19
18

More than 1 year has passed since last update.

Rails × Vue をdocker-composeで環境構築する

Last updated at Posted at 2022-02-04

はじめに

アプリ構成を

  • Backend: Rails
  • Frontend: Vue.js

でDockerで環境構築した時の備忘録です。

使用技術

  • Rails: 6.0.4
  • ruby: 2.7.5
  • MySQL: 8.0.28
  • Vue: 3
  • node: 16.13.2
  • ブロジェクト作成ツール: Vite

作業内容

  1. ディレクトリ/ファイルの作成
  2. RailsのDocker環境を構築する
  3. VueのDocker環境を構築する

1. ディレクトリ/ファイルの作成

ディレクトリ構造は以下の通りです。

  • rootディレクトリ
  • docker-compose.yml: 複数コンテナの設定
  • .env: 環境変数の管理
  • .gitignore: Gitで追跡させないファイルの設定
  • backend: Rails構築のためのファイル群
  • frontend: Vue構築のためのファイル群
ターミナル

% tree root_directory
.
├── docker-compose.yml
├── .env
├── .gitignore
├── backend
│   ├── Dockerfile
│   ├── Gemfile
│   ├── Gemfile.lock
│   ├── entrypoint.sh
├── frontend
     └── Dockerfile


2. RailsのDocker環境を構築する

以下の通り、5つのファイルを作成/編集します。

  • .gitignore
  • .env
  • docker-compose.yml
  • backend/Dockerfile
  • frontend/Dockerfile

以降は、コードを書いていくので
まず、作業ブランチを切っておく。

ターミナル

% git checkout -b Build_the_environment

% git branch

.gitignore

環境変数を管理する.envファイルをGit追跡を除外させます。

.gitignore

.env

.env

.envでは、docker-composeに渡す環境変数の値を入力します。

ここでは、下記の意図で定めています。

環境変数 用途
1 WORKDIR back/frontコンテナの作業ディレクトリ名
2 MYSQL_ROOT_PASSWORD ・mysqlコンテナに登録するパスワード
・railsコンテナがmysqlコンテナに接続時に用いるパスワード
.env

WORKDIR=app
MYSQL_ROOT_PASSWORD=mypassword

docker-compose.yml

次に、複数コンテナをまとめるdocker-compose.ymlを編集します。

MySQLコンテナ/Railsコンテナを先に設定します。
(Vueコンテナは次章で設定予定)

.envファイルから値を受け取って環境変数に登録されていることを
念頭に置きながら理解していきます。

以下の通り、コメントで補足しています。

docker-compose.yml

# https://docs.docker.com/compose/compose-file/compose-versioning/
version: '3.8'

services:

  db:
    # DockerHubにあるmysql8.0のイメージを使用
    image: mysql:8.0.28
    # MySQL8.0以降の認証方式に元に戻す設定
    command: --default-authentication-plugin=mysql_native_password
    # dbディレクトリをホスト側に作成してコンテナ側と同期
    volumes: 
      - "./db:/var/lib/mysql"
    # .envの環境変数を展開してMYSQLコンテナのパスワードを登録
    environment:
      MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD

  backend:
    # ./backendにあるDockerfileをもとにイメージを生成する
    build:
      context: ./backend
      # .envの環境変数を展開して、WORKDIRという引数を登録し、backend/Dockerfileに渡す
      args:
        WORKDIR: $WORKDIR
    # ホストのRailsファイルとBack用のコンテナを同期
    volumes:
      - "./backend:/$WORKDIR"
    # .envの環境変数を展開して、Railsの環境変数MYSQL_ROOT_PASSWORDを登録
    environment:
      MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
    # ホストの8000番ポートをコンテナの3000番ポートに繋ぐ
    ports:
      - "8000:3000"
    # dbコンテナ起動後にbackendコンテナを起動
    depends_on:
      - db

なお、環境変数が正しく展開されているかは
下記コマンドでチェックできますので、確認しておきましょう。

ターミナル

% docker-compose config

Gemfile/Gemfile.lock

GemfileとGemfile.lockの2つをbackendディレクトリに用意します。

Gemfileはrails newコマンドで用いるファイルです。
コマンド実行後はファイルは上書きされてrails構築に必要なGem一式が揃います。
ここではバージョンは6.0.4で指定しています。

Gemfile.lockはGemライブラリのバージョン管理を行うものです。
bundle installコマンド実行後にインストールされたGemを
自動的に管理してくれるものなので、個人では何も編集しません。

Gemfile

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

Gemfile.lock
## 何も記入しない

Dockerfile

続いて、RailsコンテナのイメージとなるDockerfileです。

同様にコメントで補足します。

backend/Dockerfile

# DockerHubから軽量のalpineイメージを選択する
FROM ruby:2.7.5-alpine

# docker-compose.ymlからWORKDIRの値を受け取る
ARG WORKDIR

# パッケージを永続使用/一時的使用の2つの変数にまとめる
ARG RUNTIME_PACKAGES="bash imagemagick nodejs yarn tzdata mysql-dev mysql-client git less"
ARG DEV_PACKAGES="build-base curl-dev"

# docker-composeで受け取ったWORKDIRを展開して、RailsコンテナのHOMEという環境変数を設定する(ホームディレクトリを設定)
ENV HOME=/${WORKDIR}

# HOMEを展開して、WORKDIRを設定する(作業ディレクトリをホームディレクトリと統一する)
WORKDIR ${HOME}

# ホストにあるGemfileとGemfile.lockをコンテナにコピーする
COPY Gemfile* ./

# パッケージのインストール & 削除
RUN apk update && \
    apk upgrade && \
    apk add --no-cache ${RUNTIME_PACKAGES} && \
    apk add --virtual build-dependencies --no-cache ${DEV_PACKAGES} && \
    bundle install -j4 && \
    apk del build-dependencies

# ホストのファイル一式をコンテナにコピーする
COPY . ./

# CMD実行前にentrypoint.shを通す
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

# 開発用サーバーの実行
CMD ["rails", "server", "-b", "0.0.0.0"]

entrypoint.sh

entrypoint.shはコンテナ生成前に実行するスクリプトです。

サーバー起動前にエラー発生の可能性であるプロセスを削除します。

処理が終了後は、DockerfileのCMDに戻ります。

backend/entrypoint.sh

#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /app/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

Railsプロジェクトを作成する

では、準備は整いましたので、Railsプロジェクトを作成して
開発用サーバーの起動まで確認しましょう。

ターミナル

# イメージを生成する
% docker-compose build

# backendコンテナを起動させてRailsアプリを生成する
% docker-compose run --rm backend rails new . -f -B -d mysql --api --skip-test --skip-turbolinks

### rails new オプション補足 ###
# -f   既にあるファイルを上書き(Gemfile/Gemfile.lock)
# -B   bundle installコマンドを実行しない
# -d   データベースを指定(デフォルトはsqlite)
# --api   APIモードで作成する
# --skip-test   minitestを作成しない
# --skip-turbolinks   turbolinksを作成しない

ターミナルで上記コマンド実行後には、Railsアプリに関わるファイル一式が自動生成されているはずです。

同時にGemfileは中身が上書きされています。

backend/Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.7.5'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main'
gem 'rails', '~> 6.0.4', '>= 6.0.4.4'
# Use mysql as the database for Active Record
gem 'mysql2', '>= 0.4.4'
# Use Puma as the app server
gem 'puma', '~> 4.1'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
# gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Active Storage variant
# gem 'image_processing', '~> 1.2'

# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.2', require: false

# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
# gem 'rack-cors'

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  gem 'listen', '~> 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

database.yml

ここまででプロジェクトは作成されましたが、
RailsからMySQLへの接続設定が不十分な状態です。

そこで、DB接続に関わるdatabase.ymlを編集します。

具体的に言うと、
Railsコンテナがrais db:*** コマンド実行時に
MySQLコンテナに接続する為に用いる設定です。

なお、MySQLのパスワードは秘匿情報のために
.env -> docker-compose.yml -> railsコンテナの環境変数の順で
値を橋渡しています。

最終的に環境変数MYSQL_ROOT_PASSWORDを展開して
passwordに設定しています。

backend/config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  socket: /tmp/mysql.sock
  # 接続先を別コンテナのdbに設定
  host: db
  # MySQLのrootユーザーを使用
  username: root
  # コンテナ内の環境変数を展開した値をpasswordに設定
  password: <%= ENV['MYSQL_ROOT_PASSWORD'] %>


development:
  <<: *default
  database: プロジェクト名_development

動作検証

では、Railsサーバーが起動するか検証してみましょう。

ターミナル

# 上書きされたGemfileをもとにイメージを改めて生成する
% docker-compose build

# backendコンテナを起動させて新規データベースを作成する
% docker-compose run --rm backend rails db:create

# バックグラウンドでRailサーバーを起動させる
% docker-compose up

ここまでで、ブラウザにhttp://localhost:8000と入力して
動作を確認します。

スクリーンショット 2022-02-04 16.56.30.png

上記のように開発サーバーの画面が表示されていれば成功です。

3. VueのDocker環境を構築する

では、次はVueの環境を構築します。

編集するファイルはdocker-compose.ymlとDockerfileです。

docker-compose.yml

以下の通り、コメントで説明しています。

docker-compose.yml

--以下を追加する--

  frontend:
    # frontendにあるDockerfileをもとにイメージを生成する
    build:
      context: ./frontend
      # .envの環境変数を展開して、WORKDIRという引数を登録し、frontend/Dockerfileに渡す
      args:
        WORKDIR: $WORKDIR
    # frontendディレクトリにあるホストのファイルとコンテナを同期
    volumes:
      - "./frontend:/$WORKDIR"
    # ホストの3000番ポートをコンテナの3000番ポートに繋ぐ
    ports:
      - "3000:3000"
    # backendコンテナ起動後にfrontendコンテナを起動
    depends_on:
      - backend

Dockerfile

同様にコメントで解説しています。

frontend/Dockerfile

# nodeのstable版を公式ページから確認し、DockerHubからalpineベースのものを指定
FROM node:16.13.2-alpine

# docker-compose.ymlからWORKDIRの値を受け取る
ARG WORKDIR

# コンテナのホームディレクトリを設定する
ENV HOME=/${WORKDIR}

# コマンド実行する作業ディレクトリの設定する
WORKDIR ${HOME}

# Alpineのリポジトリから最新インデックスを取得し、npm自体も最新版に更新する
RUN apk update && npm install -g npm

# Viteで開発サーバーを起動する
CMD ["npm", "run", "dev"]

Vueプロジェクトを作成する

では準備が整いましたので、Viteを用いてプロジェクトを作成しましょう。

ターミナル

# イメージの生成
% docker-compose build

# 生成したイメージをもとにashシェルでコンテナに接続する
% docker-compose run frontend ash

以降は、frontendコンテナ内でコマンドを実行します。

ターミナル(frontendコンテナ)

# プロジェクトを生成する
% npm init vite@latest

 ↓

# 質問に答える
Need to install the following packages:
  create-vite@latest
Ok to proceed? (y) y
✔ Project name: … vite-project
✔ Select a framework: › vue
✔ Select a variant: › vue

Scaffolding project in /app/vite-project...

Done. Now run:

  cd vite-project
  npm install
  npm run dev

# コンテナ内のディレクトリ/ファイルを確認
% ls -a

# 生成されたファイル群を移動させて、要らないvite-projectディレクトリを削除
% mv vite-project/* /app/
% mv vite-project/.gitignore /app/
% mv vite-project/.vscode /app/
% rmdir vite-project

# package.jsonをもとにライブラリをインストール
% npm install

# frontendコンテナから抜ける
% exit

このままだと、ブラウザからコンテナにアクセスできないため
Viteの設定ファイルを編集します。

はじめは、当設定を行わずにサーバーを起動させたのですが
Network: use --host to exposeというメッセージが
Vueサーバー側のログに出ていたので、下記記事を参考に編集しました。

frontend/vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  // 追加
  server:{
    host: true
  }
})

動作検証

それでは、コンテナを起動させましょう。

ターミナル

# docker-composeでコンテナを起動させる
% docker-compose up 


ブラウザにhttp://localhost:3000/を入力して
下記画面が表示されれば成功です。

スクリーンショット 2022-02-05 7.54.15.png

これで開発環境の構築が終わりです!

CSSフレームワーク

公式ページの手順に沿って作業を行えば、エラーなく適用できました。

Vue公式ライブラリ

いずれもnpmコマンドでインストールしましたが、同じくエラーありませんでした。

src以下のディレクトリ構造は、VueCLIを参考に下記としました。

ターミナル

% tree frontend/src 
frontend/src
├── App.vue
├── main.js
├── assets
│   └── index.css
├── components
│   └── SignupForm.vue
├── router
│   └── index.js
├── store
│   └── index.js
└── views
    ├── Home.vue
    ├── Vuex.vue
    └── Welcome.vue

参考記事

参考動画

終わりに

少し前にVueCLIでもプロジェクトを生成したんですが
だんだん速度が遅くなってきたので、思い切ってViteに変えました。

ただし、使いこなせるかが心配であります…笑

長い記事となってしまいましたが、
最後までお読み頂き、ありがとうございました。

19
18
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
18