وظيفة Prometheus scrape لا يمكنها الوصول إلى المقاييس

لدي تثبيت discourse قيد التشغيل (اثنان في الواقع، واحد في مرحلة الاختبار والآخر في الإنتاج، آلات افتراضية مختلفة وكل شيء). أنا أختبر على بيئة الاختبار. تم التثبيت عبر الدليل الرسمي.

حاليًا، تم نشر مكدس Grafana/Prometheus/Node Exporter عبر docker compose على نفس الجهاز الافتراضي حيث تم نشر تثبيت discourse بالفعل.

هذا هو 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

لقد قمت بإعادة بناء discourse مع تحديد شبكة حتى لا يتم نشره على bridge وربط Prometheus بنفس الشبكة.

docker network create -d bridge discourse
/var/discourse/launcher rebuild app --docker-args '--network discourse'

لقد اختبرت عن طريق الدخول إلى حاوية Prometheus ورسم بياني لحاوية discourse باستخدام الاسم المستعار للشبكة الداخلية وتمكنت من الوصول إليها.

الآن، عند تكوين مهمة Prometheus لكشط المقاييس، باستخدام عنوان IP داخلي، لا أرى سوى 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 هو استبدال للاسم الفعلي للجهاز الافتراضي.

وفقًا للتوثيق هنا، يجب السماح بالوصول عبر عنوان IP الداخلي:

بشكل افتراضي، نسمح بمسار metrics للمسؤولين وعناوين IP الخاصة.

يرجى مساعدتي في معرفة ما الذي أفتقده :stuck_out_tongue:

لمزيد من التعمق في الأمر، حاولت إنشاء مفتاح API من Discourse والوصول إليه باستخدام الاسم المضيف الداخلي، والاستجابة ليست 301، وهذا صحيح لأن كل طلب يجب إعادة توجيهه إلى https.

أعتقد أن المشكلة هي أن الطلبات الواردة، حتى لو كانت من عنوان IP داخلي، تُعامل على أنها غير مصرح بها وتنتهي بـ 404 لهذا السبب.

هل لديك المكون الإضافي Prometheus مثبتًا ومُمكّنًا؟ يجب أن يسمح بطلبات من عناوين خاصة، ولكن يمكنك محاولة تعيين متغير البيئة للسماح بالوصول من عنوان IP الذي تسحب منه.

نعم، بروميثيوس موجود على نفس الجهاز الظاهري ومُنشأ كحاوية دوكر. كل شيء يعمل (لدي مُصدِّرات أخرى مُنشأة أيضًا) ولكن لسبب ما، فإن إضافة بروميثيوس لـ Discourse، حتى لو كانت تعمل بوضوح، لا تقبل الطلبات.

عندما تقول متغير البيئة، هل تقصد البيئة في ملف app.yaml الخاص بـ Discourse؟

إذًا، شيء كهذا:

env:
  DISCOURSE_PROMETHEUS_TRUSTED_IP_ALLOWLIST_REGEX: 172.20.0.3

172.20.0.3 هو عنوان IP الداخلي الحالي الذي سيحصل عليه بروميثيوس على شبكة دوكر الافتراضية التي يتصل بها Discourse أيضًا.

لقد حاولت بالفعل استخدام عنوان IP الخارجي الذي تشترك فيه جميع الحاويات على أي حال (عنوان 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 هو اسم شبكة الحاوية في شبكتها. الاسم صحيح، يمكنني اختباره من حاوية بروميثيوس قيد التشغيل.
ليس لدي أي فكرة من أين يأتي 127.0.0.11:53 بصراحة :thinking:

الرسالة هي نفسها إذا قمت بالتعليق على متغير البيئة.

أعتقد ذلك، لكنني لست متأكدًا تمامًا. يمكنك الاختبار من داخل الحاوية ومعرفة ما إذا كان بإمكانك استخدام curl من هناك.

تشغيل أمر wget من حاوية prometheus يُرجع:

/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 لاسم النطاق العام وهو عنوان IP داخلي لـ Cloudflare وهذا بالطبع يطلب من أي طلب العودة.

الآن هذا ليس هو النقطة المهمة لأن هذا التوجيه لا ينبغي أن يحدث لمسار الرابط http://yourwebsite.com/metrics إذا كان قادمًا من عنوان IP داخلي وكنت أتوقع أن يقوم المكون الإضافي بالتعامل مع ذلك عن طريق إضافة تكوين nginx يضيف هذه القاعدة والتي يبدو أنها لا تحدث؟

هل يمكن لأحد مطوري Discourse التدخل؟ لا أريد أن أزعج الأشخاص عشوائيًا ويبدو غريبًا أن لا أحد قد أبلغ عن هذه المشكلة من قبل.

تعديل: قمت بإعادة البناء مع تحديد اسم مضيف ثابت لتكوين الشبكة لأنني لاحظت أنه في كل إعادة بناء يتم تعيين اسم عشوائي جديد للحاوية.
بعد ذلك، حاولت أيضًا تعيين مهمة prometheus للوصول إلى إصدار https للمقاييس ولكن المشكلة تعود إلى الخطوة الأولى:

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

في هذه المرحلة، يبدو أن هذه مشكلة في المكون الإضافي نفسه.

يبدو صحيحًا. تحتاج إلى الوصول إليه باستخدام اسم المضيف، وليس اسم الحاوية.

أنا أستخدم اسم المضيف، لقد كتبت الكثير وفي وقت متأخر، ربما كان مربكًا ولكني بالتأكيد أستخدم اسم المضيف للشبكة الداخلية.

هذا ليس مجال خبرتي، لكنني قمت بالبحث في المنشورات التي ابتلعها مؤقت الموضوع لمعرفة ما إذا كان أي منها ذا صلة، وربما وجدت هذه؟ (أعتذر إذا كنت مخطئًا تمامًا :slight_smile: :pray: )

شكراً @JammyDodger ولكن للأسف لم تساعد تلك الموارد.

لديهم مشكلة مماثلة ولكنها مختلفة قليلاً لدرجة أنها لا تنطبق في هذه الحالة.
للتأكد، جربت ما اقترحه أحد تلك المواضيع (بالإضافة إلى @pfaffman) وتلاعبت بمتغير البيئة DISCOURSE_PROMETHEUS_TRUSTED_IP_ALLOWLIST_REGEX.

لقد اختبرت:

  • التعليق عليه
  • إضافته بقيمة IP داخلية
  • إضافته بقيمة IP خارجية

جربت أيضًا تغيير مهمة فحص Prometheus لمعالجة تثبيت Discourse كـ:

  • عنوان IP داخلي مباشر
  • اسم مضيف داخلي لـ Docker
  • عنوان IP خارجي مباشر
  • اسم نطاق عام

في كل حالة، جربت كلاً من http و https.

في جميع الحالات، أحصل على 404.
ما أتوقعه هو استجابة الصفحة الفعلية حيث أن الطلب قادم من عنوان IP داخلي.

إعجاب واحد (1)

ما قصده جاي هنا هو أنك تحتاج إلى استخدام اسم المضيف المُكوَّن (DISCOURSE_HOSTNAME في تعريف ملف .yml الخاص بالحاوية) بدلاً من أي اسم مضيف يحل إلى عنوان IP الصحيح.

هذا متعمد، بحيث لا يمكنك بسهولة عكس وكيل نسخة عامة من أي مكان، ولذلك يتم قبول اسم المضيف المُكوَّن فقط:

$ 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
[...]

# ما يلي يعادل إنشاء سجل DNS في
# try.somebogusreverseproxy.com يشير إلى نفس عنوان IP مثل try.discourse.org،
# ثم طلب 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

يجب أن يعمل، ولكنه حل مؤقت. التوقع هو أنك ستقوم بإعداد DNS حسب الحاجة حتى يمكن الوصول إلى Discourse باسم المضيف المُكوَّن بشفافية:

curl -I https://YOUR_CONFIGURED_HOSTNAME/metrics

كيفية القيام بذلك يعتمد بشكل كبير على متطلباتك، ولكن أبسط خيار هو إعداد اسم مستعار في /etc/hosts من حيث تنشأ طلبات HTTP الخاصة بك.

3 إعجابات

لا يعمل مُصدِّر Prometheus على المنفذ 80 - فهو يستمع على منفذه الخاص. افتراضيًا المنفذ 9405.

5 إعجابات

اكتشاف جيد ولكن إذا حاولت استهداف هذا المنفذ المحدد، أحصل على رسالة “تم رفض الاتصال”.

Get "http://discourse_app:9405/metrics": dial tcp 172.20.0.2:9405: connect: connection refused

تم الاختبار باستخدام wget من داخل حاوية prometheus أيضًا للتأكد.

/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 بسيطة) ولكن تم الوصول إلى المقاييس على أي حال.

إذًا، ما تقوله هو أنه يجب عليّ إيجاد طريقة لجعل الحاوية التي تشغل prometheus تحتوي على إدخال في /etc/hosts يحل… لقد فقدتك هناك آسف :slight_smile:

ما قمت به هو إضافة حاوية Docker أخرى تحتوي ببساطة على nginx وتقديم تكوين وكيل أمامي يضيف الرأس 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)

للتوثيق فقط، لدي مستودع قمت فيه بإعداد كل ما هو ضروري.
هناك بعض القيم المكتوبة بشكل ثابت (مثل اسم النطاق المؤهل بالكامل لموقعنا الإلكتروني في ملف تكوين الوكيل الأمامي) والتي ستحتاج إلى تغيير في حالة رغبة شخص آخر في استخدامه، ولكن ربما يمكن أن يكون مفيدًا لشخص آخر هناك.

يتضمن كل شيء، من docker compose إلى تكوين nginx وتوفير grafana للموارد ولوحات المعلومات.

هذا بسبب السطر التالي:

GlobalSetting.add_default :prometheus_collector_port, 9405
GlobalSetting.add_default :prometheus_webserver_bind, "localhost"
GlobalSetting.add_default :prometheus_trusted_ip_allowlist_regex, ""

الربط بـ 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 هذه تتحدث الآن إلى prometheus عبر عنوان IP localhost.

إذا لم تكن متأكدًا من عناوين 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
…

هذا هو خادم الأسماء الذي يرفض طلب البحث عن عنوان IP لـ vmi1187507-app. المنفذ 53 هو DNS.

إعجابَين (2)

هذا رائع يا مايكل، شكراً لك على تخصيص الوقت لكتابته.

سأقوم باختباره خلال عطلة نهاية الأسبوع حيث أنني قضيت بالفعل وقتاً طويلاً خلال أيام عملي لهذا الأسبوع :stuck_out_tongue:

خلال محاولاتي، حاولت إضافة عنوان IP الداخلي الذي سيظهر منه الحاوية مع Prometheus على أنه يطلب المقاييس إلى DISCOURSE_PROMETHEUS_TRUSTED_IP_ALLOWLIST_REGEX ولكنه لم ينجح.

أنت تقترح DISCOURSE_PROMETHEUS_WEBSERVER_BIND. هل لي أن أسأل من أين حصلت عليه؟ أفترض أنه متغير بيئة آخر لإضافته إلى ملف app.yml، صحيح؟

كيف لم يعمل؟

إذا فشل الاتصال، فلن يكون لإعداد القائمة المسموح بها أي أهمية لأنه يعمل بعد اتصال L4.

هناك سحر :magic_wand: في قاعدة كود Discourse حيث إذا قمت بتعيين DISCOURSE_SITE_OR_GLOBAL_SETTING_NAME في ENV فسيتم تجاوزه.

لذلك فإن تعيين ذلك سيتجاوز:

GlobalSetting.add_default :prometheus_webserver_bind, "localhost"

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.