Docker  Rails + Reactの本番環境構築(ubuntu + Apache + rails + React + MySQL)

# はじめに
バックエンドをrailsで、フロントエンドをreactのアプリケーションを開発した際の、環境構築に苦戦したため、備忘録もかねて投稿します。
とりあえず動くとこまでなので、dockerの利点を生かせていなかったり、セキュリティ関連の設定などは行っていません。
間違いなどあればご指摘いただけると幸いです。

# 前提
railsアプリとreactアプリは開発環境で開発し、完成したものを持ってきて本番環境を構築しました。
そのため、本投稿の構成では開発段階を考慮していません。
継続的に改修していく場合にどうするかが課題です。

# コンテナ構成
##### serverコンテナ
このコンテナにMySQL以外の全てのサービスを詰め込んでしまいます。
dockerは1コンテナにつき1サービスが好ましいので良くない構成かもです...
開発環境ならrailsやreactをそれぞれが持つフレームワーク付随のサーバで良いため、コンテナを分けられますが、webサーバとしてapacheを使用した場合の構築方法が分かりませんでした。
今後の課題です。

##### dbコンテナ
このコンテナには、MySQLを立ち上げます。

# ファイル準備
##### ディレクトリ構成
```
/ -- docker-compose.yml
                server/ -- Dockerfile
                                  db/ -- Dockerfile
                                 web/ -- configs/  -- apache/ -- 000-default.conf
                                                                 ports.conf
                                                      react/  -- .htaccess
                                         webfront/ -- reactアプリケーションプログラム
                                              api/ -- railsアプリケーションプログラム                         
```
##### / docker-compose.yml
```yml:docker-compose.yml
version: '3'
services:
  server:
    build: ./server
    ports:
      - 3000:3000
      - 3001:3001
    depends_on:
      - db
    tty: true
    stdin_open: true
  db:
    build: ./server/db
    volumes:
      - db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: test_db
      TZ: Asia/Tokyo
    ports:
      - 3306:3306
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
volumes:
  db-volume:
```
##### / server / Dockerfile
```Dockerfile:/server/Dockerfile
FROM ubuntu:20.04

RUN apt -y update \
    && apt -y upgrade \
    && apt-get install -y vim git

# タイムゾーン設定
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime


# ruby2.7.0 インストール
RUN apt-get -y install ruby


# apacheをセットアップ
RUN apt-get install -y apache2 apache2-dev
COPY ./web/configs/apache/000-default.conf /etc/apache2/sites-available/000-default.conf
COPY ./web/configs/apache/ports.conf /etc/apache2/ports.conf


# railsアプリセットアップ
RUN apt-get install -y build-essential ruby-dev libmysqlclient-dev libcurl4-openssl-dev nodejs
RUN mkdir /app \
    && mkdir /app/api
WORKDIR /app/api
COPY ./web/api/Gemfile /app/api/Gemfile
COPY ./web/api/Gemfile.lock /app/api/Gemfile.lock
RUN gem install bundler
COPY ./web/api /app/api
RUN bundle install
RUN rm -f tmp/pids/server.pid
RUN mkdir public \
    && chmod 777 public \
    && chown www-data:www-data -R public \
    && chown -R www-data:www-data /app

# passengerとapache関連
RUN gem install passenger


# react セットアップ
RUN apt-get install -y npm \
    && npm install n -g \
    && n lts \
    && a2enmod rewrite
RUN mkdir /app/webfront
WORKDIR /app/webfront
COPY ./web/webfront /app/webfront
COPY ./web/configs/react/.htaccess /app/webfront/public
RUN npm install
RUN chown -R www-data:www-data /app/webfront
RUN npm run build


WORKDIR /app
```
##### 補足
「railsアプリセットアップ」部分で自分で/publicディレクトリを作成しています。
これはなぜか私の環境ではpublicディレクトリが生成されておらず、ドキュメントルートにする場所に困ったため、自分でpublicディレクトリを作成しています。
これでも問題なく動作しました。

##### server / db / Dockerfile
```Dockerfile
FROM mysql:5.7

RUN apt-get update
RUN apt-get -y install locales-all

ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
```
##### server / web / config / apache / 000-default.conf
```conf:000-default.conf
<VirtualHost *:3000>
        ServerAdmin webmaster@localhost
        DocumentRoot /app/api/public
        RailsEnv development

        <Directory "/app/api/public">
                AllowOverride all
                Require all granted
                Options MultiViews
                Order deny,allow
                Allow from all
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

<VirtualHost *:3001>
        ServerAdmin webmaster@localhost
        DocumentRoot /app/webfront/build

        <Directory "/app/webfront/build">
                AllowOverride all
                Require all granted
                Order deny,allow
                Allow from all
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
```
##### server / web / config / apache / ports.conf
```conf:ports.conf
Listen 3000
Listen 3001

<IfModule ssl_module>
        Listen 443
</IfModule>

<IfModule mod_gnutls.c>
        Listen 443
</IfModule>
```
##### server / web / config / react / .htaccess
```
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [QSA,L]
```
##### server / web / api /
railsのアプリケーションを格納します。
##### server / web / webfront /
reactのアプリケーションを格納します。

# 起動する
##### buildする
```
docker-compose build
```
#### コンテナを立ち上げる
```
docker-compose up -d
```
# apacheの設定を完了する
現在のままでは、passengerの設定が完了しておらず、railsアプリケーションがapache経由でアクセスできません。
passengerの設定には、コマンド実行後に選択肢が出てしまうため、Dockerfileに含められませんでした。
##### serverコンテナに入る
apacheやrailsのアプリケーションはserverコンテナに存在するため、コンテナに入って作業をします。
```
docker-compose exec server bash
```
##### passengerを使えるようにコンパイル？みたいな
passengerを使えるようにコンパイル？を行います。
初めにrailsでpassengerを使用するための必要な追加パッケージがインストールされているかが確認され、問題なければコンパイル？が実行されます。
もし、必要なパッケージがインストールされていなければインストールしてください。
```
passenger-install-apache2-module
```
##### passengerを使うための設定値を出力
以下を実行して、出力された設定値を[/etc/apache2/apache2.conf]の末尾に追加してください。
```
passenger-install-apache2-module --snippet
```
###### apacheの再起動
```
service apache2 restart
```
port 3000番でrailsが、3001番でreactが起動しているはずです！

# 苦戦したポイント
- nodejsやapacheをbuild時にインストールする時、選択肢で止まってしまう。
  => docker-compose.ymlで初めにタイムゾーンを設定することで解決。

- railsのドキュメントルートとなる/publicディレクトリが存在しない
  => mkdir publicと単純に空のpublicディレクトリを作成し、ドキュメントルートに設定することで解決

- 権限の問題でapacheからrailsやreactのアプリケーションにアクセスできない
  => apacheのユーザーがwww-dataだったため、 chown -R www-data:www-data /app などとして解決

- npmやnodeのバージョンが低い
  => n をインストールし、npmとnodeを最新のバージョンにすることで解決

- reactアプリがreact-routerでのルーティングがされない(今回開発したアプリがSPAだったため)
  => /publicディレクトリに設定を記述した.htaccessを配置することで解決
  
- .htaccessに記述したrewriteをapacheが上手く認識しない
  => ディフォルトではそのパッケージ?が使えないため、a2enmod rewriteコマンドを実行して使えるようにして解決

# 参考文献
- [Ubuntu 16.04 LTS で Passenger + Apache を用いて Railsアプリ を公開する方法 - 約束の地](https://obel.hatenablog.jp/entry/20161113/1479005116)

- [Ubuntu で Node の最新版/推奨版を使う (n コマンド編) - Qiita](https://qiita.com/cointoss1973/items/c000c4f84ae4b0c166b5)

- [react-routerでルーティングしているSPAをApacheに公開する - Qiita](https://qiita.com/mugrow/items/3d89e836b29c0b3d2534)

- [Ruby on Railsの開発環境をDockerで構築する方法(Rails 5.x)](https://zenn.dev/tmasuyama1114/articles/rails-docker-5x-how-to)

- [DockerのMySQLコンテナを日本語対応させる - Qiita](https://qiita.com/zongxiaojie/items/6b593ec4ce5e85bb342c)

- [ Apache2でmod_rewrite が動かない？ - それマグで！](https://takuya-1st.hatenablog.jp/entry/2020/06/26/151330)

- [CentOS7でApache+PassengerのRails本番環境を構築する手順 - 銀の弾丸を探して](https://takaxyz.hatenablog.com/entry/2018/12/12/125935)