Nuxt.js+Rails+Docker+postgresqlでの開発環境構築

## はじめに
Nuxt.js Rails Docker postgresqlで新規プロジェクトがあったのでその環境構築の備忘録

## 環境
macOS

## 前提条件
* Dockerがインストールされている<br>
インストールされていない場合は[こちら](https://qiita.com/gahoh/items/92217e0a887bb81e3155)を参考にどうぞ

## ゴール
* localhost:3000にアクセスして下記画面がでる
![rails.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1986536/2a21b713-a667-0cb5-d99c-8df0ddc9e4d6.png)
* localhost:8080にアクセスして下記画面がでる
![Nuxt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1986536/15826f63-b080-d78b-63db-4435d91c7759.png)

## ディレクトリ構成図
sample $

```
├── sample
  ├── .env
  ├── .gitignore
  ├── docker-compose.yml
  ├── api
  │   　　├── Dockerfile
  │   　　├── Gemfile
  │   　　└── Gemfile.lock
  └── front
       └── Dockerfile
```


## ディレクトリ/ファイルの作成
```
documents $ mkdir sample

sample $ mkdir {api,front}

sample $ touch {docker-compose.yml,.env,.gitignore}

api $ touch {Gemfile,Gemfile.lock,Dockerfile}

front $ touch Dockerfile
```

api/Dockerfile

```Dockerfile
FROM ruby:2.7.1-alpine

ARG WORKDIR

ENV RUNTIME_PACKAGES="linux-headers libxml2-dev make gcc libc-dev nodejs tzdata postgresql-dev postgresql git" \
  DEV_PACKAGES="build-base curl-dev" \
  HOME=/${WORKDIR} \
  LANG=C.UTF-8 \
  TZ=Asia/Tokyo

WORKDIR ${HOME}

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 ["rails", "server", "-b", "0.0.0.0"]
```

api/Gemfile

```ruby:Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 6.0.0'
```

front/Dockerfile

```Dockerfile

FROM node:16.13.1-alpine
# ↑　互換性の関係で変更する可能性あります。

ARG WORKDIR
ARG CONTAINER_PORT

ENV HOME=/${WORKDIR} \
  LANG=C.UTF-8 \
  TZ=Asia/Tokyo \
  HOST=0.0.0.0

WORKDIR ${HOME}

EXPOSE ${CONTAINER_PORT}
```

sample/docker-compose.yml

```docker-compose.yml
version: "3.8"

services:
  db:
    image: postgres:12.3-alpine
    environment:
      TZ: UTC
      PGTZ: UTC
      POSTGRES_PASSWORD: $POSTGRES_PASSWORD
    volumes:
      - ./api/tmp/db:/var/lib/postgresql/data

  api:
    build:
      context: ./api
      args:
        WORKDIR: $WORKDIR
    environment:
      POSTGRES_PASSWORD: $POSTGRES_PASSWORD
    volumes:
      - ./api:/$WORKDIR
    depends_on:
      - db
    ports:
      - "$API_PORT:$CONTAINER_PORT"

  front:
    build:
      context: ./front
      args:
        WORKDIR: $WORKDIR
        CONTAINER_PORT: $CONTAINER_PORT
    command: yarn run dev
    volumes:
      - ./front:/$WORKDIR
    ports:
      - "$FRONT_PORT:$CONTAINER_PORT"
    depends_on:
      - api
```

sample/.env

```.env
# api/front
WORKDIR=app
CONTAINER_PORT=3000
API_PORT=3000
FRONT_PORT=8080

# db
POSTGRES_PASSWORD=password

```

sample/.gitignore

```
/.env
```
*.envファイルをgitの管理下から外します

## Dokerイメージの生成
```
sample $ docker-compose build
```

失敗例

```
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
```

※dockerデスクトップを立ち上げて再度、`docker-compose build`を実行

## Dockerイメージの確認

```
sample $ docker images

REPOSITORY     TAG       IMAGE ID       CREATED              SIZE
sample_api     latest    b19d75f43738   About a minute ago   561MB
sample_front   latest    9f9a253cb41e   47 hours ago         115MB
```

## Railsをapiモードで生成する

```
sample $ docker-compose run --rm api rails new . -f -B -d postgresql --api


create  app
      create  app/assets/config/manifest.js
      create  app/assets/stylesheets/application.css
      create  app/channels/application_cable/channel.rb
      create  app/channels/application_cable/connection.rb
      create  app/controllers/application_controller.rb
      create  app/helpers/application_helper.rb
      create  app/javascript/channels/consumer.js
      create  app/javascript/channels/index.js
      create  app/javascript/packs/application.js
      create  app/jobs/application_job.rb.............
```

## Gemfileの確認

```ruby:sample/api/Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.7.1'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main'
gem 'rails', '~> 6.0.4', '>= 6.0.4.1'
# Use postgresql as the database for Active Record
gem 'pg', '>= 0.18', '< 2.0'
# 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]
```
railsアプリを生成したことによりGemfileが書き変わっています

## apiのdockerイメージを再度buildする
```
sample $ docker-compose build api
```
公式ドキュメントよりGemfile/Dockerfileを変更した場合はイメージを再ビルドする必要があると記載がある

## API(Rails)DB設定
```api/app/config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db # 追加
  username: postgres # 追加
  password: <%= ENV["POSTGRES_PASSWORD"] %> # 追加
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
```
設定完了後、DBを作成する

```
sample $ docker-compose run api bundle exec rails db:create

# 成功
Created database 'app_development'
Created database 'app_test'
```

## apiコンテナ起動確認(Rails)
```
sample $ docker-compose up api


sample-api-1  | * Min threads: 5, max threads: 5
sample-api-1  | * Environment: development
sample-api-1  | * Listening on tcp://0.0.0.0:3000
sample-api-1  | Use Ctrl-C to stop
```
[http://localhost:3000](http://localhost:3000)へアクセスし下記が画面が出るか確認

![rails.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1986536/d30afc5d-c99a-eba0-0c40-09fcda11d405.png)

## apiコンテナ停止
新規でターミナルを立ち上げsampleディレクトリへ移動する

```
sample $ docker-compose down api

[+] Running 4/4
 ⠿ Container sample_api_run_184a69330fa1  Removed                          0.1s
 ⠿ Container sample-api-1                 Remo...                          0.3s
 ⠿ Container sample-db-1                  Remov...                         0.2s
 ⠿ Network sample_default                 Remo...                          0.1s
```

## Nuxt.jsを生成する
```
sample $ docker-compose run --rm front yarn create nuxt-app --overwrite-dir .
```
Nuxt.jsはアプリを生成する時に複数(12個)の質問が返されます
今回は下記設定でNuxt.jsを生成します

```
質問1 ? Project name:sample
質問2 ? Programming language:javaScript
質問3 ? Package manager:yarn
質問4 ? UI framework:vuetify.js
質問5 ? Nuxt.js modules:Axios - Promise based HTTP client
質問6 ? Linting tools:ESLint
質問7 ? Testing framework: None
質問8 ? Rendering mode: Single Page App
質問9 ? Deployment target: Server (Node.js hosting)
質問10 ? Development tools: jsconfig.json (Recommended for VS Code if you're not usingtypescript)
質問11 ? Continuous integration: None
質問12 ? Version control system: Git


# 成功
🎉  Successfully created project smple
```
今回は上記設定でNuxt.jsを生成します

## frontコンテナ起動確認(Nuxt.js)
```
sample $ docker-compose up front
```
[http://localhost:8080](http://localhost:8080)へアクセスし下記が画面が出るか確認

![Nuxt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1986536/23ce6064-bd2e-5e86-8973-92cf67806f70.png)

お疲れ様でした