在Kubernetes多Worker的Flask+Gunicorn服务中通过独立端口暴露Prometheus指标
嘿,这个场景我太熟悉了——多Worker的Gunicorn部署下,直接用start_http_server会碰到端口冲突(每个Worker都想绑定同一个端口),还得满足指标只在集群内部访问的要求。给你几个经过实践验证的解决方案,按推荐程度排序:
方案1:用Prometheus Flask Exporter(最省心)
这个库专门为Flask应用做了Prometheus指标适配,还原生支持多Worker场景,不用自己处理端口冲突和指标汇总。
步骤1:安装依赖
pip install prometheus-flask-exporter
步骤2:修改Flask应用代码
from flask import Flask from prometheus_flask_exporter import PrometheusMetrics app = Flask(__name__) # 初始化指标采集器,指定单独的指标端口(比如9090),绑定到localhost确保只有Pod内部能直接访问 metrics = PrometheusMetrics( app, path='/metrics', port=9090, addr='localhost' ) # 自定义业务指标示例 requests_total = metrics.counter( 'flask_requests_total', 'Total number of Flask requests', labels={'endpoint': lambda: request.endpoint} ) @app.route('/') def hello(): return "Hello from Flask + Gunicorn!" if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
步骤3:配置Gunicorn与Kubernetes
首先,需要设置环境变量让库支持多Worker的指标汇总,在Dockerfile或者Deployment里添加:
# 提前创建多进程指标存储目录 RUN mkdir -p /tmp/prometheus-multiproc
Gunicorn启动命令:
PROMETHEUS_MULTIPROC_DIR=/tmp/prometheus-multiproc gunicorn --workers=4 --bind=0.0.0.0:5000 app:app
然后在Kubernetes Deployment里配置ClusterIP类型的Service,只在集群内部暴露指标端口:
apiVersion: apps/v1 kind: Deployment metadata: name: flask-gunicorn-app spec: replicas: 2 selector: matchLabels: app: flask-app template: metadata: labels: app: flask-app annotations: # 告诉Prometheus自动采集这个Pod的指标 prometheus.io/scrape: "true" prometheus.io/port: "9090" prometheus.io/path: "/metrics" spec: containers: - name: flask-app image: your-app-image:latest ports: - containerPort: 5000 name: app-port - containerPort: 9090 name: metrics-port env: - name: PROMETHEUS_MULTIPROC_DIR value: /tmp/prometheus-multiproc command: ["sh", "-c", "mkdir -p /tmp/prometheus-multiproc && gunicorn --workers=4 --bind=0.0.0.0:5000 app:app"] --- apiVersion: v1 kind: Service metadata: name: flask-app-metrics spec: # ClusterIP是默认类型,只在集群内部可访问 type: ClusterIP selector: app: flask-app ports: - port: 9090 targetPort: metrics-port name: metrics
这个方案的优点:几乎不用自己写额外的指标逻辑,库已经封装好了多Worker的指标聚合,而且通过ClusterIP Service确保指标只在集群内部可见。
方案2:Sidecar容器解耦指标采集
如果想完全把业务应用和指标采集分开,可以用Kubernetes的Sidecar模式——一个容器跑Flask+Gunicorn,另一个容器专门暴露Prometheus指标,两者通过共享卷传递指标数据。
步骤1:修改业务应用代码
让业务Worker把指标写到共享目录:
from flask import Flask from prometheus_client import Counter, multiprocess, CollectorRegistry app = Flask(__name__) # 初始化多进程兼容的注册表 registry = CollectorRegistry() multiprocess.MultiProcessCollector(registry) # 自定义指标 requests_total = Counter('flask_requests_total', 'Total requests', registry=registry) @app.route('/') def hello(): requests_total.inc() return "Hello from Sidecar setup!" if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
步骤2:编写Sidecar指标暴露代码
创建一个单独的metrics_exporter.py,负责读取共享目录的指标并暴露端口:
from prometheus_client import start_http_server, multiprocess, CollectorRegistry import time if __name__ == '__main__': registry = CollectorRegistry() multiprocess.MultiProcessCollector(registry) # 绑定到0.0.0.0:9090,让Pod内部的Sidecar能被Prometheus访问 start_http_server(9090, registry=registry) # 保持进程运行 while True: time.sleep(3600)
步骤3:Kubernetes配置
用emptyDir卷共享指标目录,部署两个容器:
apiVersion: apps/v1 kind: Deployment metadata: name: flask-sidecar-app spec: replicas: 2 selector: matchLabels: app: flask-sidecar-app template: metadata: labels: app: flask-sidecar-app annotations: prometheus.io/scrape: "true" prometheus.io/port: "9090" prometheus.io/path: "/metrics" spec: volumes: - name: metrics-shared-dir emptyDir: {} containers: - name: flask-app image: your-app-image:latest ports: - containerPort: 5000 name: app-port env: - name: PROMETHEUS_MULTIPROC_DIR value: /tmp/metrics volumeMounts: - name: metrics-shared-dir mountPath: /tmp/metrics command: ["gunicorn", "--workers=4", "--bind=0.0.0.0:5000", "app:app"] - name: metrics-exporter image: your-exporter-image:latest ports: - containerPort: 9090 name: metrics-port env: - name: PROMETHEUS_MULTIPROC_DIR value: /tmp/metrics volumeMounts: - name: metrics-shared-dir mountPath: /tmp/metrics command: ["python", "metrics_exporter.py"] --- apiVersion: v1 kind: Service metadata: name: flask-sidecar-metrics spec: type: ClusterIP selector: app: flask-sidecar-app ports: - port: 9090 targetPort: metrics-port name: metrics
这个方案的优点:业务代码和指标采集完全解耦,各自可以独立更新和维护,适合复杂的微服务场景。
注意事项
- 无论用哪个方案,都要确保指标端口的Service是
ClusterIP类型(默认就是),这样外部无法访问,满足集群内部访问的要求。 - 多Worker场景下,必须启用Prometheus的多进程模式(通过
PROMETHEUS_MULTIPROC_DIR环境变量),否则指标会被多个Worker覆盖,数据不准确。
内容的提问来源于stack exchange,提问作者Peanut
相关产品推荐
相关产品推荐

