Rails & Nuxt.jsのDocker環境をalpineイメージで構築する

Ruby on Rails、Nuxt.js、MySQLのDocker環境を作成します。
Rails、Nuxtのalpine環境の構築手順はそれぞれだと多くあるのですが、まとまったものがあまり ない 見つからなかったので、復習を兼ねてポストを作成します。


準備

ディレクトリ作成

作業ディレクトリは任意です。

$ NEW_APP=rails-nuxt-app #任意のアプリ名
$ mkdir ${NEW_APP}
$ cd ${NEW_APP}
$ mkdir ./backend ./frontend

backend はRails用、frontend はNuxt用のディレクトリです。

まずは下記のファイルを修正していきます。

.
├── backend
│   ├── Dockerfile
│   ├── Gemfile
│   └── Gemfile.lock

├── frontend
│   └── Dockerfile

├── docker-compose.yml
└── .env

docker-compose.yml

.env

docker-compose.ymlで参照する環境変数を記載します。
ここではMySQLのrootパスワード、RailsおよびNuxt環境のホスト、ポート番号のみ定義します。
RailsとNuxtは、共にデフォルトのポートが 3000 番なので、後の利便性のためにいずれかを変えておきます。
(本記事ではNuxt側を 8080 に変更)

MYSQL_ROOT_PASSWORD=password

BACKEND_HOST=0.0.0.0
BACKEND_PORT=3000

FRONTEND_HOST=0.0.0.0
FRONTEND_PORT=8080

./docker-compose.yml

.envで定義した変数を参照しています。
docker-compose.ymlの environment、 Dockerfileの ENV で同じ環境変数が定義されていた場合は、前者が使用されます。
(本記事ではDockerfile単体でもイメージ作成できるように環境変数の記載を残していますが、docker-compose.ymlに定義されていれば問題ありません)

下記はDockerボリュームを作成します。

  • mysqlのdatadir
  • rubyのgem_home
  • nodeのnode_modules
version: '3'
services:
db:
image: mysql:5.7.27
restart: always
volumes:
- db-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
backend:
build: ./backend
ports:
- ${BACKEND_PORT}:3000
command: /bin/sh -c "rm -f /app/tmp/pids/server.pid && bundle exec rails s -b ${BACKEND_HOST}"
volumes:
- ./backend:/app
- backend-bundle:/usr/local/bundle
environment:
- HOST=${BACKEND_HOST}
- PORT=${BACKEND_PORT}
depends_on:
- db
tty: true
stdin_open: true
frontend:
build: ./frontend
ports:
- ${FRONTEND_PORT}:8080
command: /bin/sh -c "yarn dev"
volumes:
- ./frontend:/app
- frontend-node_modules:/app/node_modules
environment:
- HOST=${FRONTEND_HOST}
- PORT=${FRONTEND_PORT}
tty: true
volumes:
db-data:
backend-bundle:
frontend-node_modules:

backend

Rails環境構築のためのファイルを準備します。

./backend/Gemfile

Railsのバージョンのみ指定しておきます。

source 'https://rubygems.org'

gem 'rails', '5.2.3'

./backend/Gemfile.lock

空ファイルをtouchしておけばOKです。

./backend/Dockerfile

Alpine Linuxのパッケージは最低限のものだけインストールします。
開発を進めるうちにgemのインストールで依存エラーが発生した場合には、不足パッケージを都度追加しましょう。

FROM ruby:2.6.3-alpine

ENV RUNTIME_PACKAGES "mysql-client mysql-dev tzdata nodejs"
ENV DEV_PACKAGES "build-base curl-dev"
ENV APP_HOME /app
ENV TZ Asia/Tokyo

ENV HOST 0.0.0.0
ENV PORT 3000

WORKDIR ${APP_HOME}
ADD Gemfile ${APP_HOME}/Gemfile
ADD Gemfile.lock ${APP_HOME}/Gemfile.lock

RUN apk update \
&& apk upgrade \
&& apk add --update --no-cache ${RUNTIME_PACKAGES} \
&& apk add --update --no-cache --virtual=.build-dependencies ${DEV_PACKAGES} \
&& bundle install -j4 \
&& rm -rf /usr/local/bundle/cache/*.gem \
&& find /usr/local/bundle/gems/ -name "*.c" -delete \
&& find /usr/local/bundle/gems/ -name "*.o" -delete \
&& apk del --purge .build-dependencies \
&& rm -rf /var/cache/apk/*

COPY . ${APP_HOME}

EXPOSE ${PORT}

CMD ["rails", "server", "-b", ${HOST}]

frontend

./frontend/Dockerfile

FROM node:12.9.0-alpine

ENV APP_HOME /app
ENV PATH ${APP_HOME}/node_modules/.bin:$PATH
ENV TZ Asia/Tokyo

ENV HOST 0.0.0.0
ENV PORT 8080

WORKDIR ${APP_HOME}
ADD . ${APP_HOME}

RUN apk update \
&& apk upgrade \
&& yarn install \
&& rm -rf /var/cache/apk/*

EXPOSE ${PORT}

CMD ["yarn", "dev"]

アプリケーション作成

Rails、Nuxt環境にプロジェクトを作成します。
docker-compose run を実行したタイミングで、それぞれのDockerイメージがbuildされ、さらにコンテナが立ち上がります。

--no-deps オプションで、docker-compose.ymlで depends_on & links 指定するサービスが起動しないようにします。
--rm オプションで、アプリケーション作成を終えたコンテナが自動的に削除されるようにします。

backend

アプリケーション作成

rails new でRailsアプリケーションを作成します。
--api オプションでAPIモードにしていますが、不要な方は外してください。

$ docker-compose run --no-deps --rm backend rails new . --force --api --database=mysql --skip-bundle

DB接続のため、下記のファイルを修正します。

.
└── backend
    ├── config
    │   └── database.yml
    ├── Gemfile
    └── .env

./backend/.env

docker-compose.ymlで参照している MYSQL_ROOT_PASSWORD と同じもの設定します。

MYSQL_ROOT_PASSWORD=password

./backend/Gemfile

.envから環境変数を読み込むdotenv-railsというgemを追加します。

## (中略) ##

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]

gem "dotenv-rails" #added
end

## (中略) ##

./backend/config/database.yml

DBへのアクセスに使用するパスワードを、環境変数から取得します。

## (中略) ##

default: &default
adapter: mysql2
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: <%= ENV.fetch("MYSQL_ROOT_PASSWORD") { '' } %> #環境変数を参照するように修正
host: db #localhostからdocker-compose.ymlのサービス名に修正

## (中略) ##

frontend

アプリケーション作成

npx でNuxtアプリケーションを作成します。
後から追加/変更できるので、このタイミングではEnterキー連打でOKです。

$ docker-compose run --rm frontend npx create-nuxt-app .

## (中略) ##

create-nuxt-app v2.10.0
✨ Generating Nuxt.js project in .
? Project name #アプリ名 <Enter>
? Project description #任意 <Enter>
? Author name #任意 <Enter>
? Choose the package manager #Yarn <Enter>
? Choose UI framework #None <Enter>
? Choose custom server framework #None <Enter>
? Choose Nuxt.js modules #(Nothing) <Enter>
? Choose linting tools #(Nothing) <Enter>
? Choose test framework #None <Enter>
? Choose rendering mode #Universal (SSR) <Enter>
? Choose development tools #(Nothing) <Enter>

Dockerイメージ作成

アプリケーション作成時にできたDockerボリュームは削除しておきます。

$ docker-compose down --volume
# もしくは docker volume rm ボリューム名

各ファイルを修正した状態で、Dockerイメージをビルドします。

$ docker-compose build

docker-compose.ymlで build を指定しているbackendとfrontendのイメージが作成されたことを確認します。

$ docker images --format "{{.Repository}}\t{{.CreatedSince}}" ${NEW_APP}*
rails-nuxt-app_frontend About a minutes ago
rails-nuxt-app_backend About a minutes ago

Hello World

最後にDockerコンテナを起動し、Rails、NuxtアプリケーションのHelloWorldを確認します、

docker-compose.ymlで定義したサービスを -d オプション(デタッチモード)でバックグラウンド起動します。

$ docker-compose up -d

プロセスが立ち上がっていることを確認します。

$ docker-compose ps
Name Command State Ports
---------------------------------------------------------------------------------------
rails-nuxt-app_backend_1 /bin/sh -c rm -f /app/tmp/ ... Up 0.0.0.0:3000->3000/tcp
rails-nuxt-app_db_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
rails-nuxt-app_frontend_1 docker-entrypoint.sh /bin/ ... Up 0.0.0.0:8080->8080/tcp

失敗している場合は docker-compose logs などで原因を探りましょう。

backend

RailsアプリケーションのDBを作成します。

$ docker-compose exec backend rails db:create
Created database 'app_development'
Created database 'app_test'

ブラウザで http://localhost:3000/ を開きます。
rails-helloworld

frontend

ブラウザで http://localhost:8080/ を開きます。
nuxt-helloworld


お疲れさまでした。
次回は GraphQL の導入について投稿したいと思います。