From 350964746203f9ad99e46ab3b925234d56dd356a Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Mon, 9 Nov 2020 12:41:02 +0100 Subject: [PATCH] Docker swarm: add filtering of services (#8074) * Docker swarm: add filtering of services Add filters on all docker swarm roles (nodes, tasks and services). Signed-off-by: Julien Pivotto --- config/config_test.go | 1 + discovery/dockerswarm/dockerswarm.go | 30 +- discovery/dockerswarm/mock_test.go | 2 +- discovery/dockerswarm/nodes.go | 2 +- discovery/dockerswarm/services.go | 2 +- discovery/dockerswarm/services_test.go | 109 +++ discovery/dockerswarm/tasks.go | 2 +- .../testdata/swarmprom/{_ping => _ping.json} | 0 .../swarmprom/services.json__wvKVCQ4HhD | 257 +++++++ .../testdata/swarmprom/services__wvKVCQ4HhD | 724 ------------------ docs/configuration/configuration.md | 15 + 11 files changed, 410 insertions(+), 734 deletions(-) rename discovery/dockerswarm/testdata/swarmprom/{_ping => _ping.json} (100%) create mode 100644 discovery/dockerswarm/testdata/swarmprom/services.json__wvKVCQ4HhD delete mode 100644 discovery/dockerswarm/testdata/swarmprom/services__wvKVCQ4HhD diff --git a/config/config_test.go b/config/config_test.go index c371c58cd..04980239a 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -619,6 +619,7 @@ var expectedConf = &Config{ ServiceDiscoveryConfigs: discovery.Configs{ &dockerswarm.SDConfig{ + Filters: []dockerswarm.Filter{}, Host: "http://127.0.0.1:2375", Role: "nodes", Port: 80, diff --git a/discovery/dockerswarm/dockerswarm.go b/discovery/dockerswarm/dockerswarm.go index 9e1544548..2e0b477cd 100644 --- a/discovery/dockerswarm/dockerswarm.go +++ b/discovery/dockerswarm/dockerswarm.go @@ -20,6 +20,7 @@ import ( "net/url" "time" + "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" "github.com/go-kit/kit/log" "github.com/prometheus/common/config" @@ -41,6 +42,7 @@ var userAgent = fmt.Sprintf("Prometheus/%s", version.Version) var DefaultSDConfig = SDConfig{ RefreshInterval: model.Duration(60 * time.Second), Port: 80, + Filters: []Filter{}, } func init() { @@ -51,13 +53,21 @@ func init() { type SDConfig struct { HTTPClientConfig config.HTTPClientConfig `yaml:",inline"` - Host string `yaml:"host"` - Role string `yaml:"role"` - Port int `yaml:"port"` + Host string `yaml:"host"` + Role string `yaml:"role"` + Port int `yaml:"port"` + Filters []Filter `yaml:"filters"` RefreshInterval model.Duration `yaml:"refresh_interval"` } +// Filter represent a filter that can be passed to Docker Swarm to reduce the +// amount of data received. +type Filter struct { + Name string `yaml:"name"` + Values []string `yaml:"values"` +} + // Name returns the name of the Config. func (*SDConfig) Name() string { return "dockerswarm" } @@ -99,9 +109,10 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { // the Discoverer interface. type Discovery struct { *refresh.Discovery - client *client.Client - role string - port int + client *client.Client + role string + port int + filters filters.Args } // NewDiscovery returns a new Discovery which periodically refreshes its targets. @@ -123,6 +134,13 @@ func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) { client.WithAPIVersionNegotiation(), } + d.filters = filters.NewArgs() + for _, f := range conf.Filters { + for _, v := range f.Values { + d.filters.Add(f.Name, v) + } + } + // There are other protocols than HTTP supported by the Docker daemon, like // unix, which are not supported by the HTTP client. Passing HTTP client // options to the Docker client makes those non-HTTP requests fail. diff --git a/discovery/dockerswarm/mock_test.go b/discovery/dockerswarm/mock_test.go index 24a992863..a55e26244 100644 --- a/discovery/dockerswarm/mock_test.go +++ b/discovery/dockerswarm/mock_test.go @@ -94,7 +94,7 @@ func (m *SDMock) SetupHandlers() { f = filepath.Join(p[:len(p)-1], strutil.SanitizeLabelName(parts[len(parts)-1])) } else { query := strings.Split(parts[len(parts)-1], "?") - f = query[0] + f = query[0] + ".json" if len(query) == 2 { h := sha1.New() h.Write([]byte(query[1])) diff --git a/discovery/dockerswarm/nodes.go b/discovery/dockerswarm/nodes.go index 68d89a8fa..79727a949 100644 --- a/discovery/dockerswarm/nodes.go +++ b/discovery/dockerswarm/nodes.go @@ -48,7 +48,7 @@ func (d *Discovery) refreshNodes(ctx context.Context) ([]*targetgroup.Group, err Source: "DockerSwarm", } - nodes, err := d.client.NodeList(ctx, types.NodeListOptions{}) + nodes, err := d.client.NodeList(ctx, types.NodeListOptions{Filters: d.filters}) if err != nil { return nil, fmt.Errorf("error while listing swarm nodes: %w", err) } diff --git a/discovery/dockerswarm/services.go b/discovery/dockerswarm/services.go index 2769bc59c..ae46bfd4d 100644 --- a/discovery/dockerswarm/services.go +++ b/discovery/dockerswarm/services.go @@ -46,7 +46,7 @@ func (d *Discovery) refreshServices(ctx context.Context) ([]*targetgroup.Group, Source: "DockerSwarm", } - services, err := d.client.ServiceList(ctx, types.ServiceListOptions{}) + services, err := d.client.ServiceList(ctx, types.ServiceListOptions{Filters: d.filters}) if err != nil { return nil, fmt.Errorf("error while listing swarm services: %w", err) } diff --git a/discovery/dockerswarm/services_test.go b/discovery/dockerswarm/services_test.go index 4c8803e42..f21caa175 100644 --- a/discovery/dockerswarm/services_test.go +++ b/discovery/dockerswarm/services_test.go @@ -314,3 +314,112 @@ host: %s }) } } + +func TestDockerSwarmSDServicesRefreshWithFilters(t *testing.T) { + sdmock := NewSDMock(t, "swarmprom") + sdmock.Setup() + + e := sdmock.Endpoint() + url := e[:len(e)-1] + cfgString := fmt.Sprintf(` +--- +role: services +host: %s +filters: +- name: name + values: ["mon_node-exporter", "mon_grafana"] +`, url) + var cfg SDConfig + testutil.Ok(t, yaml.Unmarshal([]byte(cfgString), &cfg)) + + d, err := NewDiscovery(&cfg, log.NewNopLogger()) + testutil.Ok(t, err) + + ctx := context.Background() + tgs, err := d.refresh(ctx) + testutil.Ok(t, err) + + testutil.Equals(t, 1, len(tgs)) + + tg := tgs[0] + testutil.Assert(t, tg != nil, "tg should not be nil") + testutil.Assert(t, tg.Targets != nil, "tg.targets should not be nil") + testutil.Equals(t, 4, len(tg.Targets)) + + for i, lbls := range []model.LabelSet{ + { + "__address__": model.LabelValue("10.0.0.7:9100"), + "__meta_dockerswarm_network_id": model.LabelValue("qvwhwd6p61k4o0ulsknqb066z"), + "__meta_dockerswarm_network_ingress": model.LabelValue("true"), + "__meta_dockerswarm_network_internal": model.LabelValue("false"), + "__meta_dockerswarm_network_name": model.LabelValue("ingress"), + "__meta_dockerswarm_network_scope": model.LabelValue("swarm"), + "__meta_dockerswarm_service_endpoint_port_name": model.LabelValue(""), + "__meta_dockerswarm_service_endpoint_port_publish_mode": model.LabelValue("ingress"), + "__meta_dockerswarm_service_id": model.LabelValue("3qvd7bwfptmoht16t1f7jllb6"), + "__meta_dockerswarm_service_label_com_docker_stack_image": model.LabelValue("stefanprodan/swarmprom-node-exporter:v0.16.0"), + "__meta_dockerswarm_service_label_com_docker_stack_namespace": model.LabelValue("mon"), + "__meta_dockerswarm_service_mode": model.LabelValue("global"), + "__meta_dockerswarm_service_name": model.LabelValue("mon_node-exporter"), + "__meta_dockerswarm_service_task_container_hostname": model.LabelValue(""), + "__meta_dockerswarm_service_task_container_image": model.LabelValue("stefanprodan/swarmprom-node-exporter:v0.16.0@sha256:1d2518ec0501dd848e718bf008df37852b1448c862d6f256f2d39244975758d6"), + }, + { + "__address__": model.LabelValue("10.0.1.2:9100"), + "__meta_dockerswarm_network_id": model.LabelValue("npq2closzy836m07eaq1425k3"), + "__meta_dockerswarm_network_ingress": model.LabelValue("false"), + "__meta_dockerswarm_network_internal": model.LabelValue("false"), + "__meta_dockerswarm_network_label_com_docker_stack_namespace": model.LabelValue("mon"), + "__meta_dockerswarm_network_name": model.LabelValue("mon_net"), + "__meta_dockerswarm_network_scope": model.LabelValue("swarm"), + "__meta_dockerswarm_service_endpoint_port_name": model.LabelValue(""), + "__meta_dockerswarm_service_endpoint_port_publish_mode": model.LabelValue("ingress"), + "__meta_dockerswarm_service_id": model.LabelValue("3qvd7bwfptmoht16t1f7jllb6"), + "__meta_dockerswarm_service_label_com_docker_stack_image": model.LabelValue("stefanprodan/swarmprom-node-exporter:v0.16.0"), + "__meta_dockerswarm_service_label_com_docker_stack_namespace": model.LabelValue("mon"), + "__meta_dockerswarm_service_mode": model.LabelValue("global"), + "__meta_dockerswarm_service_name": model.LabelValue("mon_node-exporter"), + "__meta_dockerswarm_service_task_container_hostname": model.LabelValue(""), + "__meta_dockerswarm_service_task_container_image": model.LabelValue("stefanprodan/swarmprom-node-exporter:v0.16.0@sha256:1d2518ec0501dd848e718bf008df37852b1448c862d6f256f2d39244975758d6"), + }, + { + "__address__": model.LabelValue("10.0.0.15:3000"), + "__meta_dockerswarm_network_id": model.LabelValue("qvwhwd6p61k4o0ulsknqb066z"), + "__meta_dockerswarm_network_ingress": model.LabelValue("true"), + "__meta_dockerswarm_network_internal": model.LabelValue("false"), + "__meta_dockerswarm_network_name": model.LabelValue("ingress"), + "__meta_dockerswarm_network_scope": model.LabelValue("swarm"), + "__meta_dockerswarm_service_endpoint_port_name": model.LabelValue(""), + "__meta_dockerswarm_service_endpoint_port_publish_mode": model.LabelValue("ingress"), + "__meta_dockerswarm_service_id": model.LabelValue("uk9su5tb9ykfzew3qtmp14uzh"), + "__meta_dockerswarm_service_label_com_docker_stack_image": model.LabelValue("stefanprodan/swarmprom-grafana:5.3.4"), + "__meta_dockerswarm_service_label_com_docker_stack_namespace": model.LabelValue("mon"), + "__meta_dockerswarm_service_mode": model.LabelValue("replicated"), + "__meta_dockerswarm_service_name": model.LabelValue("mon_grafana"), + "__meta_dockerswarm_service_task_container_hostname": model.LabelValue(""), + "__meta_dockerswarm_service_task_container_image": model.LabelValue("stefanprodan/swarmprom-grafana:5.3.4@sha256:2aca8aa5716e6e0eed3fcdc88fec256a0a1828c491a8cf240486ae7cc473092d"), + }, + { + "__address__": model.LabelValue("10.0.1.29:3000"), + "__meta_dockerswarm_network_id": model.LabelValue("npq2closzy836m07eaq1425k3"), + "__meta_dockerswarm_network_ingress": model.LabelValue("false"), + "__meta_dockerswarm_network_internal": model.LabelValue("false"), + "__meta_dockerswarm_network_label_com_docker_stack_namespace": model.LabelValue("mon"), + "__meta_dockerswarm_network_name": model.LabelValue("mon_net"), + "__meta_dockerswarm_network_scope": model.LabelValue("swarm"), + "__meta_dockerswarm_service_endpoint_port_name": model.LabelValue(""), + "__meta_dockerswarm_service_endpoint_port_publish_mode": model.LabelValue("ingress"), + "__meta_dockerswarm_service_id": model.LabelValue("uk9su5tb9ykfzew3qtmp14uzh"), + "__meta_dockerswarm_service_label_com_docker_stack_image": model.LabelValue("stefanprodan/swarmprom-grafana:5.3.4"), + "__meta_dockerswarm_service_label_com_docker_stack_namespace": model.LabelValue("mon"), + "__meta_dockerswarm_service_mode": model.LabelValue("replicated"), + "__meta_dockerswarm_service_name": model.LabelValue("mon_grafana"), + "__meta_dockerswarm_service_task_container_hostname": model.LabelValue(""), + "__meta_dockerswarm_service_task_container_image": model.LabelValue("stefanprodan/swarmprom-grafana:5.3.4@sha256:2aca8aa5716e6e0eed3fcdc88fec256a0a1828c491a8cf240486ae7cc473092d"), + }, + } { + t.Run(fmt.Sprintf("item %d", i), func(t *testing.T) { + testutil.Equals(t, lbls, tg.Targets[i]) + }) + } +} diff --git a/discovery/dockerswarm/tasks.go b/discovery/dockerswarm/tasks.go index d42682a35..04ced3d11 100644 --- a/discovery/dockerswarm/tasks.go +++ b/discovery/dockerswarm/tasks.go @@ -43,7 +43,7 @@ func (d *Discovery) refreshTasks(ctx context.Context) ([]*targetgroup.Group, err Source: "DockerSwarm", } - tasks, err := d.client.TaskList(ctx, types.TaskListOptions{}) + tasks, err := d.client.TaskList(ctx, types.TaskListOptions{Filters: d.filters}) if err != nil { return nil, fmt.Errorf("error while listing swarm services: %w", err) } diff --git a/discovery/dockerswarm/testdata/swarmprom/_ping b/discovery/dockerswarm/testdata/swarmprom/_ping.json similarity index 100% rename from discovery/dockerswarm/testdata/swarmprom/_ping rename to discovery/dockerswarm/testdata/swarmprom/_ping.json diff --git a/discovery/dockerswarm/testdata/swarmprom/services.json__wvKVCQ4HhD b/discovery/dockerswarm/testdata/swarmprom/services.json__wvKVCQ4HhD new file mode 100644 index 000000000..962697227 --- /dev/null +++ b/discovery/dockerswarm/testdata/swarmprom/services.json__wvKVCQ4HhD @@ -0,0 +1,257 @@ +[ + { + "ID": "3qvd7bwfptmoht16t1f7jllb6", + "Version": { + "Index": 41 + }, + "CreatedAt": "2020-06-19T19:14:29.269637662Z", + "UpdatedAt": "2020-06-19T19:14:29.288101671Z", + "Spec": { + "Name": "mon_node-exporter", + "Labels": { + "com.docker.stack.image": "stefanprodan/swarmprom-node-exporter:v0.16.0", + "com.docker.stack.namespace": "mon" + }, + "TaskTemplate": { + "ContainerSpec": { + "Image": "stefanprodan/swarmprom-node-exporter:v0.16.0@sha256:1d2518ec0501dd848e718bf008df37852b1448c862d6f256f2d39244975758d6", + "Labels": { + "com.docker.stack.namespace": "mon" + }, + "Args": [ + "--path.sysfs=/host/sys", + "--path.procfs=/host/proc", + "--collector.textfile.directory=/etc/node-exporter/", + "--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($|/)", + "--no-collector.ipvs" + ], + "Env": [ + "NODE_ID={{.Node.ID}}" + ], + "Privileges": { + "CredentialSpec": null, + "SELinuxContext": null + }, + "Mounts": [ + { + "Type": "bind", + "Source": "/proc", + "Target": "/host/proc", + "ReadOnly": true + }, + { + "Type": "bind", + "Source": "/sys", + "Target": "/host/sys", + "ReadOnly": true + }, + { + "Type": "bind", + "Source": "/", + "Target": "/rootfs", + "ReadOnly": true + }, + { + "Type": "bind", + "Source": "/etc/hostname", + "Target": "/etc/nodename" + } + ], + "Isolation": "default" + }, + "Resources": { + "Limits": { + "MemoryBytes": 134217728 + }, + "Reservations": { + "MemoryBytes": 67108864 + } + }, + "Placement": { + "Platforms": [ + { + "Architecture": "amd64", + "OS": "linux" + } + ] + }, + "Networks": [ + { + "Target": "npq2closzy836m07eaq1425k3", + "Aliases": [ + "node-exporter" + ] + } + ], + "ForceUpdate": 0, + "Runtime": "container" + }, + "Mode": { + "Global": {} + }, + "EndpointSpec": { + "Mode": "vip", + "Ports": [ + { + "Protocol": "tcp", + "TargetPort": 9100, + "PublishedPort": 9100, + "PublishMode": "ingress" + } + ] + } + }, + "Endpoint": { + "Spec": { + "Mode": "vip", + "Ports": [ + { + "Protocol": "tcp", + "TargetPort": 9100, + "PublishedPort": 9100, + "PublishMode": "ingress" + } + ] + }, + "Ports": [ + { + "Protocol": "tcp", + "TargetPort": 9100, + "PublishedPort": 9100, + "PublishMode": "ingress" + } + ], + "VirtualIPs": [ + { + "NetworkID": "qvwhwd6p61k4o0ulsknqb066z", + "Addr": "10.0.0.7/24" + }, + { + "NetworkID": "npq2closzy836m07eaq1425k3", + "Addr": "10.0.1.2/24" + } + ] + } + }, + { + "ID": "uk9su5tb9ykfzew3qtmp14uzh", + "Version": { + "Index": 92 + }, + "CreatedAt": "2020-06-19T19:14:54.28743674Z", + "UpdatedAt": "2020-06-19T19:14:54.301718496Z", + "Spec": { + "Name": "mon_grafana", + "Labels": { + "com.docker.stack.image": "stefanprodan/swarmprom-grafana:5.3.4", + "com.docker.stack.namespace": "mon" + }, + "TaskTemplate": { + "ContainerSpec": { + "Image": "stefanprodan/swarmprom-grafana:5.3.4@sha256:2aca8aa5716e6e0eed3fcdc88fec256a0a1828c491a8cf240486ae7cc473092d", + "Labels": { + "com.docker.stack.namespace": "mon" + }, + "Env": [ + "GF_SECURITY_ADMIN_PASSWORD=admin", + "GF_SECURITY_ADMIN_USER=admin", + "GF_USERS_ALLOW_SIGN_UP=false" + ], + "Privileges": { + "CredentialSpec": null, + "SELinuxContext": null + }, + "Mounts": [ + { + "Type": "volume", + "Source": "mon_grafana", + "Target": "/var/lib/grafana", + "VolumeOptions": { + "Labels": { + "com.docker.stack.namespace": "mon" + } + } + } + ], + "Isolation": "default" + }, + "Resources": { + "Limits": { + "MemoryBytes": 134217728 + }, + "Reservations": { + "MemoryBytes": 67108864 + } + }, + "Placement": { + "Constraints": [ + "node.role == manager" + ], + "Platforms": [ + { + "Architecture": "amd64", + "OS": "linux" + } + ] + }, + "Networks": [ + { + "Target": "npq2closzy836m07eaq1425k3", + "Aliases": [ + "grafana" + ] + } + ], + "ForceUpdate": 0, + "Runtime": "container" + }, + "Mode": { + "Replicated": { + "Replicas": 1 + } + }, + "EndpointSpec": { + "Mode": "vip", + "Ports": [ + { + "Protocol": "tcp", + "TargetPort": 3000, + "PublishedPort": 3000, + "PublishMode": "ingress" + } + ] + } + }, + "Endpoint": { + "Spec": { + "Mode": "vip", + "Ports": [ + { + "Protocol": "tcp", + "TargetPort": 3000, + "PublishedPort": 3000, + "PublishMode": "ingress" + } + ] + }, + "Ports": [ + { + "Protocol": "tcp", + "TargetPort": 3000, + "PublishedPort": 3000, + "PublishMode": "ingress" + } + ], + "VirtualIPs": [ + { + "NetworkID": "qvwhwd6p61k4o0ulsknqb066z", + "Addr": "10.0.0.15/24" + }, + { + "NetworkID": "npq2closzy836m07eaq1425k3", + "Addr": "10.0.1.29/24" + } + ] + } + } +] diff --git a/discovery/dockerswarm/testdata/swarmprom/services__wvKVCQ4HhD b/discovery/dockerswarm/testdata/swarmprom/services__wvKVCQ4HhD deleted file mode 100644 index 5dd065891..000000000 --- a/discovery/dockerswarm/testdata/swarmprom/services__wvKVCQ4HhD +++ /dev/null @@ -1,724 +0,0 @@ -[ - { - "ID": "3qvd7bwfptmoht16t1f7jllb6", - "Version": { - "Index": 41 - }, - "CreatedAt": "2020-06-19T19:14:29.269637662Z", - "UpdatedAt": "2020-06-19T19:14:29.288101671Z", - "Spec": { - "Name": "mon_node-exporter", - "Labels": { - "com.docker.stack.image": "stefanprodan/swarmprom-node-exporter:v0.16.0", - "com.docker.stack.namespace": "mon" - }, - "TaskTemplate": { - "ContainerSpec": { - "Image": "stefanprodan/swarmprom-node-exporter:v0.16.0@sha256:1d2518ec0501dd848e718bf008df37852b1448c862d6f256f2d39244975758d6", - "Labels": { - "com.docker.stack.namespace": "mon" - }, - "Args": [ - "--path.sysfs=/host/sys", - "--path.procfs=/host/proc", - "--collector.textfile.directory=/etc/node-exporter/", - "--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($|/)", - "--no-collector.ipvs" - ], - "Env": [ - "NODE_ID={{.Node.ID}}" - ], - "Privileges": { - "CredentialSpec": null, - "SELinuxContext": null - }, - "Mounts": [ - { - "Type": "bind", - "Source": "/proc", - "Target": "/host/proc", - "ReadOnly": true - }, - { - "Type": "bind", - "Source": "/sys", - "Target": "/host/sys", - "ReadOnly": true - }, - { - "Type": "bind", - "Source": "/", - "Target": "/rootfs", - "ReadOnly": true - }, - { - "Type": "bind", - "Source": "/etc/hostname", - "Target": "/etc/nodename" - } - ], - "Isolation": "default" - }, - "Resources": { - "Limits": { - "MemoryBytes": 134217728 - }, - "Reservations": { - "MemoryBytes": 67108864 - } - }, - "Placement": { - "Platforms": [ - { - "Architecture": "amd64", - "OS": "linux" - } - ] - }, - "Networks": [ - { - "Target": "npq2closzy836m07eaq1425k3", - "Aliases": [ - "node-exporter" - ] - } - ], - "ForceUpdate": 0, - "Runtime": "container" - }, - "Mode": { - "Global": {} - }, - "EndpointSpec": { - "Mode": "vip", - "Ports": [ - { - "Protocol": "tcp", - "TargetPort": 9100, - "PublishedPort": 9100, - "PublishMode": "ingress" - } - ] - } - }, - "Endpoint": { - "Spec": { - "Mode": "vip", - "Ports": [ - { - "Protocol": "tcp", - "TargetPort": 9100, - "PublishedPort": 9100, - "PublishMode": "ingress" - } - ] - }, - "Ports": [ - { - "Protocol": "tcp", - "TargetPort": 9100, - "PublishedPort": 9100, - "PublishMode": "ingress" - } - ], - "VirtualIPs": [ - { - "NetworkID": "qvwhwd6p61k4o0ulsknqb066z", - "Addr": "10.0.0.7/24" - }, - { - "NetworkID": "npq2closzy836m07eaq1425k3", - "Addr": "10.0.1.2/24" - } - ] - } - }, - { - "ID": "9bbq7j55tzzz85k2gg52x73rg", - "Version": { - "Index": 116 - }, - "CreatedAt": "2020-06-19T19:15:16.676178796Z", - "UpdatedAt": "2020-06-19T19:15:16.690701679Z", - "Spec": { - "Name": "mon_unsee", - "Labels": { - "com.docker.stack.image": "cloudflare/unsee:v0.8.0", - "com.docker.stack.namespace": "mon" - }, - "TaskTemplate": { - "ContainerSpec": { - "Image": "cloudflare/unsee:v0.8.0@sha256:28398f47f63feb1647887999701fa730da351fc6d3cc7228e5da44b40a663ada", - "Labels": { - "com.docker.stack.namespace": "mon" - }, - "Env": [ - "ALERTMANAGER_URIS=default:http://alertmanager:9093" - ], - "Privileges": { - "CredentialSpec": null, - "SELinuxContext": null - }, - "Isolation": "default" - }, - "Resources": {}, - "Placement": { - "Platforms": [ - { - "Architecture": "amd64", - "OS": "linux" - } - ] - }, - "Networks": [ - { - "Target": "npq2closzy836m07eaq1425k3", - "Aliases": [ - "unsee" - ] - } - ], - "ForceUpdate": 0, - "Runtime": "container" - }, - "Mode": { - "Replicated": { - "Replicas": 1 - } - }, - "EndpointSpec": { - "Mode": "vip" - } - }, - "Endpoint": { - "Spec": { - "Mode": "vip" - }, - "VirtualIPs": [ - { - "NetworkID": "npq2closzy836m07eaq1425k3", - "Addr": "10.0.1.34/24" - } - ] - } - }, - { - "ID": "hv645udwaaewyw7wuc6nspm68", - "Version": { - "Index": 54 - }, - "CreatedAt": "2020-06-19T19:14:31.707250955Z", - "UpdatedAt": "2020-06-19T19:14:31.713627185Z", - "Spec": { - "Name": "mon_prometheus", - "Labels": { - "com.docker.stack.image": "stefanprodan/swarmprom-prometheus:v2.5.0", - "com.docker.stack.namespace": "mon" - }, - "TaskTemplate": { - "ContainerSpec": { - "Image": "stefanprodan/swarmprom-prometheus:v2.5.0@sha256:f1a3781c4785637ba088dcf54889f77d9b6b69f21b2c0a167c1347473f4e2587", - "Labels": { - "com.docker.stack.namespace": "mon" - }, - "Args": [ - "--config.file=/etc/prometheus/prometheus.yml", - "--storage.tsdb.path=/prometheus", - "--storage.tsdb.retention=24h" - ], - "Privileges": { - "CredentialSpec": null, - "SELinuxContext": null - }, - "Mounts": [ - { - "Type": "volume", - "Source": "mon_prometheus", - "Target": "/prometheus", - "VolumeOptions": { - "Labels": { - "com.docker.stack.namespace": "mon" - } - } - } - ], - "Configs": [ - { - "File": { - "Name": "/etc/prometheus/swarm_node.rules.yml", - "UID": "0", - "GID": "0", - "Mode": 292 - }, - "ConfigID": "zffindunvquarrlgdrklzczbz", - "ConfigName": "mon_node_rules" - }, - { - "File": { - "Name": "/etc/prometheus/swarm_task.rules.yml", - "UID": "0", - "GID": "0", - "Mode": 292 - }, - "ConfigID": "fbhk5cmleeicn5fkzujm909k7", - "ConfigName": "mon_task_rules" - } - ], - "Isolation": "default" - }, - "Resources": { - "Limits": { - "MemoryBytes": 2147483648 - }, - "Reservations": { - "MemoryBytes": 134217728 - } - }, - "Placement": { - "Constraints": [ - "node.role == manager" - ], - "Platforms": [ - { - "Architecture": "amd64", - "OS": "linux" - } - ] - }, - "Networks": [ - { - "Target": "npq2closzy836m07eaq1425k3", - "Aliases": [ - "prometheus" - ] - } - ], - "ForceUpdate": 0, - "Runtime": "container" - }, - "Mode": { - "Replicated": { - "Replicas": 1 - } - }, - "EndpointSpec": { - "Mode": "vip" - } - }, - "Endpoint": { - "Spec": { - "Mode": "vip" - }, - "VirtualIPs": [ - { - "NetworkID": "npq2closzy836m07eaq1425k3", - "Addr": "10.0.1.13/24" - } - ] - } - }, - { - "ID": "iml8vdd2dudvq457sbirpf66z", - "Version": { - "Index": 83 - }, - "CreatedAt": "2020-06-19T19:14:49.165966453Z", - "UpdatedAt": "2020-06-19T19:14:49.1722461Z", - "Spec": { - "Name": "mon_cadvisor", - "Labels": { - "com.docker.stack.image": "google/cadvisor", - "com.docker.stack.namespace": "mon" - }, - "TaskTemplate": { - "ContainerSpec": { - "Image": "google/cadvisor:latest@sha256:815386ebbe9a3490f38785ab11bda34ec8dacf4634af77b8912832d4f85dca04", - "Labels": { - "com.docker.stack.namespace": "mon" - }, - "Args": [ - "-logtostderr", - "-docker_only" - ], - "Privileges": { - "CredentialSpec": null, - "SELinuxContext": null - }, - "Mounts": [ - { - "Type": "bind", - "Source": "/var/run/docker.sock", - "Target": "/var/run/docker.sock", - "ReadOnly": true - }, - { - "Type": "bind", - "Source": "/", - "Target": "/rootfs", - "ReadOnly": true - }, - { - "Type": "bind", - "Source": "/var/run", - "Target": "/var/run" - }, - { - "Type": "bind", - "Source": "/sys", - "Target": "/sys", - "ReadOnly": true - }, - { - "Type": "bind", - "Source": "/var/lib/docker/", - "Target": "/var/lib/docker", - "ReadOnly": true - } - ], - "Isolation": "default" - }, - "Resources": { - "Limits": { - "MemoryBytes": 134217728 - }, - "Reservations": { - "MemoryBytes": 67108864 - } - }, - "Placement": { - "Platforms": [ - { - "Architecture": "amd64", - "OS": "linux" - } - ] - }, - "Networks": [ - { - "Target": "npq2closzy836m07eaq1425k3", - "Aliases": [ - "cadvisor" - ] - } - ], - "ForceUpdate": 0, - "Runtime": "container" - }, - "Mode": { - "Global": {} - }, - "EndpointSpec": { - "Mode": "vip" - } - }, - "Endpoint": { - "Spec": { - "Mode": "vip" - }, - "VirtualIPs": [ - { - "NetworkID": "npq2closzy836m07eaq1425k3", - "Addr": "10.0.1.23/24" - } - ] - } - }, - { - "ID": "rl4jhdws3r4lkfvq8kx6c4xnr", - "Version": { - "Index": 104 - }, - "CreatedAt": "2020-06-19T19:15:09.840775581Z", - "UpdatedAt": "2020-06-19T19:15:09.854119631Z", - "Spec": { - "Name": "mon_alertmanager", - "Labels": { - "com.docker.stack.image": "stefanprodan/swarmprom-alertmanager:v0.14.0", - "com.docker.stack.namespace": "mon" - }, - "TaskTemplate": { - "ContainerSpec": { - "Image": "stefanprodan/swarmprom-alertmanager:v0.14.0@sha256:7069b656bd5df0606ff1db81a7553a25dc72be51d3aca6a7e08d776566cefbd8", - "Labels": { - "com.docker.stack.namespace": "mon" - }, - "Args": [ - "--config.file=/etc/alertmanager/alertmanager.yml", - "--storage.path=/alertmanager" - ], - "Env": [ - "SLACK_CHANNEL=devops-alerts", - "SLACK_URL=https://hooks.slack.com/services/TOKEN", - "SLACK_USER=alertmanager" - ], - "Privileges": { - "CredentialSpec": null, - "SELinuxContext": null - }, - "Mounts": [ - { - "Type": "volume", - "Source": "mon_alertmanager", - "Target": "/alertmanager", - "VolumeOptions": { - "Labels": { - "com.docker.stack.namespace": "mon" - } - } - } - ], - "Isolation": "default" - }, - "Resources": { - "Limits": { - "MemoryBytes": 134217728 - }, - "Reservations": { - "MemoryBytes": 67108864 - } - }, - "Placement": { - "Constraints": [ - "node.role == manager" - ] - }, - "Networks": [ - { - "Target": "npq2closzy836m07eaq1425k3", - "Aliases": [ - "alertmanager" - ] - } - ], - "ForceUpdate": 0, - "Runtime": "container" - }, - "Mode": { - "Replicated": { - "Replicas": 1 - } - }, - "EndpointSpec": { - "Mode": "vip" - } - }, - "Endpoint": { - "Spec": { - "Mode": "vip" - }, - "VirtualIPs": [ - { - "NetworkID": "npq2closzy836m07eaq1425k3", - "Addr": "10.0.1.31/24" - } - ] - } - }, - { - "ID": "uk9su5tb9ykfzew3qtmp14uzh", - "Version": { - "Index": 92 - }, - "CreatedAt": "2020-06-19T19:14:54.28743674Z", - "UpdatedAt": "2020-06-19T19:14:54.301718496Z", - "Spec": { - "Name": "mon_grafana", - "Labels": { - "com.docker.stack.image": "stefanprodan/swarmprom-grafana:5.3.4", - "com.docker.stack.namespace": "mon" - }, - "TaskTemplate": { - "ContainerSpec": { - "Image": "stefanprodan/swarmprom-grafana:5.3.4@sha256:2aca8aa5716e6e0eed3fcdc88fec256a0a1828c491a8cf240486ae7cc473092d", - "Labels": { - "com.docker.stack.namespace": "mon" - }, - "Env": [ - "GF_SECURITY_ADMIN_PASSWORD=admin", - "GF_SECURITY_ADMIN_USER=admin", - "GF_USERS_ALLOW_SIGN_UP=false" - ], - "Privileges": { - "CredentialSpec": null, - "SELinuxContext": null - }, - "Mounts": [ - { - "Type": "volume", - "Source": "mon_grafana", - "Target": "/var/lib/grafana", - "VolumeOptions": { - "Labels": { - "com.docker.stack.namespace": "mon" - } - } - } - ], - "Isolation": "default" - }, - "Resources": { - "Limits": { - "MemoryBytes": 134217728 - }, - "Reservations": { - "MemoryBytes": 67108864 - } - }, - "Placement": { - "Constraints": [ - "node.role == manager" - ], - "Platforms": [ - { - "Architecture": "amd64", - "OS": "linux" - } - ] - }, - "Networks": [ - { - "Target": "npq2closzy836m07eaq1425k3", - "Aliases": [ - "grafana" - ] - } - ], - "ForceUpdate": 0, - "Runtime": "container" - }, - "Mode": { - "Replicated": { - "Replicas": 1 - } - }, - "EndpointSpec": { - "Mode": "vip", - "Ports": [ - { - "Protocol": "tcp", - "TargetPort": 3000, - "PublishedPort": 3000, - "PublishMode": "ingress" - } - ] - } - }, - "Endpoint": { - "Spec": { - "Mode": "vip", - "Ports": [ - { - "Protocol": "tcp", - "TargetPort": 3000, - "PublishedPort": 3000, - "PublishMode": "ingress" - } - ] - }, - "Ports": [ - { - "Protocol": "tcp", - "TargetPort": 3000, - "PublishedPort": 3000, - "PublishMode": "ingress" - } - ], - "VirtualIPs": [ - { - "NetworkID": "qvwhwd6p61k4o0ulsknqb066z", - "Addr": "10.0.0.15/24" - }, - { - "NetworkID": "npq2closzy836m07eaq1425k3", - "Addr": "10.0.1.29/24" - } - ] - } - }, - { - "ID": "ul5qawv4s7f7msm7dtyfarw80", - "Version": { - "Index": 74 - }, - "CreatedAt": "2020-06-19T19:14:45.311963014Z", - "UpdatedAt": "2020-06-19T19:14:45.327315101Z", - "Spec": { - "Name": "mon_dockerd-exporter", - "Labels": { - "com.docker.stack.image": "stefanprodan/caddy", - "com.docker.stack.namespace": "mon" - }, - "TaskTemplate": { - "ContainerSpec": { - "Image": "stefanprodan/caddy:latest@sha256:44541cfacb66f4799f81f17fcfb3cb757ccc8f327592745549f5930c42d115c9", - "Labels": { - "com.docker.stack.namespace": "mon" - }, - "Env": [ - "DOCKER_GWBRIDGE_IP=172.18.0.1" - ], - "Privileges": { - "CredentialSpec": null, - "SELinuxContext": null - }, - "Configs": [ - { - "File": { - "Name": "/etc/caddy/Caddyfile", - "UID": "0", - "GID": "0", - "Mode": 292 - }, - "ConfigID": "4glhzmw6fndnkjn2cok90a9gu", - "ConfigName": "mon_dockerd_config" - } - ], - "Isolation": "default" - }, - "Resources": { - "Limits": { - "MemoryBytes": 134217728 - }, - "Reservations": { - "MemoryBytes": 67108864 - } - }, - "Placement": { - "Platforms": [ - { - "Architecture": "amd64", - "OS": "linux" - } - ] - }, - "Networks": [ - { - "Target": "npq2closzy836m07eaq1425k3", - "Aliases": [ - "dockerd-exporter" - ] - } - ], - "ForceUpdate": 0, - "Runtime": "container" - }, - "Mode": { - "Global": {} - }, - "EndpointSpec": { - "Mode": "vip" - } - }, - "Endpoint": { - "Spec": { - "Mode": "vip" - }, - "VirtualIPs": [ - { - "NetworkID": "npq2closzy836m07eaq1425k3", - "Addr": "10.0.1.17/24" - } - ] - } - } -] diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index 01860c071..ba356c09a 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -577,6 +577,16 @@ role: # tasks and services that don't have published ports. [ port: | default = 80 ] +# Optional filters to limit the discovery process to a subset of available +# resources. +# The available filters are listed in the upstream documentation: +# Services: https://docs.docker.com/engine/api/v1.40/#operation/ServiceList +# Tasks: https://docs.docker.com/engine/api/v1.40/#operation/TaskList +# Nodes: https://docs.docker.com/engine/api/v1.40/#operation/NodeList +[ filters: + [ - name: + values: , [...] ] + # The time after which the droplets are refreshed. [ refresh_interval: | default = 60s ] @@ -598,6 +608,11 @@ basic_auth: [ bearer_token_file: ] ``` +The [relabeling phase](#relabel_config) is the preferred and more powerful +way to filter tasks, services or nodes. For users with thousands of tasks it +can be more efficient to use the Swarm API directly which has basic support for +filtering nodes (using `filters`). + See [this example Prometheus configuration file](/documentation/examples/prometheus-dockerswarm.yml) for a detailed example of configuring Prometheus for Docker Swarm.