いきなりまとめ
- マイクロサービスとかでいくつものアプリケーションに対してリクエストを行うような構造のアプリケーションはリクエストIDを設定しておき、異なるマイクロサービスでも同一のIDがログ上で記録されるので、ログのチェックなどがはかどって便利。
- Nginx 1.10以降で利用できる $request_id を使うと簡単に リクエストごとに発番できる。
- Railsは HEADER X-Request-Id を取得してログにタグを簡単に設定できる。
なぜ必要なのかをもっと詳しく
Railsアプリケーションの手前でNginxでTLSを終端していたり、 複数のアプリケーションをまたいだりしているマイクロサービスでアプリケーションを実装していると、もし大げさなサービスを構築していなくとも、リクエストが多いとログを確認するのが大変なので、 なにかとNginxでリクエストごとに生成したIDを振ったものをProxyしているアプリケーションに渡してやることでログの確認を補助することができる。
やりたいこと・サンプルアプリケーションの構成
- 今回は前段にTLS終端を想定した、Nginxでロードバランサを立てる。
- 1.のNginxアプリケーション(コンテナ)でNginxでUUIDを割り当て、Proxyする。
- 2のコンテナから、ProxyからのアクセスにX-Request-Id が設定されている場合は、それをそのまま X-Request-Id に設定する。設定されていない場合は、3のコンテナでリクエストIDを発番する。
- 更にRailsアプリケーション用にProxyして、ProxyHeaderに書き込まれた X-Request-Id をRailsのログにタグとして設定して書き込む
図解
サンプルリポジトリ
これをGit cloneしてきて、docker-compose up ってすればシュシュッとサンプルのアプリケーションが動くので、よかったら動かしてみて欲しい。
TLS終端用のNginx側の設定
リクエストごとにIDを発番する機構はNginx1.10以上であれば、$request_id を利用して、簡単に設定することができる。
server { listen 80; server_name _; client_max_body_size 4G; keepalive_timeout 5; 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 http; location / { # X-Request-IdをProxy Headerに設定 proxy_set_header X-Request-Id $request_id; proxy_pass http://nginx_rails_proxy; } }
上記は設定の抜粋なので、下記にすべて記載したものを掲載しておく。*1
Rails Proxy用のNginxコンテナの設定
基本的にはTLS終端用のNginxの設定と同じ。RailsアプリケーションへのProxy設定部分以外で異なるのは、 先程のTLS終端用のコンテナから受け取った X-Request-Id をProxyするアプリケーションに対して ProxyHeaderに設定してあげればOKということ。 もし X-Request-Idがない場合は、このNginxでリクエストIDを生成して設定すればOK。
server { listen 80; server_name _; client_max_body_size 4G; keepalive_timeout 5; # この生成したRequestIdをProxy用のRequest IDに設定。 set $proxy_request_id $request_id; if ($http_x_request_id) { # Proxy Headerに `X-Request-Id`が設定されている場合、 Proxy用のリクエストIDに設定する set $proxy_request_id $http_x_request_id; } root /usr/src/app/public; try_files $uri/index.html $uri.html $uri @app; location @app { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; # Header, Proxy Headerに `X-Request-Id` を設定する。 add_header X-Request-Id $proxy_request_id; proxy_set_header X-Request-Id $proxy_request_id; proxy_redirect off; proxy_pass http://app_server; } error_page 500 502 503 504 /500.html; location = /500.html { root /usr/src/app/public; } }
Railsの設定
require_relative 'boot' require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) module NginxProxyUuid class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 5.2 config.log_tags = [:request_id] # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. end end
ログのフォーマットはこんな感じ。
[43a62d59ee9f05db194539c71e113601] Started GET "/" for 172.20.0.2 at 2018-07-28 05:00:26 +0000 [43a62d59ee9f05db194539c71e113601] Cannot render console from 172.20.0.4! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 [43a62d59ee9f05db194539c71e113601] Processing by Rails::WelcomeController#index as HTML
*1:ここではNginxのアクセスログの設定を省略しているが、ちゃんとRequestIdを記録しておこう https://github.com/webuilder240/nginx_proxy_uuid_rails/blob/master/containers/nginx_tls/nginx.conf#L15