DockerでRuby on Rails + Nuxt.js環境を作る

Ruby on Rails+Nuxt.jsの環境をDockerで作成するための手順メモ。
環境構築とAPI実装&呼び出し方法について。

開発環境

  • MacOS Ventura(バージョン13.5)
  • Docker Compose version v2.20.2-desktop.1
  • Ruby 3.2.0
  • Rails 7.0.7
  • PostgreSQL 12.16
  • Node 16.15.1
  • Nuxt.js 2.15.8

ディレクトリとファイルを作成

以下のディレクトリ構成でファイルを作成します。

MyApp
├─ web
│  ├─ Dockerfile
│  ├─ Gemfile
│  └─ Gemfile.lock
├─ front
│  └─ Dockerfile
├─ docker-compose.yml
└─ .git
# -----------------------------------
# Ruby on Rails環境構築用のDockerfile
# -----------------------------------
# ベースにするイメージ
FROM ruby:3.2.0
# RailsのインストールやDBへの接続に必要なパッケージをインストール(今回はPostgreSQLを使用する)
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs postgresql-client
# コンテナ内にアプリ用のディレクトリを作成
RUN mkdir /MyApp
# 作成したディレクトリを作業用ディレクトリとして設定
WORKDIR /MyApp
# ローカルのGemfileとGemfile.lockをコンテナに配置
ADD Gemfile /MyApp/Gemfile
ADD Gemfile.lock /MyApp/Gemfile.lock
# コンテナ内にコピーしたGemfileのbundle install
RUN bundle install
# ローカルのファイルをコンテナに配置
COPY . /MyApp
source 'https://rubygems.org'
gem 'rails', '~> 7.0.7', '>= 7.0.7.2'
(空ファイル)
# -----------------------------------
# Nuxt.js環境構築用のDockerfile
# -----------------------------------
# ベースにするイメージ
FROM node:16-alpine3.14
# 作業用ディレクトリ
WORKDIR /var/www/html

# 必要なパッケージをインストール
RUN apk add --update \
    bash \
    curl
RUN npm update -g npm

# ネットワーク設定
EXPOSE 3000
ENV HOST 0.0.0.0
version: '3'

services:
  # PostgreSQL用のコンテナ
  db:
    # ベースとなるイメージ
    image: postgres:12-alpine
    # 環境変数
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    # ローカル側のポート番号:コンテナ側のポート番号
    ports:
      - 5432:5432
    # ボリューム(永続的に保存したいデータ)
    # * 保存したいディレクトリをマウントする方法
    #   「- ローカル側の同期させたいディレクトリ:コンテナ側の同期させたいディレクトリ」
    # * 名前付きボリュームを利用する方法
    #   「- ボリューム名:コンテナ側の保存させたいディレクトリ」
    #   (ボリューム名を末尾のvolumes(services等と同じ階層に定義)で指定する)
    volumes:
      - postgres_data:/var/lib/postgresql/data

  # Ruby on Rails用のコンテナ
  web:
    # 指定したディレクトリにあるDockerfileを使ってビルドする
    build: ./web
    # コンテナ起動時に実行されるコマンド
    # (起動していた場合は停止後に)rails serverを起動する
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    # ボリューム(永続的に保存したいデータ)
    volumes:
      - ./web:/MyApp
    # ローカル側のポート番号:コンテナ側のポート番号
    ports:
      - "3000:3000"
    # dbコンテナ起動後にwebコンテナを起動する
    depends_on:
      - db

  # Nuxt.js用のコンテナ
  nuxt:
    build: ./front
    command: bash -c "cd MyApp && yarn dev"
    volumes:
      - ./front:/var/www/html
    # web側とポートが被るので3001に変更
    ports:
      - "3001:3000"
    tty: true

volumes:
  postgres_data:

Docker操作コマンド

Dockerを操作するにはdocker-compose.ymlファイルがあるフォルダで以下のコマンドを実行します。

# イメージ作成
docker-compose build
# コンテナ作成
docker-compose create
# コンテナ起動
docker-compose start

# イメージ作成+コンテナ作成+コンテナ起動をまとめて実行
docker-compose up -d

# イメージ作成+コンテナ作成+コンテナ起動をまとめて実行(指定したサービスだけ起動)
docker-compose run [サービス名]
# 起動と同時にコマンド実行
docker-compose run [サービス名] [コマンド]

# コンテナ停止
docker-compose down

# コンテナの稼働状況を確認
docker-compose ps

# 起動中のコンテナでコマンド実行
docker-compose exec [サービス名] [コマンド]

Ruby on Railsプロジェクトを新規作成

以下のコマンドを実行してRuby on Railsのプロジェクトを新規作成します。

# コンテナが起動済みの場合は"run" -> "exec"で読み替える
# (フロント側もまとめて全体で管理したいのでここではgit管理の対象外としておく)
docker-compose run web rails new . --force --database=postgresql --skip-bundle --skip-git
 -> 追加されたファイルがローカル環境にも同期して作成される

# Gemfileが更新されているので、イメージを再作成
docker-compose build

続いて、データベースを作成します。

default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: user
  password: password
  host: db

development:
  <<: *default
  database: MyApp_development

test:
  <<: *default
  database: MyApp_test

production:
  <<: *default
  database: MyApp_production
  username: <%= ENV["POSTGRES_USER"] %>
  password: <%= ENV["POSTGRES_PASSWORD"] %>
# データベースを作成
docker-compose exec web rails db:create

http://localhost:3000にアクセスして、以下の画面が表示されればOK。

APIの実装

コントローラクラスを作成して、ルーティングを設定します。

# コントローラを作成
docker-compose exec -it web bash

# 以下、Dockerコンテナでの操作
rails g controller samples
cd app/controllers
mkdir api
cp samples_controller.rb api/
module Api
    class SamplesController < ApplicationController
        # CSRFエラー対策
        skip_before_action :verify_authenticity_token

        # サンプルデータを返す
        def sample
            render json: { status: 'SUCCESS', message: 'Get sample data', data: { sample: 'hogehoge' } }
        end
    end
end
Rails.application.routes.draw do
  namespace :api do
    get "samples" => "samples#sample"
  end
end
# 動作確認
curl http://localhost:3000/api/samples
 -> {"status":"SUCCESS","message":"Get sample data","data":{"sample":"hogehoge"}}

Nuxt.jsプロジェクトを新規作成

以下のコマンドを実行してNuxt.jsのプロジェクトを新規作成します。

# Dockerコンテナのシェルを起動
docker-compose exec -it nuxt sh

# 以下、Dockerコンテナでの操作
npx create-nuxt-app MyApp
もしくは
yarn create nuxt-app MyApp

# インストール時の設定はお好みで
? Project name: MyApp
? Programing language: TypeScript
? Package manager: Yarn
? UI framework: Buefy
? Template engine: Pug
? Nuxt.js modules: o Axios, x PWA, x Nuxt/Content
? Linting tools: o ESLint, o Prettier, x Lint staged files, x Styleling, x Commitlint
? Testing framework: Jest
? Rendering mode: Single Page App
? Deployment target: Server
? Development tools: x
? Continuous integration: None
? Version control system: None *全体でGit使うのでここでは指定しない

# 起動
cd MyApp
yarn dev

http://localhost:3001にアクセスして、以下の画面が表示されればOK。
※UI FrameworkでBuefy以外を選んだ場合は見た目は違うものになります。

API呼出し処理の実装

プロキシを設定します。

// Dockerコンテナから見たホストマシンのIPアドレスを取得(プロキシ設定用)
const { execSync } = require('child_process')
let hostIp = execSync("cat /etc/hosts | awk 'END{print $1}' | sed -e 's/[0-9]\+$/1/g'")
// 改行を削除して、IPアドレスの最後のセグメントを1にする(なぜか上記コマンドでできない・・・)
hostIp = String(hostIp).replace('\r', '').replace('\n', '').replace(/[0-9]+$/, '1')

export default {
  〜略〜
  modules: [
    '@nuxtjs/axios',
    '@nuxtjs/proxy',
  ],

  axios: {
    baseURL: '/',
  },

  proxy: {
    '/api': {
      target: 'http://' + hostIp + ':3000/'
    }
  },

  telemetry: false,
  〜略〜
}

画面を作成します。

<template>
    <div>
      <p>{{ sampleData.sample }}</p>
    </div>
</template>

<script>
export default {
    data: () => ({
        sampleData: ''
    }),

    created: function() {
        this.$axios.get('/api/samples')
        .then((res) => {
            this.sampleData = res.data.data
        })
        .catch((error) => {
            console.log(error)
        }
    }
}
</script>

http://localhost:3001/sampleにアクセスして、Rails側で設定した値(hogehoge)が表示されていれば成功です。

コメント

  1. hikari より:

    database.ymlを下記にしないとdocker-compose exec web rails db:createが失敗しますかと

    ・username: MyApp→user

タイトルとURLをコピーしました