Crius
(Crius)
2023 年 5 月 13 日午後 5:23
1
すでに Discourse のインストールが稼働しています(実際には 2 つあり、ステージングと本番で、それぞれ異なる VM です)。ステージング環境でテストしています。インストールは公式ガイド に従って行いました。
現在、Discourse が既にデプロイされているのと同じ VM に、docker compose を介して Grafana/Prometheus/Node Exporter スタックがデプロイされています。
以下は docker-compose.yaml です。
version: "3"
services:
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
restart: unless-stopped
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
networks:
- prometheus-cadvisor
node_exporter:
image: quay.io/prometheus/node-exporter:latest
container_name: node_exporter
command:
- '--path.rootfs=/host'
pid: host
restart: unless-stopped
volumes:
- '/:/host:ro,rslave'
networks:
- prometheus-node_exporter
prometheus:
image: prom/prometheus:latest
restart: unless-stopped
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus:/app.cfg
networks:
- world
- prometheus-cadvisor
- prometheus-node_exporter
- discourse
- grafana-prometheus
command: >-
--config.file=/app.cfg/prometheus.yaml
--storage.tsdb.path=/prometheus
--web.console.libraries=/usr/share/prometheus/console_libraries
--web.console.templates=/usr/share/prometheus/consoles
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
ports:
- "3000:3000"
environment:
GF_SECURITY_ADMIN_USER: [OMITTED]
GF_SECURITY_ADMIN_PASSWORD: [OMITTED]
GF_PATHS_PROVISIONING: '/app.cfg/provisioning'
volumes:
- ./grafana:/app.cfg
- ./grafana/provisioning:/etc/grafana/provisioning
networks:
- world
- grafana-prometheus
networks:
world:
grafana-prometheus:
internal: true
prometheus-cadvisor:
internal: true
prometheus-node_exporter:
internal: true
discourse:
external: true
bridge ではなくネットワークを指定して Discourse を再構築し、Prometheus を同じネットワークに接続しました。
docker network create -d bridge discourse
/var/discourse/launcher rebuild app --docker-args '--network discourse'
Prometheus コンテナに入り、内部ネットワークエイリアスを使用して Discourse コンテナに ping を送信したところ、到達可能であることを確認しました。
現在、内部 IP を使用してメトリクスをスクレイピングするように Prometheus ジョブを設定していますが、「server returned HTTP status 404 Not Found」しか表示されません。
以下は Prometheus の設定です。
global:
scrape_interval: 30s
scrape_timeout: 10s
rule_files:
scrape_configs:
- job_name: prometheus
metrics_path: /metrics
static_configs:
- targets:
- 'prometheus:9090'
- job_name: node_exporter
static_configs:
- targets:
- 'node_exporter:9100'
- job_name: discourse_exporter
static_configs:
- targets:
- 'vmuniqueID-app:80'
vmuniqueID は実際の VM 名の置き換えです。
ドキュメントこちら によると、内部 IP 経由でのアクセスは許可されるはずです。
デフォルトで、metrics ルートは管理者とプライベート IP に許可されます。
何が不足しているか教えていただけますでしょうか
Crius
(Crius)
2023 年 5 月 13 日午後 5:47
2
さらに詳しく調べるために、DiscourseからAPIキーを生成し、内部ホスト名を使用してそれに到達しようとしましたが、応答は301ではありませんでした。これは、すべてのリクエストがhttpsにリダイレクトされることになっているため、正しいです。
問題は、内部IPからのリクエストであっても、承認されていないと見なされ、その結果404になることだと私は思います。
pfaffman
(Jay Pfaffman)
2023 年 5 月 14 日午前 2:14
3
Prometheus プラグインがインストールされ、有効になっていることを確認しましたか?プライベートアドレスからのリクエストを許可するはずですが、取得元の IP からのアクセスを許可するように環境変数を設定することもできます。
Crius
(Crius)
2023 年 5 月 14 日午後 10:04
4
はい、Prometheus は同じ VM 上にあり、Docker コンテナとしてデプロイされています。すべて正常に動作していますが(他のエクスポーターもデプロイされています)、なぜか Discourse Prometheus プラグインは、明らかに稼働しているにもかかわらず、リクエストを受け付けていません。
ENV 変数について話しているとき、Discourse の app.yaml ファイル内の環境について話していますか?
では、このような感じでしょうか?
env:
DISCOURSE_PROMETHEUS_TRUSTED_IP_ALLOWLIST_REGEX: 172.20.0.3
172.20.0.3 は、Discourse も接続されている Docker 仮想ネットワーク上の Prometheus の現在の内部 IP です。
コンテナが互いにアクセスする場合、内部 IP を介してアクセスするため、すべてのコンテナが共有している外部 IP(VM の静的 IP)を使用することも試しましたが、同じネットワーク上にあるため、内部 IP を介してアクセスします。
./launcher restart app で環境変数が認識されるはずですよね?
その場合、以下のようになります。
Get "http://vmi1187507-app:80/metrics": dial tcp: lookup vmi1187507-app on 127.0.0.11:53: server misbehaving
vmi1187507-app は、そのネットワーク内のコンテナネットワーク名です。名前は正しく、Prometheus コンテナから ping できることを確認しました。
正直なところ、127.0.0.11:53 がどこから来ているのか全く分かりません
環境変数をコメントアウトしても、メッセージは同じです。
pfaffman
(Jay Pfaffman)
2023 年 5 月 14 日午後 10:18
5
そう思います が、確信はありません。コンテナ内から curl が実行できるか試してみてください。
Crius
(Crius)
2023 年 5 月 14 日午後 10:33
6
Prometheus コンテナから wget を実行すると、次のエラーが返されます。
/prometheus # wget http://vmi1229594-app:80/metrics
Connecting to vmi1229594-app:80 (172.20.0.2:80)
Connecting to [public URL] (172.67.69.84:443)
wget: note: TLS certificate validation not implemented
wget: server returned error: HTTP/1.1 404 Not Found
これは、Discourse の nginx コンテナからの自動リダイレクトが原因だと推測していますか?
発生しているのは、パブリックドメイン名の HTTPS に転送されることで、これは内部 Cloudflare IP であり、当然ながらリクエストを戻すように指示されます。
しかし、これは本題ではなく、内部 IP からのリクエストの場合、パス URL http://yourwebsite.com/metrics に対してこのリダイレクトが発生するはずではなく、プラグインがこれを処理し、このルールを追加する nginx 設定を追加することを期待していましたが、そうはなっていないようです。
Discourse の開発者の方、どなたかコメントいただけますか?ランダムに人を ping したり、この問題を報告した人が誰もいないのが奇妙だと感じたりしたくありません。
編集:ネットワーク設定の静的ホスト名を指定して再構築しました。これは、再構築ごとにコンテナに新しいランダムなホスト名が割り当てられていることに気づいたためです。
その後、metrics の HTTPS バージョンにアクセスするように Prometheus ジョブを設定しようとしましたが、問題はステップ 1 に戻ります。
global:
scrape_interval: 30s
scrape_timeout: 10s
rule_files:
scrape_configs:
# other jobs
# [...]
- job_name: discourse_exporter
scheme: https
tls_config:
insecure_skip_verify: true
static_configs:
- targets:
- 'discourse_app'
/prometheus # wget https://discourse_app/metrics
Connecting to discourse_app (172.20.0.2:443)
wget: note: TLS certificate validation not implemented
Connecting to [public URL] (104.26.4.193:443)
wget: server returned error: HTTP/1.1 404 Not Found
この時点で、これはプラグイン自体の問題のようです。
pfaffman
(Jay Pfaffman)
2023 年 5 月 15 日午前 12:40
7
そのようですね。コンテナ名ではなく、ホスト名を使用してアクセスする必要があります。
Crius
(Crius)
2023 年 5 月 15 日午前 7:42
8
ホスト名を使用しています。たくさん書いてしまい、遅くなってしまったので、混乱を招いたかもしれませんが、間違いなく内部ネットワークのホスト名を使用しています。
Crius
(Crius)
2023 年 5 月 15 日午前 10:21
10
@JammyDodgerさん 、ありがとうございます。残念ながら、それらのリソースは役に立ちませんでした。
それらは似たような問題を抱えていますが、このケースには適用できないほどわずかに異なります。
念のため、それらのトピックのいずれかが提案したこと(@pfaffmanも同様 )を試しました。そして、DISCOURSE_PROMETHEUS_TRUSTED_IP_ALLOWLIST_REGEX 環境変数で遊びました。
試したのは次のとおりです。
コメントアウトする
内部IP値を追加して
外部IP値を追加して
Prometheusのスクレイプジョブを変更して、Discourseのインストールを次のようにアドレス指定することも試しました。
直接の内部IP
Dockerの内部ホスト名
直接の外部IP
公開ドメイン名
すべてのケースで、httpとhttpsの両方を試しました。
すべてのケースで、404エラーが発生します。
リクエストは内部IPから来ているので、実際のページの応答が期待されるものです。
「いいね!」 1
leonardo
(Leonardo Mosquera)
2023 年 5 月 15 日午後 4:41
11
Jay がここで言いたかったのは、正しい IP アドレスに解決される任意の名前ではなく、設定されたホスト名(コンテナの .yml 定義の DISCOURSE_HOSTNAME)を使用する必要があるということです。
これは意図的なものであり、どこからでもパブリックインスタンスを簡単にリバースプロキシできないようにするため、また設定されたホスト名のみが受け入れられるようにするためです。
$ curl -I https://try.discourse.org/about.json
HTTP/2 200
server: nginx
date: Mon, 15 May 2023 16:25:05 GMT
content-type: application/json; charset=utf-8
[... ]
# 次のものは、try.discourse.org と同じ IP アドレスを指す
# try.somebogusreverseproxy.com で DNS レコードを作成し、
# 次に https://try.somebogusreverseproxy.com/about.json をリクエストするのと同等です。
$ curl -H 'Host: try.somebogusreverseproxy.com' -I https://try.discourse.org/about.json
HTTP/2 404
cache-control: no-cache
content-length: 1427
content-type: text/html
cdck-proxy-id: app-router-tiehunter02.sea1
cdck-proxy-id: app-balancer-tieinterceptor1b.sea1
逆に、次を試すと:
curl -H 'Host: YOUR_CONFIGURED_HOSTNAME' -I https://discourse_app/metrics
機能するはずですが、これはハックです。期待されるのは、Discourse が設定されたホスト名で透過的に到達できるように、必要に応じて DNS を設定することです。
curl -I https://YOUR_CONFIGURED_HOSTNAME/metrics
その方法は要件によって大きく異なりますが、最も簡単なオプションは、HTTP リクエストの発信元から /etc/hosts にエイリアスを設定することです。
「いいね!」 3
Prometheus exporterはポート80では実行されません。独自のポートでリッスンします。デフォルトではポート9405 です。
「いいね!」 5
Crius
(Crius)
2023 年 5 月 16 日午前 10:28
13
見つけましたが、その特定のポートをターゲットにしようとすると、「接続拒否」メッセージが表示されます。
Get "http://discourse_app:9405/metrics": dial tcp 172.20.0.2:9405: connect: connection refused
念のため、Prometheusコンテナ内からwgetでテストしました。
/prometheus # ping discourse_app
PING discourse_app (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.223 ms
64 bytes from 172.20.0.2: seq=1 ttl=64 time=0.270 ms
^C
--- discourse_app ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.223/0.246/0.270 ms
/prometheus # wget discourse_app:9405/metrics
Connecting to discourse_app:9405 (172.20.0.2:9405)
wget: can't connect to remote host (172.20.0.2): Connection refused
はい、wgetでテストしました(prometheusコンテナは最小限のbusyboxです)が、それでもmetricsには到達しました。
つまり、Prometheusを実行しているコンテナに/etc/hostsエントリがあり、それが解決されるようにする方法を見つける必要があるということですか?すみません、そこまではわかりませんでした
私がやったことは、単にnginxを含む別のDockerを追加し、受信したリクエストにHostヘッダーを追加するフォワードプロキシ設定を提供することです。ポートは公開されていないため、内部仮想ネットワークからのみアクセスできます。
では、どのように変更されますか?
Prometheus Job:
- job_name: discourse_exporter_proxy
scheme: http
static_configs:
- targets:
- 'discourse_forward_proxy:8080'
docker-compose.yaml(プロキシの部分のみ)
version: "3"
services:
# [...]
discourse_forward_proxy:
image: nginx:latest
container_name: discourse_forward_proxy
restart: unless-stopped
volumes:
- ./discourse_forward_proxy/:/etc/nginx/conf.d
networks:
- prometheus-discourse_forward_proxy
- discourse
# [...]
networks:
prometheus-discourse_forward_proxy:
internal: true
discourse:
external: true
docker-compose.yamlがあるディレクトリに、./discourse_forward_proxy/discourse_forward_proxy.confを配置してください。
server {
listen 8080;
location /metrics {
proxy_set_header Host "YOUR_DOMAIN_HERE.COM";
proxy_pass https://discourse_app/metrics;
}
}
どうぞ:
「いいね!」 1
Crius
(Crius)
2023 年 5 月 16 日午後 12:17
14
後々のために、必要なものをすべて設定したリポジトリを用意しました。
フォワードプロキシの設定ファイルにあるウェブサイトのFQDNのようなハードコードされた値は、他の人が使用したい場合に変更する必要がありますが、他の誰かの役に立つかもしれません。
Docker ComposeからNginxの設定、リソースとダッシュボードのGrafanaプロビジョニングまで、すべてが含まれています。
Contribute to netgamers-forum/ngi-monitor-stack development by creating an account on GitHub.
これは次の行によるものです。
GlobalSetting.add_default :prometheus_collector_port, 9405
GlobalSetting.add_default :prometheus_webserver_bind, "localhost"
GlobalSetting.add_default :prometheus_trusted_ip_allowlist_regex, ""
localhost にバインドすると、localhost IP でのみ接続できるため、172.20.0.2 への接続が失敗します。これは、意図したよりもはるかに広い範囲のオーディエンスに誤って公開されないようにするためのセキュリティ対策です。
コンテナ定義ファイルで次のように設定した場合:
DISCOURSE_PROMETHEUS_WEBSERVER_BIND: '*'
すべての IP アドレスでリッスンするようになり、別のコンテナから接続できるようになります。
これが機能した理由:
server {
listen 8080;
location /metrics {
proxy_set_header Host "YOUR_DOMAIN_HERE.COM";
proxy_pass https://discourse_app/metrics;
}
}
これは、この nginx コンテナが現在 localhost IP を介して prometheus と通信しているためです。
サービスがリッスンしている IP またはポートがわからない場合は、コンテナ内で ss -ltp または netstat -ltp(それぞれ必要なパッケージは net-tools および iproute2)を使用して確認できます。たとえば、prometheus プラグインでコンテナを再構築したところ、次のようになりました。
root@discourse-docker-app:/# ss -ltp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 127.0.0.1:3000 0.0.0.0:*
LISTEN 0 128 0.0.0.0:postgresql 0.0.0.0:*
LISTEN 0 128 0.0.0.0:https 0.0.0.0:* users:(("nginx",pid=555,fd=7))
LISTEN 0 128 127.0.0.1:9405 0.0.0.0:*
LISTEN 0 128 0.0.0.0:redis 0.0.0.0:*
LISTEN 0 128 0.0.0.0:http 0.0.0.0:* users:(("nginx",pid=555,fd=6))
LISTEN 0 128 [::]:postgresql [::]:*
LISTEN 0 128 [::]:https [::]:* users:(("nginx",pid=555,fd=8))
LISTEN 0 128 [::]:redis [::]:*
root@discourse-docker-app:/# curl http://172.17.0.2:9405/metrics
curl: (7) Failed to connect to 172.17.0.2 port 9405: Connection refused
root@discourse-docker-app:/# curl http://localhost:9405/metrics
# HELP discourse_collector_working Is the master process collector able to collect metrics
# TYPE discourse_collector_working gauge
discourse_collector_working 1
# HELP discourse_collector_rss total memory used by collector process
# TYPE discourse_collector_rss gauge
discourse_collector_rss 38178816
…
それは、vmi1187507-app の IP ルックアップ要求を拒否しているネームサーバーです。ポート 53 は DNS です。
「いいね!」 2
Crius
(Crius)
2023 年 5 月 16 日午後 11:18
19
マイケル、素晴らしい内容をまとめてくれてありがとう。
今週は仕事で時間を使いすぎたので、週末にテストしてみます
試している間に、Prometheusコンテナがメトリクスをリクエストする際の内部IPを DISCOURSE_PROMETHEUS_TRUSTED_IP_ALLOWLIST_REGEX に追加しようとしましたが、うまくいきませんでした。
DISCOURSE_PROMETHEUS_WEBSERVER_BIND を提案されていますが、これはどこから情報を得たのでしょうか? app.yml ファイルに追加する別の環境変数だと仮定してよろしいでしょうか?
Crius:
しかし、うまくいきませんでした
どのように うまくいかなかったのですか?
接続に失敗した場合、allowlistの設定は関係ありません。なぜなら、それはL4接続の後に 動作するからです。
Crius:
どこからそれを取得したのか教えていただけますか?
Discourseのコードベースには魔法 があり、ENVでDISCOURSE_SITE_OR_GLOBAL_SETTING_NAMEを設定すると、それをオーバーライドします。
したがって、それを設定すると、以下がオーバーライドされます。
GlobalSetting.add_default :prometheus_webserver_bind, "localhost"
system
(system)
クローズされました:
2023 年 6 月 16 日午前 12:08
21
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.