はじめに
アプリ構成を
- 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
作業内容
- ディレクトリ/ファイルの作成
- RailsのDocker環境を構築する
- 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追跡を除外させます。
.env
.env
.envでは、docker-composeに渡す環境変数の値を入力します。
ここでは、下記の意図で定めています。
環境変数 | 用途 | |
---|---|---|
1 | WORKDIR | back/frontコンテナの作業ディレクトリ名 |
2 | MYSQL_ROOT_PASSWORD | ・mysqlコンテナに登録するパスワード ・railsコンテナがmysqlコンテナに接続時に用いるパスワード |
WORKDIR=app
MYSQL_ROOT_PASSWORD=mypassword
docker-compose.yml
次に、複数コンテナをまとめるdocker-compose.ymlを編集します。
MySQLコンテナ/Railsコンテナを先に設定します。
(Vueコンテナは次章で設定予定)
.envファイルから値を受け取って環境変数に登録されていることを
念頭に置きながら理解していきます。
以下の通り、コメントで補足しています。
# 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を
自動的に管理してくれるものなので、個人では何も編集しません。
source 'https://rubygems.org'
gem 'rails', '~> 6.0.4'
## 何も記入しない
Dockerfile
続いて、Railsコンテナのイメージとなる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に戻ります。
#!/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は中身が上書きされています。
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に設定しています。
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
と入力して
動作を確認します。
上記のように開発サーバーの画面が表示されていれば成功です。
3. VueのDocker環境を構築する
では、次はVueの環境を構築します。
編集するファイルはdocker-compose.ymlとDockerfileです。
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
同様にコメントで解説しています。
# 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コンテナ内でコマンドを実行します。
# プロジェクトを生成する
% 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サーバー側のログに出ていたので、下記記事を参考に編集しました。
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/
を入力して
下記画面が表示されれば成功です。
これで開発環境の構築が終わりです!
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に変えました。
ただし、使いこなせるかが心配であります…笑
長い記事となってしまいましたが、
最後までお読み頂き、ありがとうございました。