前提
Apple M1チップのMacBook Air(macOS Big Sur, 8GB)
構成
Server
Rails6.14 API mode
Mysql5.7
Front
Vue3/Nuxt3/TypeScript
この記事でやること
M1 macを使用して、Rails6.14 + Nuxt.js 3 の環境をDockerで作っていきます。
レポジトリもそれぞれAPIサーバーとフロントサーバーに分ける想定なので、ニコイチで作りたい方は
docker-compose.yml
を一つにしてよしなに対応お願いします。
また、できるだけ参考にした記事などは共有しますが漏れていた場合は追記しますのでご指摘ください。
動機
仕事ではdockerを使ってはいるものの自分で一からセットアップしたことがなかったせいで
結構つまづく部分が多かったので作ってみたかった + 備忘録的に書いておこうと思った次第です。
今回この構成でサービスを作る予定なので宣伝も兼ねて環境構築手順を共有していきます。
サービスができたらこの下あたりにでもリンクを貼るのでお暇な方はどうぞ。
いつになったらリリースするのかとかは聞かないでください笑
ここ⇨
Railsの環境構築
全体の構成などはこちらの記事を参考にしました。
自分の場合と異なり、こちらの記事ではdocker imageにaplineを、dbにpostgresを採用しているため多少の違いがあります。
alpineやpostgresを使用したい場合はこちらを参考にするといいかもです。
ちなみにalpineを採用するメリットは軽量化(リリース時間が短くなるなど)だと思うのですが以前pdf作成機能を作った時に
imagemagickなどが入っておらず苦労した覚えがあるため使用していません。
alpineの良し悪しに関する考察はこちらを参考にどうぞ
作業用ディレクトリを用意
ディレクトリ名などは各々好きに決めてください。
$ /Users/ユーザー名/workspace/rails-api
ディレクトリ構成
rails-api
└.env
└Dockerfile
└Gemfile
└Gemfile.lock
それでは一つずつ解説して行きます。
.envファイル
# commons
WORKDIR=rails-api <-ここをrootディレクトリ名と同じにする
CONTAINER_PORT=3000
FRONT_PORT=8080
API_PORT=3000
# db
MYSQL_ROOT_PASSWORD=password
環境変数が複数ある場合、.envという名前のファイルに環境変数のデフォルト値を設定することができます。 あるいはコマンドラインオプション--env-fileを使って環境変数ファイルへのパスを指定して利用することもできます。
公式にあるように、デフォルトで採用されている環境変数用のファイルです。
今回はこちらに環境変数を記載して行きます。
docker-compose.yml
version: '3'
services:
db:
image: mysql/mysql-server:5.7.28
container_name: db
environment:
MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
MYSQL_ROOT_HOST: '%' # コンテナ外からdbに接続するために記載
ports:
- "3306:3306"
# command: --default-authentication-plugin=mysql_native_password <- mysql8.0の場合に必要
api:
stdin_open: true
tty: true
build:
context: .
args:
WORKDIR: $WORKDIR
command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
environment:
MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
depends_on:
- db
ports:
- "$API_PORT:$CONTAINER_PORT"
volumes:
- .:/rails-api
注意すべきは以下2点です。
1 . MYSQL_ROOT_HOST: '%'
これはapiコンテナからdbコンテナに接続する場合に必要な設定になります。これを書かなかった場合、コンテナにログインしてmysqlを操作することはできますが、コンテナ外部から操作することができなくなります。
参考記事:
2 . command: --default-authentication-plugin=mysql_native_password
こちらはmysql8.0を使用したい場合に必要になる設定です。他記事をみていますとmy.confに書いている方もいますが、今回はより簡易な手法としてこちらを記載しておきます。
参考記事:
Dockerfile
FROM ruby:3.0.2
ARG WORKDIR
ENV HOME=/${WORKDIR} \
LANG=C.UTF-8 \
TZ=Asia/Tokyo
WORKDIR ${HOME}
COPY Gemfile* ./
RUN wget --quiet -O - /tmp/pubkey.gpg https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
echo 'deb http://dl.yarnpkg.com/debian/ stable main' > /etc/apt/sources.list.d/yarn.list
RUN set -x && apt-get update -y -qq && apt-get install -yq nodejs yarn
RUN bundle install
COPY . .
環境変数の設定に関しては上記の記事を参考にさせていただきました。
ARG
やENV
、${WORKDIR}
などは.env
ファイルから取得した環境変数をDockerfile、docker-compose.yml、コンテナで使用できるようにするためのものです。
詳細は上記の記事を読んでいただけると理解できると思いますので割愛します。
この記事ではパッケージマネージャーにapt-getを使用していますが、alpine環境を使用する場合はapkを使用する必要があるそうです。
Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'rails', '~> 6.1.4', '>= 6.1.4.4'
Gemfile.lock
こちらはからファイルを作成します。
手順
1 . まずは上で解説したディレクトリ構成でファイルを作成しましょう。
2 . Dockerfileを実行し、docker imageを作成します。
$ docker-compose build
3 . imageができたか確認します。
REPOSITORY TAG IMAGE ID CREATED SIZE
rails-api_api latest 0d08728fc697 26 hours ago 1.01GB
4 . コンテナを起動してrailsアプリを作成します。以下コマンドは2で作成したdocker imageからapiコンテナを起動してrails newするものです。ここでコンテナ内にrailsアプリができた場合は自分のホスト環境のrails-apiディレクトリ配下にもrailsアプリが作成されているはずです。
$ docker-compose run --rm api rails new . -f -B -d mysql --api
5 . アプリが作成できたら、自分のホスト環境のdatabase.ymlファイルを修正しコンテナ内のdbと接続できるようにします。
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: <%= ENV["MYSQL_ROOT_PASSWORD"] %>
host: db
6 . database.ymlを修正したらもう一度ビルドし直し、dbを作成します。
$ docker-compose build
$ docker-compose run --rm api rails db:create
7 . dbが作成できたらdocker環境を立ち上げます。
$ docker-compose up
うまく立ち上がったら以上でrailsアプリの環境構築は完了です。
Nuxt3の環境構築
Nuxt3の環境もRailsの環境と大枠では一緒です。
ディレクトリ構成
nuxt-front
L .env
L docker-compose.yml
L Dockerfile
.env
# commons
WORKDIR=nuxt-front
CONTAINER_PORT=3000
FRONT_PORT=8080
API_DOMAIN=172.20.0.3:3000
API_ACCESS_URL=http://172.20.0.3:3000/graphql
API_DOMAINに使用しているIPは以下の方法で取得してください
$ docker ps
$ docker exec -it {apiコンテナのid} bash
$ hostname -i
docker-compose.yml
version: '3'
services:
nuxt:
environment:
API_DOMAIN: $API_DOMAIN
API_ACCESS_URL: $API_ACCESS_URL
build:
context: .
args:
WORKDIR: $WORKDIR
tty: true
command: yarn dev
volumes:
- .:/nuxt-front
ports:
- "$FRONT_PORT:$CONTAINER_PORT"
Dockerfile
FROM node:17-slim
ARG WORKDIR
ARG CONTAINER_PORT
ARG API_URL
ARG API_URL_BROWSER
ARG FRONT_PORT
ENV HOME=/${WORKDIR} \
LANG=C.UTF-8 \
TZ=Asia/Tokyo \
HOST=0.0.0.0 \
API_URL=${API_URL} \
API_URL_BROWSER=${API_URL_BROWSER}
WORKDIR ${HOME}
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y git && \
yarn global add @vue/cli && \
yarn global add @vue/cli-init
# COPY package*.json ./
# RUN yarn install
#
# COPY . ./
EXPOSE ${CONTAINER_PORT}
手順
1 . 上記ディレクトリ構成通りにフォルダ・ファイルを作成する。
2 . nuxt-frontディレクトリに移動する。
3 . Dockerfileを実行してimageを作成する
この時、Dockerfileの下記部分をコメントアウトしておく。
# COPY package*.json ./
# RUN yarn install
#
# COPY . ./
解説
・COPY package*.json ./
自分のホスト環境のpackage.jsonとpackage.json.lockをコンテナのWORKDIR(/nuxt-front)に配置する。
・RUN yarn install
配置したpackage.jsonを元にパッケージをコンテナにインストール
・COPY . ./
自分のホスト環境のnuxt-front配下をコンテナのnuxt-front配下にコピーする。
要は新しい機能を実装したりパッケージを追加したりした時に、自分のホスト環境の修正内容をコンテナにコピーして追加したパッケージをinstallすると言ったことを行なっている。
初めて環境構築する場合はそもそも自分のホスト環境にpackage.jsonもpackage.json.lockもないので、コメントアウトしておかないとエラーになるので注意。
image作成
$ docker-compose build
4 . docker環境を立ち上げ、コンテナ内でnuxtアプリを作成する
まずdocker-compose.ymlのcommand: yarn dev
部分をコメントアウトする。
※ コンテナにnuxtアプリがない場合エラーになってしまうため
$ docker-compose up
立ち上がったコンテナを確認する
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
879a1f3fa8e6 nuxt-front_nuxt "docker-entrypoint.s…" 19 hours ago Up 4 seconds 0.0.0.0:8080->3000/tcp nuxt-front_nuxt_1
コンテナに入る
$ docker exec -it 879a1f3fa8e6 bash <- 879a1f3fa8e6は上で表示されたCONTAINER IDを指定する
カレントディレクトリを確認
$ pwd
/nuxt-front
nuxt3アプリを作成する
$ npx nuxi init app
Nuxt CLI v3.0.0-27369360.33ebb01 18:14:05
ℹ cloned nuxt/starter#v3 to /Users/ユーザー名/workspace/nuxt-front/app 18:14:06
18:14:06
🎉 Another pioneering Nuxt project just made! Next steps:
📁 `cd app`
💿 Install dependencies with `npm install` or `yarn install`
🚀 Start development server with `npm run dev` or `yarn dev`
結果的に現在のコンテナでのディレクトリ構成はこうなる
nuxt-front
L .degit
L .npm
L package.jsonなど
L app
L node_modules
L app.vue
L nuxt.config.ts
L package.json...など
L Dockerfile
L docker-compose.yml
今回はapp配下の構成をnuxt-front配下に持ってきたいので、mvコマンドを使用してapp配下を移動させる。
$ mv app/{*,.*} ../nuxt-front
その後からになったappディレクトリを削除する。
$ rm -rf app
また、npx nuxi init app
を実行すると.degitファイルと.npmディレクトリが作成されるが、
nuxtアプリとして本来必要なのはapp配下で、.degitと.npmは一部を除いて使用しないので最終的にはgitに含めなくても良いはず。
※.degitと.npmについて
この二つのファイル/ディレクトリはnuxt3をインストールする際に必要なnuxiパッケージを事前にインストールするために作成されるファイルと思われる。.nmp配下のpackage.jsonに以下の記述があるので、npx nuxi init app
コマンドを叩いたときに.degitと.npmを作成 + npm installまでを自動で行なっているはず。(詳しく調べてないので間違ってたらコメントください。)
"devDependencies": {
"nuxi": "^0.10.1"
}
なぜnuxiをインストールしているかというと、先ほどまでapp配下にあったpackage.jsonにスクリプトが作成されており、そこでnuxiコマンドを使用しているため。 サーバー立てる時と本番用にコンパイルするときに使用するっぽい。
Dockerfileでわざわざ2回に分けてyarn installしたくないのでこの内容をpackage.jsonに追加しておく。
追加できたら.degitと.npmは削除する。
{
"private": true,
"scripts": {
"dev": "nuxi dev", <- ここでnuxiが使用されている
"build": "nuxi build", <- ここでnuxiが使用されている
"start": "node .output/server/index.mjs"
},
"devDependencies": {
"nuxt3": "latest",
"nuxi": "^0.10.1" <- ここに追加
}
}
5 . docker環境を立ち上げる
Dockerfileとdocker-compose.ymlのコメントアウトを外す
COPY package*.json ./
RUN yarn install
COPY . ./
version: '3'
services:
nuxt:
build:
context: .
args:
WORKDIR: $WORKDIR
tty: true
# command: yarn dev <- ここのコメントアウトを外す
volumes:
- .:/nuxt-front
ports:
- "$FRONT_PORT:$CONTAINER_PORT"
command: yarn dev
はdocker-compose upした際にサーバーを立ち上げる。 実際には
yarn devするとpackage.jsonに定義されていたscriptの
nuxi devが実行されるため、 この後
docker-compose upする際に
nuxi: not found`などのエラーが出ていた場合はpackage.jsonに
nuxiの記述が足りないため追加する。
"devDependencies": {
"nuxt3": "latest",
"nuxi": "^0.10.1" <- ここが足りない
}
docker環境立ち上げ
$ docker-compose up
Nuxt CLI v3.0.0-27369360.33ebb01
nuxt_1 |
nuxt_1 | > Local: http://localhost:3000/
nuxt_1 | > Network: http://172.20.0.2:3000/
nuxt_1 |
無事環境が立ち上がったらブラウザで http://localhost:8080/ にアクセスして以下の画面が出れば動作確認完了です。
スクリーンショット 2022-01-16 19.04.17
また、初めてyarn dev
した時に.nuxtディレクトリが作成されますが、docker-compose up
したら勝手に作成されるので
gitに含めなくても大丈夫です。
後書き
まとまりなく書いてしまったのですが誰かの役に立てれば幸いです。
今回作成した環境でサービス開発していく予定なので、何か記事化できそうなことがあれば書いて行くつもりです。
予定では以下のものを使用するつもりなのでそのうち記事にするかもです。
Graphql
ユーザー認証: railsのdeviseかfirebase authか
Github project(使用中)
Github ActionsでCI/CD
決済: Pay.jpかstripe
Atomic design
Vuetify.js
などなど
追記(2022年1月21日)
nuxtのdocker-compose.ymlなのですが以下の記述を追加しないと無限リロードすることがわかりました。
原因はvite関連だとは思うのですが調査中です。どなたかわかる方いたらコメントください。
version: '3'
services:
nuxt:
build:
context: .
args:
WORKDIR: $WORKDIR
tty: true
# command: yarn dev
volumes:
- .:/nuxt-front
ports:
- "$FRONT_PORT:$CONTAINER_PORT"
- 24678:24678 # これを入れないとnuxtが無限リロードしてしまう