From 2eed6c393ffcca38c2898c8d71918588919b1f35 Mon Sep 17 00:00:00 2001 From: hagen1778 Date: Sun, 12 Apr 2020 12:47:26 +0100 Subject: [PATCH] vmalert: prepare package for external usage * update README according to changes * add Makefile with basic commands --- app/vmalert/Makefile | 78 ++++++++++++++++++ app/vmalert/README.md | 108 ++++++++++++++++++------- app/vmalert/main.go | 11 +-- app/vmalert/rule.go | 2 - app/vmalert/testdata/rules0-good.rules | 10 +++ app/vmalert/vmalert.png | Bin 25765 -> 0 bytes 6 files changed, 173 insertions(+), 36 deletions(-) create mode 100644 app/vmalert/Makefile delete mode 100644 app/vmalert/vmalert.png diff --git a/app/vmalert/Makefile b/app/vmalert/Makefile new file mode 100644 index 0000000000..64b9e27ad4 --- /dev/null +++ b/app/vmalert/Makefile @@ -0,0 +1,78 @@ +# All these commands must run from repository root. + +vmalert: + APP_NAME=vmalert $(MAKE) app-local + +vmalert-race: + APP_NAME=vmalert RACE=-race $(MAKE) app-local + +vmalert-prod: + APP_NAME=vmalert $(MAKE) app-via-docker + +vmalert-pure-prod: + APP_NAME=vmalert $(MAKE) app-via-docker-pure + +vmalert-amd64-prod: + APP_NAME=vmalert $(MAKE) app-via-docker-amd64 + +vmalert-arm-prod: + APP_NAME=vmalert $(MAKE) app-via-docker-arm + +vmalert-arm64-prod: + APP_NAME=vmalert $(MAKE) app-via-docker-arm64 + +vmalert-ppc64le-prod: + APP_NAME=vmalert $(MAKE) app-via-docker-ppc64le + +vmalert-386-prod: + APP_NAME=vmalert $(MAKE) app-via-docker-386 + +package-vmalert: + APP_NAME=vmalert $(MAKE) package-via-docker + +package-vmalert-pure: + APP_NAME=vmalert $(MAKE) package-via-docker-pure + +package-vmalert-amd64: + APP_NAME=vmalert $(MAKE) package-via-docker-amd64 + +package-vmalert-arm: + APP_NAME=vmalert $(MAKE) package-via-docker-arm + +package-vmalert-arm64: + APP_NAME=vmalert $(MAKE) package-via-docker-arm64 + +package-vmalert-ppc64le: + APP_NAME=vmalert $(MAKE) package-via-docker-ppc64le + +package-vmalert-386: + APP_NAME=vmalert $(MAKE) package-via-docker-386 + +publish-vmalert: + APP_NAME=vmalert $(MAKE) publish-via-docker + +test-vmalert: + go test -race -cover ./app/vmalert + +run-vmalert: vmalert + ./bin/vmalert -rule=app/vmalert/testdata/rules0-good.rules \ + -datasource.url=http://localhost:8428 -notifier.url=http://localhost:9093 \ + -evaluationInterval=3s + +vmalert-amd64: + CGO_ENABLED=1 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -mod=vendor -ldflags "$(GO_BUILDINFO)" -o bin/vmalert-amd64 ./app/vmalert + +vmalert-arm: + CGO_ENABLED=0 GOOS=linux GOARCH=arm GO111MODULE=on go build -mod=vendor -ldflags "$(GO_BUILDINFO)" -o bin/vmalert-arm ./app/vmalert + +vmalert-arm64: + CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GO111MODULE=on go build -mod=vendor -ldflags "$(GO_BUILDINFO)" -o bin/vmalert-arm64 ./app/vmalert + +vmalert-ppc64le: + CGO_ENABLED=0 GOOS=linux GOARCH=ppc64le GO111MODULE=on go build -mod=vendor -ldflags "$(GO_BUILDINFO)" -o bin/vmalert-ppc64le ./app/vmalert + +vmalert-386: + CGO_ENABLED=0 GOOS=linux GOARCH=386 GO111MODULE=on go build -mod=vendor -ldflags "$(GO_BUILDINFO)" -o bin/vmalert-386 ./app/vmalert + +vmalert-pure: + APP_NAME=vmalert $(MAKE) app-local-pure diff --git a/app/vmalert/README.md b/app/vmalert/README.md index 833d401070..96012529b9 100644 --- a/app/vmalert/README.md +++ b/app/vmalert/README.md @@ -1,41 +1,91 @@ ## VM Alert -#### Abstract -The application which accepts the alert rules, executes them on given source, sends(fires) an alert to(in) alert management system +`vmalert` executes a list of given MetricsQL expressions (rules) and +sends alerts to [Alert Manager](https://github.com/prometheus/alertmanager). -### Components +NOTE: `vmalert` is in early alpha and wasn't tested in production systems yet. -#### Alert Config Reader -It accepts yaml config as input parameter in Prometheus format, parses it into Go struct. +### Features: +* Integration with [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) TSDB; +* VictoriaMetrics [MetricsQL](https://github.com/VictoriaMetrics/VictoriaMetrics/wiki/MetricsQL) + expressions validation; +* Prometheus [alerting rules definition format](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/#defining-alerting-rules) + support; +* Integration with [Alertmanager](https://github.com/prometheus/alertmanager); +* Lightweight without extra dependencies. -#### Source Caller -Create own watchdog for every alert group (goroutines), which executes alert query on given source and issues an alert if source returns non-empty result. -Source can be any service which supports PromQL (MetricsQL). +### TODO: +* Persist alerts state as timeseries in TSDB. Currently, alerts state is stored +in process memory only and will be lost on restart; +* Configuration hot reload. -#### Alert Management System Provider -Send positive alert to alert management system, provides interface for every concrete implementation. -Should be ingratiated with Prometheus alertmanager. +### QuickStart -open questions: -- do we really need alert group or can just run every alert in own goroutine? +To build `vmalert` from sources: +``` +git clone https://github.com/VictoriaMetrics/VictoriaMetrics +cd VictoriaMetrics +make vmalert +``` +The build binary will be placed to `VictoriaMetrics/bin` folder. -#### Web Server -Expose metrics +To start using `vmalert` you will need the following things: +* list of alert rules - PromQL/MetricsQL expressions to execute; +* datasource address - reachable VictoriaMetrics instance for rules execution; +* notifier address - reachable Alertmanager instance for processing, +aggregating alerts and sending notifications. -open questions: -- should the tool provide API or UI for managing alerting rules? Where to store config updated via the API or UI? -- should the tool provide “alerting rules validation mode” for validating and debugging alerting rules? This mode is useful when creating and debugging alerting rules. +Then configure `vmalert` accordingly: +``` +./bin/vmalert -rule=alert.rules \ + -datasource.url=http://localhost:8428 \ + -notifier.url=http://localhost:9093 +``` -#### Requirements: -- Stateless -- Avoid external dependencies if possible -- Reuse existing code from VictoriaMetrics repo -- Makefile rules for common tasks – see Makefiles for other apps in the app/ dir -- Every package should be covered by tests -- Dockerfile -- Graceful shutdown -- Helm template -- Application uses command line flags for configuration +Example for `.rules` file bay be found [here](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/app/vmalert/testdata/rules0-good.rules) +`vmalert` runs evaluation for every group in a separate goroutine. +Rules in group evaluated one-by-one sequentially. -VM Alert +`vmalert` also runs a web-server (`-httpListenAddr`) for serving metrics and alerts endpoints: +* `http:///api/v1/alerts` - list of all active alerts; +* `http:///api/v1///status" ` - get alert status by ID. +Used as alert source in AlertManager. +* `http:///metrics` - application metrics. + +### Configuration + +The shortlist of configuration flags is the following: +``` +Usage of vmalert: + -datasource.url string + Victoria Metrics or VMSelect url. Required parameter. e.g. http://127.0.0.1:8428 + -datasource.basicAuth.password string + Optional basic auth password to use for -datasource.url + -datasource.basicAuth.username string + Optional basic auth username to use for -datasource.url + -evaluationInterval duration + How often to evaluate the rules. Default 1m (default 1m0s) + -external.url string + External URL is used as alert's source for sent alerts to the notifier + -notifier.url string + Prometheus alertmanager URL. Required parameter. e.g. http://127.0.0.1:9093 + -rule value + Path to the file with alert rules. + Supports patterns. Flag can be specified multiple times. + Examples: + -rule /path/to/file. Path to a single file with alerting rules + -rule dir/*.yaml -rule /*.yaml. Relative path to all .yaml files in "dir" folder, + absolute path to all .yaml files in root. + -rule.validateAnnotations + Indicates to validate annotation templates (default true) +``` + +Pass `-help` to `vmalert` in order to see the full list of supported +command-line flags with their descriptions. + +### Contributing + +`vmalert` is mostly designed and built by VictoriaMetrics community. +Feel free to share your experience and ideas for improving this +software. Please keep simplicity as the main priority. \ No newline at end of file diff --git a/app/vmalert/main.go b/app/vmalert/main.go index ebef0ed5f5..b7371623e0 100644 --- a/app/vmalert/main.go +++ b/app/vmalert/main.go @@ -23,11 +23,12 @@ import ( ) var ( - rulePath = flagutil.NewArray("rule", `Path to file with alert rules, accepts patterns. -Flag can be specified multiple time. + rulePath = flagutil.NewArray("rule", `Path to the file with alert rules. +Supports patterns. Flag can be specified multiple times. Examples: - -rule /path/to/file. Path to single file with alerting rules - -rule dir/*.yaml -rule /*.yaml. Paths to all yaml files in relative dir folder and absolute yaml file in a root.`) + -rule /path/to/file. Path to a single file with alerting rules + -rule dir/*.yaml -rule /*.yaml. Relative path to all .yaml files in "dir" folder, +absolute path to all .yaml files in root.`) validateAlertAnnotations = flag.Bool("rule.validateAnnotations", true, "Indicates to validate annotation templates") httpListenAddr = flag.String("httpListenAddr", ":8880", "Address to listen for http connections") datasourceURL = flag.String("datasource.url", "", "Victoria Metrics or VMSelect url. Required parameter. e.g. http://127.0.0.1:8428") @@ -35,7 +36,7 @@ Examples: basicAuthPassword = flag.String("datasource.basicAuth.password", "", "Optional basic auth password to use for -datasource.url") evaluationInterval = flag.Duration("evaluationInterval", 1*time.Minute, "How often to evaluate the rules. Default 1m") notifierURL = flag.String("notifier.url", "", "Prometheus alertmanager URL. Required parameter. e.g. http://127.0.0.1:9093") - externalURL = flag.String("external.url", "", "URL is used to generate sharable alert URL") + externalURL = flag.String("external.url", "", "External URL is used as alert's source for sent alerts to the notifier") ) // TODO: hot configuration reload diff --git a/app/vmalert/rule.go b/app/vmalert/rule.go index 679d2dbf6d..c51d4ce1cb 100644 --- a/app/vmalert/rule.go +++ b/app/vmalert/rule.go @@ -12,7 +12,6 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/datasource" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/notifier" - "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/metricsql" "github.com/VictoriaMetrics/metrics" ) @@ -137,7 +136,6 @@ func (r *Rule) Send(_ context.Context, ap notifier.Notifier) error { r.mu.Unlock() if len(alertsCopy) < 1 { - logger.Infof("no alerts to send") return nil } alertsSent.Add(len(alertsCopy)) diff --git a/app/vmalert/testdata/rules0-good.rules b/app/vmalert/testdata/rules0-good.rules index 5b4a01cb81..6419f3c92b 100644 --- a/app/vmalert/testdata/rules0-good.rules +++ b/app/vmalert/testdata/rules0-good.rules @@ -10,3 +10,13 @@ groups: summary: "{{ $value|humanize }}" description: "{{$labels}}" + - name: TestGroup + rules: + - alert: Conns + expr: sum(vm_tcplistener_conns) by(instance) > 1 + annotations: + summary: "Too high connection number for {{$labels.instance}}" + description: "It is {{ $value }} connections for {{$labels.instance}}" + - alert: ExampleAlertAlwaysFiring + expr: sum by(job) + (up == 1) \ No newline at end of file diff --git a/app/vmalert/vmalert.png b/app/vmalert/vmalert.png deleted file mode 100644 index 197c5e4ef96ae6ea759bc5da8cf38c48c60a18e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25765 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