В моем стеке приложений используется несколько контейнеров Docker, управляемых docker compose:
См. информацию о контейнере, возвращенную docker-compose ps:
Контейнеры отображаются в конфигурации 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 влекут за собой множество зависимостей, таких как python venv с пакетами, установка NodeJS и т. д. и т. д. Проблема явно где-то в конфигах Nginx.
Я думаю, вы неправильно поняли, что означает «минимальная» часть в минимальном воспроизводимом примере; исполняемый пример абсолютно возможен и должен содержать только те службы, о которых вы спрашиваете в этом вопросе. Если бы вы расширили существующий пример, все было бы готово.






Я немного смущен вашими целями; ваш заголовок «Разоблачение 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:
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 в контейнере, как вы предложили, но я не могу получить доступ к этим службам извне.
В показанной здесь конфигурации мы предоставляем контейнерный nginx на порту хоста 8090. Любой, у кого есть доступ к порту 8090 на хосте, может получить доступ к сервисам. То же самое относится и к опубликованным портам в предыдущем примере. Обратите внимание, что я не запускаю дополнительный nginx на хосте, поэтому, возможно, удалите его, чтобы упростить ситуацию и посмотреть, какое поведение вы получите.
Дополнительный (хост) nginx не снимается, так как он встроен в VPS, который я использую (выполняет другие функции переадресации портов). Я пытался добавить предложенные вами конфигурации в этот внешний nginx (/etc/nginx/conf.d/default.conf), но это не сработало. Также я пробовал оставлять эти конфиги серверов в контейнере nginx и добавлять простые обратные прокси во внешний (типа proxy_pass 127.0.0.1/prometheus), но безрезультатно.
Конфигурация, показанная здесь, кажется, работает нормально, если я запускаю дополнительный прокси-сервер nginx на хосте, используя точную конфигурацию, которую вы указали в своем вопросе. Запрос на http://localhost/prometheus сначала поступает на хост nginx, который из-за proxy_pass http://127.0.0.1:8090/ for location / передает его на http://127.0.0.1:8090/prometheus, который обрабатывается контейнерным прокси, который передает его контейнеру prometheus.
Ну может я что-то перепутал. Большое спасибо за помощь!
Этот вопрос выиграет от минимального воспроизводимого примера - в идеале, полного
docker-compose.yaml, который мы можем скопировать и запустить локально, чтобы воспроизвести поведение, о котором вы спрашиваете.