本文の内容は、2022年6月30日にJesus Ángel Samitierが投稿したブログ(https://sysdig.com/blog/monitor-nginx-prometheus/)を元に日本語に翻訳・再構成した内容となっております。
nginx はオープンソースのウェブサーバーで、リバースプロキシ、ロードバランサー、ウェブキャッシュとしてよく利用されます。高負荷の同時接続用に設計されており、高速で汎用性が高く、信頼性が高く、そして最も重要なのは、リソースの消費が非常に少ないことです。この記事では、Prometheusを使ってKubernetes上のnginxを監視する方法と、レイテンシーやサチュレーションなどに関するさまざまな問題をトラブルシューティングする方法について説明します。
構成要素
始める前に、このプロジェクトで使用するツールをまとめておきましょう。- nginx サーバ (きっとあなたのクラスターですでに動いているはずです!)
- オープンソースの監視標準である Prometheus
- 公式の nginx exporter
- Fluentd と Prometheus 用プラグイン
基本から始める:nginx exporter
Kubernetes上でnginxをPrometheusで監視する場合、まず最初に必要なことはnginx exporterのインストールです。推奨は、nginxサーバのサイドカーとして、デプロイメントに追加するだけでインストールできるようにすることです。以下のような内容である必要があります:apiVersion: apps/v1 kind: Deployment metadata: name: nginx-server spec: selector: matchLabels: null app: nginx replicas: 3 template: metadata: labels: app: nginx annotations: prometheus.io/scrape: 'true' prometheus.io/port: '9113' spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: nginx-config mountPath: /etc/nginx/conf.d/default.conf subPath: nginx.conf - name: nginx-exporter image: 'nginx/nginx-prometheus-exporter:0.10.0' args: - '-nginx.scrape-uri=http://localhost/nginx_status' resources: limits: memory: 128Mi cpu: 500m ports: - containerPort: 9113 volumes: - configMap: defaultMode: 420 name: nginx-config name: nginx-config
このようにすると、各 nginx サーバー Pod に nginx exporter コンテナが追加さ れることになります。レプリカを 3 つ作成したので、3 つの Pod が作成され、それぞれに 1 つの nginx サーバー コンテナと 1 つの nginx エクスポーター コンテナが含まれることになります。この新しい設定を適用すると、完了です! nginx サーバーから簡単にメトリクスを公開することができます。
Prometheus で nginx 全体のステータスを監視する
うまくいったかどうか確認したいですか?簡単です。Prometheus にアクセスして、以下の PromQL を試してみてください。sum (nginx_up)
これで、3つのコンテナで nginx_up が1つになったと報告されます。メトリクスのことはまだ気にしないでください。
Prometheus で nginx 接続を監視する
アクティブな接続
以下のメトリクスを使って、nginx のアクティブな接続を見てみましょう。どれが読み書きを行っているかに注目することもできます。nginx_connections_active
nginx_connections_reading
nginx_connections_writing
これらを使うだけで、こんな感じになります:
未処理の接続
では、nginx で処理されていないコネクションがどれだけあるかに着目してみましょう。受理されたコネクションから処理されたコネクションを取り除けばいいのです。nginx exporter は両方のメトリクスを提供してくれます。nginx_connections_handled
nginx_connections_accepted
では、受け付けられたコネクションのうち、処理されないコネクションの割合を求めてみましょう:
rate(nginx_connections_accepted{kube_cluster_name=~$cluster}[$__interval]) - rate(nginx_connections_handled{kube_cluster_name=~$cluster}[$__interval]) or vector(0) / rate(nginx_connections_accepted{kube_cluster_name=~$cluster}[$__interval]) * 100
PromQL をもっと深く知りたいですか?Prometheusがどのようにデータを保存し、PromQLの関数や演算子をどのように使用するかについては、PromQLの入門ガイドをお読みください。
うまくいけば、この数字はゼロに近くなりますよ!
接続待ち
幸いなことに、これも簡単なクエリーです。nginx_connections_waiting
と入力するだけです。これは nginx exporter がこの情報を公開するために使用するメトリクスです。もっとメトリクスが必要ですか?ログから取得しましょう!
PrometheusでKubernetesのnginxを監視するためにさらに情報が必要な場合、nginxのaccess.log
を使ってもう少し情報を取得することができます。その方法を見てみましょう。オープンソースのデータコレクターであるFluentd
Fluentdを設定することで、nginxのaccess.logから情報を拾って、Prometheusのメトリクスに変換することができます。これは、インスツルメンテッド・アプリケーションがあまり情報を公開しないような状況において、とても便利です。Fluentd のインストールと設定方法
FluentdとそのPrometheusプラグインについては、すでにここで説明しましたので、その記事の指示に従うだけで、準備は完了します。Fluentd を設定して、さらにいくつかのメトリクスをエクスポートするようにしましょう
これを行うには、access.log
フォーマットを少し調整する必要があります。デフォルトのログ形式を選択し、最後に $upstream_response_time
を追加します。 このように、Fluentdはこの変数を持ち、それを使用していくつかの有用なメトリクスを作成します。name: nginx-config data: nginx.conf: | log_format custom_format '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$upstream_response_time'; server { access_log /var/log/nginx/access.log custom_format; ... }
この設定は
nginx.conf
、通常は ConfigMap
に記述します。次に、Fluentd が新しいログのフォーマットを読み込むように設定する必要があります。これは Fluentd の
fileConfig
セクションに nginx 用の新しい config を作成することでできます。<source> @type prometheus_tail_monitor </source> <source> @type tail <parse> @type regexp expression /^(?<timestamp>.+) (?<stream>stdout|stderr)( (.))? (?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] \"(?<method>\w+)(?:\s+(?<path>[^\"]*?)(?:\s+\S*)?)?\" (?<status_code>[^ ]*) (?<size>[^ ]*)(?:\s"(?<referer>[^\"]*)") "(?<agent>[^\"]*)" (?<urt>[^ ]*)$/ time_format %d/%b/%Y:%H:%M:%S %z keep_time_key true types size:integer,reqtime:float,uct:float,uht:float,urt:float </parse> tag nginx path /var/log/containers/nginx*.log pos_file /tmp/fluent_nginx.pos </source> <filter nginx> @type prometheus </filter>
この設定で、基本的には nginx の access.log 用の正規表現パーサーを作成しました。これは
expression
の設定です。expression /^(?<timestamp>.+) (?<stream>stdout|stderr)( (.))? (?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] \"(?<method>\w+)(?:\s+(?<path>[^\"]*?)(?:\s+\S*)?)?\" (?<status_code>[^ ]*) (?<size>[^ ]*)(?:\s"(?<referer>[^\"]*)") "(?<agent>[^\"]*)" (?<urt>[^ ]*)$/
例えば、このログ行を見てみましょう:
2022-06-07T14:16:57.754883042Z stdout F 100.96.2.5 - - [07/Jun/2022:14:16:57 +0000] "GET /ok/500/5000000 HTTP/1.1" 200 5005436 "-" "python-requests/2.22.0" 0.091
パーサーで、そのログ行を以下の部分に分解してみました:
timestamp: 2022-06-07T14:16:57.754883042Z
stream: stdout
remote: 100.96.2.5
host: -
user: -
time: 07/Jun/2022:14:16:57 +0000
method: GET
path: /ok/500/5000000
status_code: 200
size: 5005436
referer: -
agent: python-requests/2.22.0
urt: 0.091
これで、Fluentd が access.log を読むように設定されたので、パーサーから得られたこれらの変数を使用して、いくつかのメトリクスを作成することができます。
nginx 送信バイト数
size
変数を使って nginx_size_bytes_total
メトリクスを作成することができます: nginx の総送信バイト数を表すカウンターです。<metric> name nginx_size_bytes_total type counter desc nginx bytes sent key size </metric>
エラーレート
このシンプルなメトリクスを作成してみましょう:<metric> name nginx_request_status_code_total type counter desc nginx request status code <labels> method ${method} path ${path} status_code ${status_code} </labels> </metric>
このメトリクスは、すべてのログ行をカウンターにしただけのものです。では、なぜそれが有用なのでしょうか?まあ、他の変数をラベルとして使うことができるので、すべての情報を分解するのに便利でしょう。このメトリクスを使って、全体のエラー率パーセンテージを取得してみましょう:
sum(rate(nginx_request_status_code_total{status_code=~"[4|5].."}[1h])) / sum(rate(nginx_request_status_code_total[1h])) * 100
また、この情報を
method
別に集計して得ることもできます:sum by (method) (rate(nginx_request_status_code_total{status_code=~"[4|5].."}[1h])) / sum by (method) (rate(nginx_request_status_code_total[1h]))
あるいは、 path別でも:
sum by (path) (rate(nginx_request_status_code_total{status_code=~"[4|5].."}[1h])) / sum by (path) (rate(nginx_request_status_code_total[1h]))
レイテンシー
成功したリクエストのレイテンシーを監視できたら素晴らしいと思いませんか?そうです、あなたの誕生日かもしれません! なぜなら、それができるからです。$upstream_response_time
変数を追加するように指示したのを覚えていますか?この変数はアップストリームサーバーからレスポンスを受け取るのに費やされた時間を秒単位で保存します。Fluentdでヒストグラムのメトリクスを作成するには、このようにします:
<metric> name nginx_upstream_time_seconds_hist type histogram desc Histogram of the total time spent on receiving the response from the upstream server. key urt <labels> method ${method} path ${path} status_code ${status_code} </labels> </metric>
さて、魔法のように、この PromQL クエリーを試すと、成功したすべてのリクエストのレイテンシーを、リクエストのパスによって集約して p95 で取得することができます。
histogram_quantile(0.95, sum(rate(nginx_upstream_time_seconds_hist_bucket{status_code !~ "[4|5].."}[1h])) by (le, path))