Разоблачение Grafana из Docker за Nginx

Фон

В моем стеке приложений используется несколько контейнеров Docker, управляемых docker compose:

  • PostgreSQL на порту 5433
  • Серверная часть FastAPI (Python) на порту 8000
  • Внешний интерфейс NodeJS на порту 8090 и доступ к порту 80 (через Nginx, см. далее)
  • pgAdmin на порту 5050
  • Регистрация Prometheus на порту 9090
  • Графана в порту 3090

См. информацию о контейнере, возвращенную docker-compose ps:

Конфигурация компоновки Docker

Контейнеры отображаются в конфигурации docker-compose.override.yml следующим образом:

version: "3.8"

services:

  pgadmin:
    ports:
      - "5050:5050"

  frontend:
    ports:
      - "8090:80"

  prometheus:
    ports:
      - "9090:9090"

  grafana:    
    ports:
      - "3090:3090"

Конфигурация внутреннего прокси

Внутри внешнего контейнера есть прокси-сервер Nginx, который управляет маршрутизацией портов внутри стека приложений. Его конфиг такой:

server {
        listen 80;
        server_name     example.com;

        gzip            on;
        gzip_types      text/plain application/xml text/css application/javascript application/json;
        gzip_min_length 1000;

        charset                                   utf-8;     
        include                                   /etc/nginx/mime.types;
        client_max_body_size                      20M;

        root                                      /usr/share/nginx/html;

        location / {
            expires                               $expires;
            index                                 index.html index.htm;
            try_files                             $uri $uri/ /index.html;
        }

        location /api/ {
            proxy_pass                          http://backend:8000/;
            proxy_http_version                  1.1;
            proxy_set_header                    Host             $host;
            proxy_set_header                    X-Real-IP        $remote_addr;
            proxy_set_header                    X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_read_timeout                  1800;
            proxy_connect_timeout               1800;
        }
}

Конфигурация хост-прокси

Сам хост имеет работающий прокси-сервер Nginx, настроенный просто так:

server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name     _;

        location / {
            proxy_pass                          http://127.0.0.1:8090/;
            proxy_set_header                    Host              $host;
            proxy_set_header                    X-Real-IP         $remote_addr;
            proxy_set_header                    X-Forwarded-For   $proxy_add_x_forwarded_for;
            proxy_set_header                    X-Forwarded-Proto $scheme;
        }
}

Вопрос

Я хочу иметь возможность просматривать панель инструментов Grafana из http://<myip>:3090 и pgAdmin из http://<myip>:5050, но в настоящее время браузер возвращает «Страница не найдена (404)» (без заголовка Nginx). Когда я пытаюсь http://<myip>:3000 (видя, что Grafana также работает на 3000, хотя я явно установил его на 3090), я получаю ту же ошибку.

При этом я как-то могу получить доступ к Prometheus по адресу http://<myip>:9090... Но не к Grafana или pgAdmin. Что я упустил?

Этот вопрос выиграет от минимального воспроизводимого примера - в идеале, полного docker-compose.yaml, который мы можем скопировать и запустить локально, чтобы воспроизвести поведение, о котором вы спрашиваете.

larsks 02.05.2023 00:59

Запускаемый пример невозможен, поскольку файлы контейнера docker влекут за собой множество зависимостей, таких как python venv с пакетами, установка NodeJS и т. д. и т. д. Проблема явно где-то в конфигах Nginx.

s0mbre 02.05.2023 01:05

Я думаю, вы неправильно поняли, что означает «минимальная» часть в минимальном воспроизводимом примере; исполняемый пример абсолютно возможен и должен содержать только те службы, о которых вы спрашиваете в этом вопросе. Если бы вы расширили существующий пример, все было бы готово.

larsks 02.05.2023 01:07
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
3
83
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я немного смущен вашими целями; ваш заголовок «Разоблачение Grafana из Docker за Nginx», но похоже, что вы планируете получить доступ к Grafana таким образом, чтобы обойти nginx, опубликовав порт на хосте и получив к нему прямой доступ.

Непосредственная проблема, которую я вижу здесь, заключается в следующем:

  grafana:
    ports:
      - "3090:3090"

Grafana по умолчанию слушает порт 3000; при отсутствии явной конфигурации наоборот, если вы хотите выставить Grafana на хост-порт 3090, вы должны написать:

  grafana:
    ports:
      - "3090:3000"

Точно так же pgadmin прослушивает порт 80, поэтому, если вы явно не устанавливаете PGADMIN_LISTEN_PORT, вы должны написать:

  pgadmin:
      ports:
        - "5050:80"

Собрав все это вместе, вы увидите следующее docker-compose.yaml:

  • Прометей на порту 9090
  • Графана на порту 3090
  • Pgadmin на порту 5050

Postgres не отображается на хосте (но будет доступен для использования другими службами в вашем наборе).

volumes:
  prometheus_data: {}
  grafana_data: {}
  postgres_data: {}

services:
  prometheus:
    image: docker.io/prom/prometheus:latest
    restart: unless-stopped
    volumes:
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--web.enable-lifecycle'
    ports:
      - 9090:9090

  grafana:
    image: docker.io/grafana/grafana:latest
    restart: unless-stopped
    volumes:
      - grafana_data:/var/lib/grafana
    ports:
      - 3090:3000

  postgres:
    image: docker.io/postgres:15
    environment:
      POSTGRES_PASSWORD: "secret"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  pgadmin:
    image: docker.io/dpage/pgadmin4:latest
    environment:
      PGADMIN_DISABLE_POSTFIX: "1"
      PGADMIN_DEFAULT_EMAIL: [email protected]
      PGADMIN_DEFAULT_PASSWORD: secret
    ports:
      - 5050:80

Это работающий пример — вы можете скопировать и вставить его локально и запустить docker compose up; он не зависит от локальных файлов.


Обратите внимание, что вы можете удалить публикацию портов из всех вышеперечисленных служб и вместо этого добавить прокси-сервер nginx, который будет публиковать один порт, а затем получать доступ к службам по определенным путям (например, http://localhost:8090/prometheus/, http://localhost:8090/grafana/, http://localhost:8090/pgadmin/ и т. д.).

Эта конфигурация может выглядеть так:

volumes:
  prometheus_data: {}
  grafana_data: {}
  postgres_data: {}

services:
  prometheus:
    image: docker.io/prom/prometheus:latest
    restart: unless-stopped
    volumes:
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--web.enable-lifecycle'
      - '--web.external-url=/prometheus/'

  grafana:
    image: docker.io/grafana/grafana:latest
    restart: unless-stopped
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
        GF_SERVER_ROOT_URL: "%(protocol)s://%(domain)s:%(http_port)s/grafana/"
        GF_SERVER_SERVE_FROM_SUB_PATH: "true"

  postgres:
    image: docker.io/postgres:15
    environment:
      POSTGRES_PASSWORD: "secret"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  pgadmin:
    image: docker.io/dpage/pgadmin4:latest
    environment:
      PGADMIN_DISABLE_POSTFIX: "1"
      PGADMIN_DEFAULT_EMAIL: [email protected]
      PGADMIN_DEFAULT_PASSWORD: secret

  nginx:
    image: docker.io/nginx:mainline
    volumes:
      - ./nginx:/etc/nginx/conf.d
    ports:
      - 8090:80

Где nginx/default.conf выглядит так:

server {
  listen 80;
  server_name     localhost;

  location /grafana/ {
    proxy_pass http://grafana:3000/;
  }

  location /prometheus/ {
    proxy_pass http://prometheus:9090/prometheus/;
  }

  location /pgadmin/ {
    proxy_pass http://pgadmin:80/;
    proxy_set_header X-Script-Name /pgadmin/;
  }
}

Большое спасибо! Я действительно ошибся в переадресации портов. Публикация, как вы предложили, решила проблему. Однако второй вариант с отображением местоположения меня все равно не устраивает. Нужно ли мне также изменить конфигурацию HOST nginx? Я изменил ВНУТРЕННЮЮ конфигурацию nginx в контейнере, как вы предложили, но я не могу получить доступ к этим службам извне.

s0mbre 02.05.2023 02:49

В показанной здесь конфигурации мы предоставляем контейнерный nginx на порту хоста 8090. Любой, у кого есть доступ к порту 8090 на хосте, может получить доступ к сервисам. То же самое относится и к опубликованным портам в предыдущем примере. Обратите внимание, что я не запускаю дополнительный nginx на хосте, поэтому, возможно, удалите его, чтобы упростить ситуацию и посмотреть, какое поведение вы получите.

larsks 02.05.2023 04:45

Дополнительный (хост) nginx не снимается, так как он встроен в VPS, который я использую (выполняет другие функции переадресации портов). Я пытался добавить предложенные вами конфигурации в этот внешний nginx (/etc/nginx/conf.d/default.conf), но это не сработало. Также я пробовал оставлять эти конфиги серверов в контейнере nginx и добавлять простые обратные прокси во внешний (типа proxy_pass 127.0.0.1/prometheus), но безрезультатно.

s0mbre 02.05.2023 06:31

Конфигурация, показанная здесь, кажется, работает нормально, если я запускаю дополнительный прокси-сервер nginx на хосте, используя точную конфигурацию, которую вы указали в своем вопросе. Запрос на http://localhost/prometheus сначала поступает на хост nginx, который из-за proxy_pass http://127.0.0.1:8090/ for location / передает его на http://127.0.0.1:8090/prometheus, который обрабатывается контейнерным прокси, который передает его контейнеру prometheus.

larsks 02.05.2023 16:14

Ну может я что-то перепутал. Большое спасибо за помощь!

s0mbre 04.05.2023 04:17

Другие вопросы по теме