docker swarm 使用 prometheus 监控集群状态
背景
想要使用 prometheus 监控 docker swarm 的集群以及集群中的容器,按照 prometheus 官方的文档实现的话,需要将所有容器的端口都暴露出来,出于安全和维护得考虑我并不想把所有的容器端口都暴露到容器集群之外,而是只使用一个代理服务暴露出来。通过服务名称在集群内通信。关于这部分网络通信可以查看 docker swarm 网络相关文档。这里引用一段关于 overlay 网络的说明。
overlay: Overlay networks connect multiple Docker daemons together and enable Swarm services and containers to communicate across nodes. This strategy removes the need to do OS-level routing. See Overlay network driver.
overlay: 覆盖网络将多个 Docker 守护进程连接在一起,并使 Swarm 服务和容器能够跨节点通信。此策略消除了进行操作系统级路由的需要。
由于网络的限制,prometheus 不能从外部访问 docker swarm 的 overlay 网络,prometheus 无法在外部访问应用端口,所以需要将 prometheus 部署对应的 stack 环境并加入到 ingress 网络,这样就能在内部通过 vip 或者 service name 访问容器。
prometheus 官方并没有提供关于这个的最佳解决方案,所以才有了本篇文章。
打开 docker 采集端口
以下是我在官方关于 docker swarm 服务发现的配置基础上做了部分改进。建议先查看 prometheus 官方文档再看以下部分,可以帮助理解。
- 修改
/etc/docker/daemon.json添加配置:
{
"metrics-addr": "0.0.0.0:9323",
"experimental": true
}也可以配置 ip 地址而不是 0.0.0.0
- 重启 docker 守护进程
$ systemctl restart docker- 需要集群中所有
docker节点打开9323端口 - 需要打开服务器防火墙
在 docker swarm 创建 configs
我们需要将 prometheus 的配置挂载到容器外的宿主机上,这里有两种方式可以使用:
- 只读方式挂载到宿主机本地磁盘
- 使用
docker config方式配置到容器的配置列表。
这里采用里的 2 的方式,这样便于从容器相关可视化页面查看,例如: portainer
在 docker swarm manager节点 创建 prometheus.yml 文件:
# my global config
global:
scrape_interval: 1m # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 1m # Evaluate rules every 15 seconds. The default is every 1 minute.
scrape_timeout: 10s # scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
scrape_configs:
1 - job_name: "dockerswarm"
2 dockerswarm_sd_configs:
- host: unix:///var/run/docker.sock
role: nodes
relabel_configs:
3 - source_labels: [__meta_dockerswarm_node_address]
target_label: __address__
replacement: $1:9323
4 - source_labels: [__meta_dockerswarm_node_hostname]
target_label: instance
5 - job_name: 'dockertasks'
metrics_path: /actuator/prometheus
dockerswarm_sd_configs:
- host: unix:///var/run/docker.sock
role: tasks
relabel_configs:
# Only keep containers that should be running.
6 - source_labels: [__meta_dockerswarm_task_desired_state]
regex: running
action: keep
7 - source_labels: [__meta_dockerswarm_container_label_com_docker_stack_namespace]
regex: dev
action: keep
8 - source_labels: [__meta_dockerswarm_container_label_external_metrics_enable]
regex: true
action: keep
9 - source_labels: [__address__]
target_label: __address__
regex: '(.+):.*'
replacement: $1:8080
10 - source_labels: [__meta_dockerswarm_service_label_com_docker_stack_namespace]
target_label: namespace
11 - source_labels: [__meta_dockerswarm_service_name]
target_label: serviceName
12 - source_labels: [__meta_dockerswarm_service_name]
target_label: application
13 - source_labels: [__meta_dockerswarm_task_id]
target_label: instance- 1
-
job_name:"dockerswarm": docker swarm 节点监控 - 2
-
dockerswarm_sd_configs: 使用prometheus内置支持的dockerswarm服务发现配置 ;host: 配置unix:///var/run/docker.sock访问 docker 的守护进程 ;role: 配置为node用于访问表示监控docker swarm节点 - 3
-
__meta_dockerswarm_node_address: 使用 docker swarm 节点地址替换__addresslabel - 4
-
__meta_dockerswarm_node_hostname: 使用 docker swarm hostname 替换instancelabel - 5
-
job_name: 'dockertasks': docker task 监控, 监控容器 - 6
-
dockerswarm_sd_configs: 同样使用 docker swarm 服务发现配置 ;host: 配置unix:///var/run/docker.sock访问 docker 的守护进程 ;role: 配置为tasks用于访问表示监控docker swarm运行的容器 - 7
-
__meta_dockerswarm_task_desired_state: 过滤容器运行状态要保持容器状态微running - 8
-
__meta_dockerswarm_container_label_com_docker_stack_namespace: 容器运行的命名空间, 对应的是 docker swarm 中的stock,namespace是k8s中不同环境之间隔离的划分名称, 这里过滤掉stock非dev - 9
-
__meta_dockerswarm_container_label_external_metrics_enable: 过滤开启了监控的容器 - 10
-
__address__: 替换默认监控容器的端口, 我习惯上使用容器内的8080端口作为服务的默认访问端口, 可以根据跟人习惯修改 - 11
-
__meta_dockerswarm_service_label_com_docker_stack_namespace: 使用stack替换namespace - 12
-
__meta_dockerswarm_service_name: 使用docker swarm的服务名称替换掉application和serviceNamelabel - 13
-
__meta_dockerswarm_task_id: 使用task_id替换掉instance
docker_compose.yml 配置
创建 docker_compose.yml 文件:
$ vim docker_compose.yml写入以下配置:
version: "3.5"
services:
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
1 user: root
deploy:
mode: replicated
replicas: 1
placement:
constraints:
2 - node.role == manager
networks:
- overlay
configs:
3 - source: prometheus_config
target: /etc/prometheus/prometheus.yml
command:
4 - '--config.file=/etc/prometheus/prometheus.yml'
volumes:
5 - /var/run/docker.sock:/var/run/docker.sock:ro
configs:
prometheus_config:
6 file: ./prometheus.yml
networks:
overlay:- 1
-
user:root: 使用 root 用户创建容器,因为需要监听docker.sock - 2
-
node.role == manager: 设置角色为manager, 因为需要将prometheus容器运行在docker swarm的主节点上 - 3
-
prometheus_config: 是上一步设置的docker config名称 - 4
-
config.file=/etc/prometheus/prometheus.yml: 设置prometheus启动时使用的命令 - 5
-
/var/run/docker.sock:/var/run/docker.sock:ro: 挂载docker的守护进程 - 6
-
configs: 对应 <3> 的配置设置, 指定使用当前启动 docker_compose.yml 文件的相对路径下的prometheus.yml
在 docker swarm 集群部署
在目标 stack 环境部署 prometheus
$ docker stack deploy -c docker_compose.yml {stack}如果是多套 stock 环境则必须每个 stock 中都要部署 prometheus 用于监控, 这是因为 docker swarm 默认的 overlay 网络之间不能互相通信. 同时每个容器只能配置唯一的 overlay 网络