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のインストールで依存エラーが発生した場合には、不足パッケージを都度追加しましょう。
面倒な場合は build-base を RUNTIME_PACKAGES に移しておけば一旦は大丈夫です。
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 or 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" #追加
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/ を開きます。

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

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