使用 Docker 部署副本进行指标收集
我是一名开发人员,但在我的新工作中,公司没有DevOps团队。因此,我们没有任何类型的指标收集或适当的 CI/CD 流程。因此,我正在尝试在这里实施一些事情,但我不是专家。
我想做的第一件事是使用 Prometheus 和 Grafana 实现指标收集和可视化,以监控一些 Python 和 Node.js 本地应用程序。我使用 Flask 应用程序进行测试,并使用 Docker 在本地安装 Prometheus 和 Grafana,然后再将它们设置在适当的服务器上。我使用
prometheus-flask-exporter
让它轻松工作,但我开始注意到一些问题,并对什么最适合我的应用程序堆栈有一些疑问。
应用程序堆栈:
Python
烧瓶
Gunicorn 有 2 个工人和 2 个线程
带有副本的 Docker
Nginx
问题与疑问:
Docker 部署副本:我立即意识到我的应用程序有一个用于负载平衡的 Docker 副本。因此,当 Prometheus 抓取 /metrics 路径时,Docker 会将请求发送到其中一个副本。我相信两者都应该在 Grafana 上有单独的指标,以查看负载平衡是否正常工作。我所做的是为每个副本创建不同的路径,例如 Nginx 上的 /metrics_1 和 /metrics_2 以及 Prometheus 上的两个不同作业,并且它有效,但我认为这不是正确的方法。
指标准确性:我想要基本指标,例如百分比延迟、每条路径上每秒的请求数、2xx 请求、3xx 请求、4xx 请求和 5xx 请求。然而,就我实现它的方式而言,我无法信任这些指标,因为当我将它们与 K6 负载测试进行比较时,我得到了完全不同的指标,尤其是百分位延迟和每秒请求数。
发生这些问题后,我很生气,并回滚了我所做的一切。现在,我想从头开始。我的问题主要是关于良好的监控实践。考虑到我的堆栈,我应该重点监控什么?我还需要从 Nginx 收集指标吗?如何处理 Docker 副本?使用
statsd-exporter
之类的东西来监控 Gunicorn 是否比使用 prometheus-flask-exporter
的 Flask 更好?我需要多进程模式吗?
我的配置文件:
compose.yml:
services:
api:
image: api-auth-ad
build: .
expose:
\- "8000"
environment:
\- SECRET_KEY=${SECRET_KEY}
\- LDAP_DOMAIN=${LDAP_DOMAIN}
deploy:
replicas: 2
resources:
limits:
cpus: "0.75"
memory: "1gb"
restart: always
nginx:
container_name: api-auth-ad-nginx
image: nginx:1.27.0
ports:
\- "80:80"
\- "443:443"
volumes:
\- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
\- api
restart: always
Dockerfile:
FROM python:3.11
WORKDIR /app
COPY pyproject.toml ./
RUN pip install poetry
RUN poetry lock
RUN poetry install --only main
COPY . .
CMD \["poetry", "run", "gunicorn", "--config", "gunicorn_config.py", "src.app:create_app()"\]
gunicorn_config.py:
workers = 2
threads = 2
bind = "0.0.0.0:8000"
loglevel = "info"
accesslog = "-"
errorlog = "-"
worker_class = "gthread"
nginx.conf:
worker_processes auto;
worker_rlimit_nofile 500000;
events {
use epoll;
worker_connections 512;
}
http {
access_log off;
error_log /dev/null emerg;
upstream api_auth {
server api:8000;
keepalive 400;
}
server {
listen 80;
location / {
proxy_pass http://api_auth;
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;
proxy_intercept_errors off;
}
}
}
这里发生了很多事情,所以我将处理副本:
处理副本的一种方法是将“实例”重写为任务级别指标中的副本名称。
您可以使用“dns_sd_configs”并设置 A 记录抓取器并使用“tasks.{service_name}”。这会在用于抓取指标的 ADDR 变量中返回服务的每个单独的 IP - 将实例重写为有趣的方式会更困难。
有一个更好的方法,通过将 Prometheus 实例固定到管理节点,您可以使用 dockerswarm_sd_configs 来提取指标:
- job_name: 'dockerswarm'
dockerswarm_sd_configs:
- host: unix:///var/run/docker.sock
role: tasks
您可以添加重新标签配置。我将实例重写为服务正在运行的节点:
relabel_configs:
- source_labels: [__meta_dockerswarm_node_hostname]
target_label: instance
dockerswarm_sd_config 不知道您的服务正在监听哪个端口的指标。我定义了一个部署标签“prometheus.metrics.port”来承载它并分配它:
relable_configs:
- source_labels:
- __address__
- __meta_dockerswarm_service_label_prometheus_metrics_port
regex: '(.*):(\d+);(\d+)'
target_label: __address__
replacement: '$1:$3'
要抓取服务,还需要将其附加到监控网络。 dockerswarm_sd_configs 将为每个连接的网络和发布的端口生成一个服务发现条目,因此我们可以过滤到全局 docker 网络。这里我假设“指标”存在:
relabel_configs:
- source_labels: [__meta_dockerswarm_network_name]
regex: monitoring
action: keep