Vagrant+Docker+Rails+Nuxt.js+MySQL+SSL化

#はじめに
ポートフォリオ作成まで、環境構築が辛すぎたのでその過程を書きました。
完全に全ての技術に対して初心者だったので、毎日絶望していました。

ポートフォリオのために快適な開発環境をまず作りたくて試行錯誤していました。
Docker for Macが重すぎ、しかもfrontendとbackendに分けて、
しかもNginxを使ってSSL化までする記事がなさすぎて絶望したので実験しながら作りました。

今後忘れないために備忘録として・・・。
とりあえずそれぞれHello World出来るまで。

#こんな人へ
とりあえずサクサクっと開発環境をつくりたいぜ。
Dockerとかの知識はちょっとあるぜ。

#これを読むとわかること/おおまかな流れ
- Vagrant環境構築
- Nuxt.js環境構築
- Docker環境構築
- nuxtとRails（APIモード）とMySQLの開発環境構築
- Nginxの環境構築
- SSL化（オレオレ証明書）

#　環境
Mac OS
ruby:2.6.3
Rails 5.2.4.3

#フォルダ構成

```
app
├─docker-compose.yml
├─mutagen.yml
├─Vagrantfile
├─back #Rails
| ├─Dockerfile
| ├─Gemfile
| └─Gemfile.lock
├─front #Nuxst.js
| └─Dockerfile
├─nginx #nginx
| └─nginx.conf
└─ssl #nginxに読み込ませる鍵
  ├─server.crt
  ├─server.csr
  └─server.key
```

#Vagrant

##おおまかな流れ
- VirtualBoxをinstall
- Vagrantをinstall
- Vagrantfile作成
- Mutagenをinstall
- VagrantにSSH接続する

##Vagrant/Virtualboxダウンロード

https://www.vagrantup.com/
https://www.virtualbox.org/

```
brew cask install virtualbox
```
```
brew cask install vagrant
```
##VagrantBox
VagrantBox(OS)のダウンロード
今回はubuntuで構築します。
```
vagrant box add ubuntu/xenial64
vagrant box list #確認しておきましょう
```
#Vagrant plugin
```
vagrant plugin install vagrant-disksize vagrant-hostsupdater vagrant-mutagen vagrant-docker-compose
```

##Vagrantセットアップ
作業フォルダの作成（名前はなんでも）

```
mkdir app
cd app
```

##Vagrantfileの作成

```console:/app
vagrant init ubuntu/xenial64
```
Vagrantfileを以下の内容に書き換えてください。

```ruby:/app/Vagrantfile
Vagrant.configure('2') do |config|
  config.vm.box = 'ubuntu/xenial64'

  config.vm.hostname = 'app' #任意のホストネーム

  config.vm.network :private_network, ip: '192.168.50.10' #ここがVagrant内にアクセスするIP

  config.vm.provider :virtualbox do |vb|
    vb.gui = false
    vb.cpus = 4 #割り当てるCPUコア数
    vb.memory = 4096　#割り当てるメモリ
    vb.customize ['modifyvm', :id, '--natdnsproxy1', 'off']
    vb.customize ['modifyvm', :id, '--natdnshostresolver1', 'off']
  end

  config.disksize.size = '30GB' #ディスクサイズ
  config.mutagen.orchestrate = true

  config.vm.synced_folder './', '/home/vagrant/app', type: "rsync",
    rsync_auto: true,
    rsync__exclude: ['.git/', 'node_modules/', 'log/', 'tmp/']

  config.vm.provision :docker, run: 'always'
  config.vm.provision :docker_compose
end
```

##MutagenのInstall
ファイル同期ソフトであるmutagenのインストールをします。
https://mutagen.io/

```
brew install mutagen-io/mutagen/mutagen
```

```console:/app
touch mutagen.yml
vim mutagen.yml
```

```yml:/app/mutagen.yml
sync:
  app:
    mode: "two-way-resolved"
    alpha: "./"
    beta: "app:/home/vagrant/app" #同期させるフォルダ/Vagrantfileで設定したホストネームと合わせてください。
    ignore:
      vcs: true
      paths:
        - "/node_modules"
        - "/log"
        - "/tmp"
```

##Vagrant起動
```console:/app
vagrant up
```

はじめてVirtualBoxを入れたタイミングで「セキュリティとプライバシー」で弾かれるそうなのでダウンロードしたアプリケーションの許可をして再度upしてください。


```console:
: No such file or directory @ rb_sysopen - /Users/hoge/.ssh/config (Errno::ENOENT)
```
また、こんな感じのエラーが出たら、

```
touch /Users/hoge/.ssh/config
```
.ssh/configを作成してあげましょう。

##仮想環境にssh接続

```
vagrant ssh
```

```console:
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-179-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

 * MicroK8s passes 9 million downloads. Thank you to all our contributors!

     https://microk8s.io/

2 packages can be updated.
0 updates are security updates.

New release '18.04.4 LTS' available.
Run 'do-release-upgrade' to upgrade to it.


Last login: Sat May 30 12:32:45 2020 from 10.0.2.2
```
こんな感じのログが出るとSSH接続完了です。

ちなみに

```
vagrant halt
```
も覚えておくと良いです。
同期されてねー！とか思ったらやります。vagrant環境の破棄です。（Vagrantfileが有る限りupで再度作成できるので安心）

##参考記事
[Docker For Macが遅い：対策の実験](https://qiita.com/FattyRabbit/items/bfb5a9a321718b7f2756)
[Vagrantを使う「Mac最速のDocker環境」を初心者向けに解説【遅いMac for Dockerを卒業】](https://qiita.com/necocoa/items/bd62ed3dba14b17552f2)
[vagrantとDockerで環境構築をした](https://qiita.com/mightysosuke/items/6004d3aaf3411601be22)
[Docker for MacからVagrant + CoreOSに切り替えた](https://qiita.com/Ucan/items/545ce4d8e32580091bc9)

#Docker
##Dockerfile
```dockerfile:/front/Dockerfile
FROM node:12.5.0-alpine

ENV HOME="/app" \
    LANG=C.UTF-8 \
    TZ=Asia/Tokyo

WORKDIR ${HOME}

RUN apk update && \
    apk upgrade && \
    npm install -g n && \
    yarn install &&\
    rm -rf /var/cache/apk/* s

ENV HOST 0.0.0.0
```
おそらく最低限の構成（もっとシンプルにできたら教えてください。）
npmとyarnをinstallしてます。VagrantなのでIPをバインディング
以下参照
[rails s -b 0.0.0.0 のオプション-bの意味/バインディングアドレスとは](https://qiita.com/Masato338/items/f162394fbc37fc490dfb#%E3%83%90%E3%82%A4%E3%83%B3%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%A8%E3%81%AF)


```dockerfile:/back/Dockerfile
FROM ruby:2.6.3-alpine3.10

#おまじない的
ENV RUNTIME_PACKAGES="linux-headers libxml2-dev make gcc libc-dev nodejs tzdata mysql-dev mysql-client yarn" \
    DEV_PACKAGES="build-base curl-dev" \
    HOME="/app" \
    LANG=C.UTF-8 \
    TZ=Asia/Tokyo

WORKDIR ${HOME} #ワークスペースの確保

ADD Gemfile ${HOME}/Gemfile #GemfileをDocker内にコピー
ADD Gemfile.lock ${HOME}/Gemfile.lock #Gemfile.lockをDocker内にコピー

RUN apk update && \
    apk upgrade && \
    apk add --update --no-cache ${RUNTIME_PACKAGES} && \
    apk add --update --virtual build-dependencies --no-cache ${DEV_PACKAGES} && \
    bundle install -j4 && \
    apk del build-dependencies && \
    rm -rf /usr/local/bundle/cache/* \
    /usr/local/share/.cache/* \
    /var/cache/* \
    /tmp/* \
    /usr/lib/mysqld* \
    /usr/bin/mysql*

ADD . ${HOME}
```
ところどころわからないところがありますが・・・。ご存知の方コメントくださると有り難いです。

```yml:/app/docker-compose.yml
version: "3"

services:
  db:
    image: mysql:5.7
    env_file:
      - ./back/environments/db.env
    restart: always
    volumes:
      - db-data:/var/lib/mysql:cached

  back:
    build: back/
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    env_file:
      - ./back/environments/db.env
    volumes:
      - ./back:/app:cached
    depends_on:
      - db
    ports:
      - 3000:3000

  front:
    build: front/
    command: yarn run dev
    volumes:
      - ./front:/app:cached
    ports:
      - 8080:3000
    depends_on:
      - back

  nginx:
    image: nginx
    ports:
      - 443:443
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./ssl/server.crt:/etc/nginx/ssl/server.crt
      - ./ssl/server.key:/etc/nginx/ssl/server.key


volumes:
  public-data:
  tmp-data:
  log-data:
  db-data:
```

##Gemfile
```console:/app/back/Gemfile
source 'https://rubygems.org'
gem 'rails', '~>5'
```

```console:/app/back
touch Gemfile.lock
```

## docker-composeを使ってbuild

```console:vagrant内/app
docker-compose build
```

##Nuxt.js

```console:/app
$ docker-compose run --rm front npx create-nuxt-app

? Project name                   --> sample   # アプリ名
? Project description            --> sample    # アプリの説明
? Author name                    --> me        # アプリの作成者
? Choose the package manager     --> Npm
? Choose UI framework            --> None
? Choose custom server framework --> None
? Choose Nuxt.js modules         --> Axios
? Choose linting tools           --> -
? Choose test framework          --> None
? Choose rendering mode          --> Universal (SSR)
```

```console:Vagrant内/app
docker-compose up front
```

`http://192.168.50.10:8080`にアクセスしてHello World!

##参考記事
[Nuxt.js + Rails(API) on DockerのHello Worldするべ！](https://qiita.com/at-946/items/08de3c9d7611f62b1894)

##Rails
今回のRailsはAPIモードで作成するので、 `--api`引数をば

```console:/app
docker-compose run --rm back rails new . -f -d mysql --api
```

```yml:back/config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch('MYSQL_USER') { 'root' } %>
  password: <%= ENV.fetch('MYSQL_PASSWORD') { 'password' } %>
  host: db

development:
  <<: *default
  database: webapp_development

test:
  <<: *default
  database: webapp_test
```

###DBの環境変数のファイルを作ります。

```console:/app/back
mkdir environments
```

```console:/app/back/environments
vim db.env
```

```console:/app/back/environments/db.env
MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_USER=username
MYSQL_PASSWORD=userpassword
```

###DB権限設定をするためのSQLを作ります。
```console:/app/back/db
vim grant_user.sql
```

```sql:grant_user.sql
GRANT ALL PRIVILEGES ON *.* TO 'username'@'%';
FLUSH PRIVILEGES;
```

###DBへクエリを流し込む
```console:Vagrant内/app
docker-compose build
docker-compose up
```

```console:Vagrant内/app
docker-compose ps
```

ちゃんとDBが動いている状態を確認

```console:Vagrant内/app
docker-compose exec db mysql -u root -p -e"$(cat back/db/grant_user.sql)"
```
先ほど設定した`rootpassword`を入力

```console:Vagrant内/app
docker-compose exec db mysql -u username -p -e"show grants;"
```
権限の確認
先ほど設定した`userpassword`を入力

```
+------------------------------------------------+
| Grants for user_name@%                         |
+------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'username'@'%' |
+------------------------------------------------+
```
こうなればOK

```console:Vagrant内/app
docker-compose exec app rails db:create
```
`http://192.168.50.10:3000`にアクセスしてHello World!

##参考記事
[Docker + Rails + Puma + Nginx + MySQL](https://qiita.com/eighty8/items/0288ab9c127ddb683315)

#Nginx

```conf:app/nginx/nginx.conf
worker_processes auto;

events {
  worker_connections 1024;
}

http {
  server {
    listen 443  ssl;
    ssl_certificate     /etc/nginx/ssl/server.crt; #SSL証明書
    ssl_certificate_key /etc/nginx/ssl/server.key; #秘密鍵

    proxy_set_header    Host    $host;
    proxy_set_header    X-Real-IP    $remote_addr;
    proxy_set_header    X-Forwarded-Host       $host;
    proxy_set_header    X-Forwarded-Server    $host;
    proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;

    location /api/ {
      proxy_pass http://192.168.50.10:3000;
      proxy_buffering off;
    }

    location / {
      proxy_pass http://192.168.50.10:8091;
      proxy_buffering off;
    }
  }
}

```

##オレオレ証明書の作成
```console:app/
#秘密鍵の作成
sudo openssl genrsa -out app/ssl/server.key 2048
#CSR（証明書署名要求）の作成
sudo openssl req -new -key app/ssl/server.key -out app/ssl/server.csr
#CRT（SSLサーバ証明書）の作成
sudo openssl x509 -days 3650 -req -signkey app/ssl/server.key -in app/ssl/server.csr -out app/ssl/server.crt 
```

```console:Vagrant内/app
docker-conpose up
```

`https://192.168.50.10:8080`にアクセスしてHello World!

###Chromeで警告が出る場合
[自分で発行したサーバー証明書（オレオレ証明書）をブラウザに登録する方法](https://kekaku.addisteria.com/wp/20190327053337)
こちらを参考に、ブラウザに証明書を登録してください。

##参考記事
[Nuxt.jsでlocalhostをSSL化する方法](https://qiita.com/yoshinbo/items/5838f43cbbd75e396c35)


#最後に
かなり駆け足・長文になってしまい申し訳ありません。
読んでくださってありがとうございます。
とりあえずの備忘録として書きましたので、間違っていたらコメントで教えていただけると有り難いです。

Vagrant環境内で、Nuxt.jsとRails、しかもDockerで構築してNginxでリッスン、しかもSSL化とかいう記事は無くて
それぞれの記事をつなぎ合わせてようやく完成しました。

Docker、Vagrant、Nginx、Rails、Nuxt.jsに関しては完全に初心者です。
初めて作成するにはかなり無謀なチャレンジでした・・・。

優しいマサカリ投げていただけると嬉しいです。