DockerでNginx、Puma(Rails7.0)の環境構築
前回の記事からの続きになります。
環境
- Apple M1 Pro
- macOS Monterey 12.1
- Docker Engine 20.10.12
- Docker Compose v2.2.3
- Ruby 3.1.1
- Ruby on Rails 7.0.2
- nginx 1.21.6
作業ディレクトリ作成
前回に引き続き、/dockerの下に/nginxを作成します
app
└─ docker
├── nginx
│ ├── Dockerfile
│ └── nginx.conf
└── web
├── Dockerfile
├── entrypoint.sh
└── start-server.sh
# ディレクトリの作成 $ mkdir -p /app/docker/nginx $ cd /app/docker/nginx
Dockerfile
今回はベースイメージにnginx:latestを使用します。
デフォルトで用意される80番ポートをlistenするserverコンテキストを持ったdefault.confファイルは不要なので、RUN rm -f /etc/nginx/conf.d/*で削除します。
また、CMD /usr/sbin/nginxでnginxを起動するようにしますが、デフォルトではデーモンで起動してしまい、フォアグラウンドで起動しないとコンテナが止まってしまうようです。
If you add a custom
CMDin the Dockerfile, be sure to include-g daemon off;in theCMDin order for nginx to stay in the foreground, so that Docker can track the process properly (otherwise your container will stop immediately after starting)! https://hub.docker.com/_/nginx
-g 'daemon off;' でフォアグラウンド化して起動します。
$ vim Dockerfile
FROM nginx:latest # デフォルトで用意されている個別設定ファイルを削除 RUN rm -f /etc/nginx/conf.d/* COPY ./docker/nginx/nginx.conf /etc/nginx/nginx.conf # Nginxをforeground起動 CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
参考:/etc/nginx/conf.d/default.conf(RUN rm -f /etc/nginx/conf.d/* で削除する)
server {
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;
#}
}
docker-compose.yml
nginxを追加します。volumesはホストのapp/docker/nginx/nginx.confを/etc/nginx/nginx.confにマウントします。
# appディレクトリにて $ vim docker-compose.yml
version: '3' services: web: build: context: . dockerfile: ./docker/web/Dockerfile volumes: - .:/app ports: - '3000:3000' depends_on: - db stdin_open: true tty: true environment: DB_ROOT_USERNAME: root DB_USERNAME: development DB_PASSWORD: password TZ: Asia/Tokyo DB_HOST: db db: platform: linux/x86_64 image: mysql:8.0 environment: - MYSQL_DATABASE=development - MYSQL_USER=development - MYSQL_PASSWORD=password - MYSQL_ROOT_PASSWORD=passwordpassword - TZ=Asia/Tokyo ports: - '3306:3306' command: --default-authentication-plugin=mysql_native_password volumes: - ./volumes/mysql/data/:/var/lib/mysql nginx: # 追加 build: context: . dockerfile: ./docker/nginx/Dockerfile volumes: - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf # ここ ports: - "80:80" depends_on: - web
nginx.conf
デフォルトで用意されているnginx.confをベースに、ほかは何もいじらず、必要部分のみを付け足してみます。
railsアプリのリバースプロキシとして、proxy_passにhttp://unix:///app/tmp/sockets/puma.sock;を指定し、UNIXドメインソケット通信でpumaに向けます。
app/docker/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
server { # 追加
listen 80;
server_name localhost;
root /app/public;
location / {
try_files $uri $uri/index.html @app;
}
location @app {
# クライアントのリクエスト情報をpumaに伝える
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://unix:///app/tmp/sockets/puma.sock;
}
}
}
puma.rb
puma側ではPORTを使用せず、ソケットファイルをbindしてソケット通信する設定を記載します。
app/config/puma.rb
# port ENV.fetch("PORT") { 3000 } bind "unix://#{Rails.root}/tmp/sockets/puma.sock"
Dockerfile
rails用のDockerfileについても、PORTを空ける必要がなくなったため削除します。
app/docker/web/Dockerfile
RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] # EXPOSE 3000 # Start the main process. CMD ["sh", "./docker/web/start-server.sh"]
start-server.sh
TCP通信の必要がなくなったため、rails serverコマンドからポートとバインドの設定を削除します。
app/docker/web/start-server.sh
#!/bin/sh echo "run start-server.sh" & rails server # rails server -p 3000 -b 0.0.0.0
docker-compose.yml
変更点は3箇所です。
- ポートを使用しないので、webコンテナのports設定は削除
- UNIXドメインソケット通信によるコンテナ間通信となるため、web・nginxコンテナで名前付きvolumeをマウントしてファイルを共有
- nginx.confでアプリケーションルートを指定する(rootディレクティブ)ため、2と同様にweb・nginxコンテナで名前付きvolumeをマウントしてファイルを共有
app/docker-compose.yml
version: '3' services: web: build: context: . dockerfile: ./docker/web/Dockerfile volumes: - .:/app - public:/app/public # 追加 - tmp:/app/tmp # 追加 # ports: # - '3000:3000' depends_on: - db stdin_open: true tty: true environment: DB_ROOT_USERNAME: root DB_USERNAME: development DB_PASSWORD: password TZ: Asia/Tokyo DB_HOST: db db: platform: linux/x86_64 image: mysql:8.0 environment: - MYSQL_DATABASE=development - MYSQL_USER=development - MYSQL_PASSWORD=password - MYSQL_ROOT_PASSWORD=passwordpassword - TZ=Asia/Tokyo ports: - '3306:3306' command: --default-authentication-plugin=mysql_native_password volumes: - ./volumes/mysql/data/:/var/lib/mysql nginx: build: context: . dockerfile: ./docker/nginx/Dockerfile volumes: - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf - public:/app/public # 追加 - tmp:/app/tmp # 追加 ports: - "80:80" depends_on: - web volumes: # 追加 tmp: # 追加 public: # 追加
動作確認
ここまできたら再ビルドして立ち上げます。
$ docker-compose build --no-cache # 一応--no-cache $ docker-compose up -d
localhostにアクセスすると、nginx経由でrailsの画面が見えるかと思います🎉

終わりに
Dockerの環境構築は久しぶりにやったのですが、昔より構築スピードが上がっていて成長を感じました。 nginxの実務ではSSRなNuxtに通信を向けてみたり、CSPやBasic認証の運用をしたり、IPアドレス直打ちの対策等をした程度でしたが、コンテナではログ・ssl・キャッシュ・ロードバランス辺りを試してみたいなと思ってます。
あとは今後Ansible辺りも触ってみたい。terraformも勉強したので、Ansibleと組み合わせて構築を自動化してみたい。
・・目指すところはDevOps・・?
参考記事
nginxをdockerで動かす時のTips 3選 - インフラエンジニアway - Powered by HEARTBEATS
Docker + Rails + Puma + Nginx + MySQL - Qiita
はじめてのDockerでRails開発環境構築 [NGINX + Rails 5 (puma) + PostgreSQL] - Qiita