はじめに
以前に、railsとvueのアプリ構成でdocker環境を構築した。
しかし、Railsの開発用サーバーをpuma単独で動かしていたので、
役割分担して構成を変更した。
- webサーバー: nginx
- applicationサーバー: puma
作業内容を備忘録として残す。
アプリ構成イメージ
使用技術
- Rails: 6.0.4.4
- nginx: 1.21.6
前提
- dockerでrailsの開発環境を構築済み
nginxの初期設定を理解する
実装前にnginxのデフォルト設定がどう動作しているのか確認しておく。
DockerHubからnginx:1.21.6-alpine
イメージを選択し、同イメージでコンテナを生成すると、
コンテナ内の/etc/nginx/conf.d/にdefault.conf
が自動生成されていた。
server {
listen 80;
listen [::]:80;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
そのまま起動されたコンテナにhttp://localhost
でアクセスすると、welcomeページに表示されてnginxが正常起動していることが分かる。
ひとまずデフォルトでは当ファイルをもとに動作していることが分かった。
(Nginxの初期設定の詳細は別の機会に学ぶことにする)
実装
今回はnginxからRailsにアクセスし、正常に動作する
をゴールにする。
負荷分散やエラーログの整理などの詳細設定は、nginxの技術書を読んでブラッシュアップする。
では実装に移る。
ディレクトリ構成
frontendと.envは今回の実装に直接は関係しないが、全体像の為に載せておく。
- frontend: Vueを構成
- .env: 環境変数を管理
% tree root -a
root
├── docker-compose.yml
├── .env
├── backend
・ ・
・ ・
・ ・
│ ├── Dockerfile
│ └── config
│ └── puma.rb
├── frontend
・ ・
・ ・
・ ・
│ └── Dockerfile
└── web
├── Dockerfile
└── nginx.cnf
作業
各ファイルにコメントで補足している。
なお、nginxとpumaを繋ぐソケットは
以下の順で使われていることを留意しておく。
- Dockerfile(Rails)のCMDでpumaを起動する
- puma.rbでbindを実行し、puma.sockというソケットを作成する
- docker-compose.ymlのvolumesで同ソケットをnginxコンテナにも共有する
- Dockerfile(Nginx)のCOPYでホスト側のnginx.confをnginxコンテナに複製する
- そのnginx.confのupstreamで共有されたソケットで繋ぐ
### 環境変数は.envファイルで管理 ###
version: '3.8'
services:
# DBコンテナ
db:
image: mysql:8.0.28
command: --default-authentication-plugin=mysql_native_password
volumes:
- "./db:/var/lib/mysql"
- "./db/personal_config/my.cnf:/etc/mysql/conf.d/my.cnf"
environment:
MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
TZ: Asia/Tokyo
# Railsコンテナ
backend:
build:
context: ./backend
args:
WORKDIR: $WORKDIR
volumes:
- "./backend:/$WORKDIR"
environment:
MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
ports:
- "8000:3000"
depends_on:
- db
# Nginxコンテナ
web:
build:
# Dockerfileのパスを指定する
context: ./web
volumes:
# 独自のNginx設定ファイルをコンテナに同期させる
- ./web:/app/public
# Railsのpuma起動時に生成されるpuma.sockをNginxコンテナにも共有する
- ./backend/tmp/sockets:/app/tmp/sockets
ports:
- 80:80
# 先にRailsが動くように依存関係を作る
depends_on:
- backend
# Vueコンテナ
frontend:
build:
context: ./frontend
args:
WORKDIR: $WORKDIR
volumes:
- "./frontend:/$WORKDIR"
ports:
- "3000:3000"
depends_on:
- backend
FROM ruby:2.7.5-alpine
ARG WORKDIR
ARG RUNTIME_PACKAGES="bash imagemagick nodejs yarn tzdata mysql-dev mysql-client git"
ARG DEV_PACKAGES="build-base curl-dev"
ENV HOME=/${WORKDIR} \
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 . ./
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
# pumaを起動させる
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]
--省略--
# puma起動時にソケットであるpuma.sockを作成する
bind "unix:///app/tmp/sockets/puma.sock"
# ベースイメージ
FROM nginx:1.21.6-alpine
# Nginxに関わる設定ファイルを全削除
RUN rm -f /etc/nginx/conf.d/*
# 独自の設定ファイルを機能する場所に配置する
COPY nginx.conf /etc/nginx/conf.d/custum.conf
# Railsのpumaが生成したソケットにnginxを繋ぐ
upstream app {
server unix:///app/tmp/sockets/puma.sock;
}
server {
# クライアントからのリクエストを80番ポートで待ち受ける
listen 80;
# サーバー名称をlocalhostに設定
server_name localhost;
# ドキュメントルートを/app/publicに設定
root /app/public;
# 静的ファイルが存在しなければ、@app(=Rails)にリクエストを渡す
try_files $uri/index.html $uri @app;
location @app {
# プロキシのヘッダー情報をクライアント情報に書き換えする
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
# プロキシの受け渡し先(upstreamで定義したappに合わせる)
proxy_pass http://app;
}
}
動作検証
ブラウザでhttp://localhost
を入力すれば、Railsの起動画面が表示される。
ちなみにVueからaxiosでHTTP通信を図るときは、Nginxの80番ポートに向けて送信すれば通信できる。
参考記事
終わりに
可用性やセキュリティ面を考えると今の設定は不十分だろうな…
時間に余裕があれば、nginxの技術書を完読した上でしっかりしたものを実装したかった。
最後までお読みいただき、ありがとうございました!