Annotations for the InfluxDB Module
Signed-off-by: Lorenzo Fontana <lo@linux.com>
This commit is contained in:
parent
83ef18fdb8
commit
1fdab5a18a
10 changed files with 256 additions and 1 deletions
2
Makefile
2
Makefile
|
@ -53,7 +53,7 @@ IMAGE = $(REGISTRY)/$(IMGNAME)
|
|||
MULTI_ARCH_IMG = $(IMAGE)-$(ARCH)
|
||||
|
||||
# Set default base image dynamically for each arch
|
||||
BASEIMAGE?=quay.io/kubernetes-ingress-controller/nginx-$(ARCH):0.45
|
||||
BASEIMAGE?=quay.io/kubernetes-ingress-controller/nginx-$(ARCH):0.46
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
QEMUARCH=arm
|
||||
|
|
|
@ -77,6 +77,11 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz
|
|||
|[nginx.ingress.kubernetes.io/lua-resty-waf-debug](#lua-resty-waf)|"true" or "false"|
|
||||
|[nginx.ingress.kubernetes.io/lua-resty-waf-ignore-rulesets](#lua-resty-waf)|string|
|
||||
|[nginx.ingress.kubernetes.io/lua-resty-waf-extra-rules](#lua-resty-waf)|string|
|
||||
|[nginx.ingress.kubernetes.io/enable-influxdb](#influxdb)|"true" or "false"|
|
||||
|[nginx.ingress.kubernetes.io/influxdb-measurement](#influxdb)|string|
|
||||
|[nginx.ingress.kubernetes.io/influxdb-port](#influxdb)|string|
|
||||
|[nginx.ingress.kubernetes.io/influxdb-host](#influxdb)|string|
|
||||
|[nginx.ingress.kubernetes.io/influxdb-server-name](#influxdb)|string|
|
||||
|
||||
### Rewrite
|
||||
|
||||
|
@ -553,3 +558,25 @@ Additionally, if the gRPC service requires TLS, add `nginx.ingress.kubernetes.io
|
|||
Exposing a gRPC service using HTTP is not supported.
|
||||
|
||||
[configmap]: ./configmap.md
|
||||
|
||||
### InfluxDB
|
||||
|
||||
Using `influxdb-*` annotations we can monitor requests passing through a Location by sending them to an InfluxDB backend exposing the UDP socket
|
||||
using the [nginx-influxdb-module](https://github.com/influxdata/nginx-influxdb-module/).
|
||||
|
||||
```yaml
|
||||
nginx.ingress.kubernetes.io/enable-influxdb: "true"
|
||||
nginx.ingress.kubernetes.io/influxdb-measurement: "nginx-reqs"
|
||||
nginx.ingress.kubernetes.io/influxdb-port: "8089"
|
||||
nginx.ingress.kubernetes.io/influxdb-host: "influxdb"
|
||||
nginx.ingress.kubernetes.io/influxdb-server-name: "nginx-ingress"
|
||||
```
|
||||
|
||||
For the `influxdb-host` parameter you have two options:
|
||||
|
||||
To use the module in the Kubernetes Nginx ingress controller, you have two options:
|
||||
|
||||
- Use an InfluxDB server configured to enable the [UDP protocol](https://docs.influxdata.com/influxdb/v1.5/supported_protocols/udp/).
|
||||
- Deploy Telegraf as a sidecar proxy to the Ingress controller configured to listen UDP with the [socket listener input](https://github.com/influxdata/telegraf/tree/release-1.6/plugins/inputs/socket_listener) and to write using
|
||||
anyone of the [outputs plugins](https://github.com/influxdata/telegraf/tree/release-1.6/plugins/outputs)
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/annotations/defaultbackend"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/grpc"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/healthcheck"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/influxdb"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/loadbalancing"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/log"
|
||||
|
@ -95,6 +96,7 @@ type Ingress struct {
|
|||
Logs log.Config
|
||||
GRPC bool
|
||||
LuaRestyWAF luarestywaf.Config
|
||||
InfluxDB influxdb.Config
|
||||
}
|
||||
|
||||
// Extractor defines the annotation parsers to be used in the extraction of annotations
|
||||
|
@ -136,6 +138,7 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
|
|||
"Logs": log.NewParser(cfg),
|
||||
"GRPC": grpc.NewParser(cfg),
|
||||
"LuaRestyWAF": luarestywaf.NewParser(cfg),
|
||||
"InfluxDB": influxdb.NewParser(cfg),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
104
internal/ingress/annotations/influxdb/main.go
Normal file
104
internal/ingress/annotations/influxdb/main.go
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package influxdb
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
type influxdb struct {
|
||||
r resolver.Resolver
|
||||
}
|
||||
|
||||
// Config contains the IfluxDB configuration to be used in the Ingress
|
||||
type Config struct {
|
||||
InfluxDBEnabled bool `json:"influxDBEnabled"`
|
||||
InfluxDBMeasurement string `json:"influxDBMeasurement"`
|
||||
InfluxDBPort string `json:"influxDBPort"`
|
||||
InfluxDBHost string `json:"influxDBHost"`
|
||||
InfluxDBServerName string `json:"influxDBServerName"`
|
||||
}
|
||||
|
||||
// NewParser creates a new InfluxDB annotation parser
|
||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||
return influxdb{r}
|
||||
}
|
||||
|
||||
// Parse parses the annotations to look for InfluxDB configurations
|
||||
func (c influxdb) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
influxdbEnabled, err := parser.GetBoolAnnotation("enable-influxdb", ing)
|
||||
if err != nil {
|
||||
influxdbEnabled = false
|
||||
}
|
||||
|
||||
influxdbMeasurement, err := parser.GetStringAnnotation("influxdb-measurement", ing)
|
||||
if err != nil {
|
||||
influxdbMeasurement = "default"
|
||||
}
|
||||
|
||||
influxdbPort, err := parser.GetStringAnnotation("influxdb-port", ing)
|
||||
if err != nil {
|
||||
// This is not the default 8086 port but the port usually used to expose
|
||||
// influxdb in UDP, the module uses UDP to talk to influx via the line protocol.
|
||||
influxdbPort = "8089"
|
||||
}
|
||||
|
||||
influxdbHost, err := parser.GetStringAnnotation("influxdb-host", ing)
|
||||
if err != nil {
|
||||
influxdbHost = "127.0.0.1"
|
||||
}
|
||||
|
||||
influxdbServerName, err := parser.GetStringAnnotation("influxdb-server-name", ing)
|
||||
if err != nil {
|
||||
influxdbServerName = "nginx-ingress"
|
||||
}
|
||||
|
||||
return &Config{
|
||||
InfluxDBEnabled: influxdbEnabled,
|
||||
InfluxDBMeasurement: influxdbMeasurement,
|
||||
InfluxDBPort: influxdbPort,
|
||||
InfluxDBHost: influxdbHost,
|
||||
InfluxDBServerName: influxdbServerName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Equal tests for equality between two Config types
|
||||
func (e1 *Config) Equal(e2 *Config) bool {
|
||||
if e1 == e2 {
|
||||
return true
|
||||
}
|
||||
if e1 == nil || e2 == nil {
|
||||
return false
|
||||
}
|
||||
if e1.InfluxDBEnabled != e2.InfluxDBEnabled {
|
||||
return false
|
||||
}
|
||||
if e1.InfluxDBPort != e2.InfluxDBPort {
|
||||
return false
|
||||
}
|
||||
if e1.InfluxDBHost != e2.InfluxDBHost {
|
||||
return false
|
||||
}
|
||||
if e1.InfluxDBServerName != e2.InfluxDBServerName {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
101
internal/ingress/annotations/influxdb/main_test.go
Normal file
101
internal/ingress/annotations/influxdb/main_test.go
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package influxdb
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestIngressInfluxDB(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[parser.GetAnnotationWithPrefix("enable-influxdb")] = "true"
|
||||
data[parser.GetAnnotationWithPrefix("influxdb-measurement")] = "nginxmeasures"
|
||||
data[parser.GetAnnotationWithPrefix("influxdb-port")] = "9091"
|
||||
data[parser.GetAnnotationWithPrefix("influxdb-host")] = "mytelegrafserver.mycompany.mytld"
|
||||
data[parser.GetAnnotationWithPrefix("influxdb-server-name")] = "nginx-test-1"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
influx, _ := NewParser(&resolver.Mock{}).Parse(ing)
|
||||
nginxInflux, ok := influx.(*Config)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
}
|
||||
|
||||
if !nginxInflux.InfluxDBEnabled {
|
||||
t.Errorf("expected influxdb enabled but returned %v", nginxInflux.InfluxDBEnabled)
|
||||
}
|
||||
|
||||
if nginxInflux.InfluxDBMeasurement != "nginxmeasures" {
|
||||
t.Errorf("expected measurement name not found. Found %v", nginxInflux.InfluxDBMeasurement)
|
||||
}
|
||||
|
||||
if nginxInflux.InfluxDBPort != "9091" {
|
||||
t.Errorf("expected port not found. Found %v", nginxInflux.InfluxDBPort)
|
||||
}
|
||||
|
||||
if nginxInflux.InfluxDBHost != "mytelegrafserver.mycompany.mytld" {
|
||||
t.Errorf("expected host not found. Found %v", nginxInflux.InfluxDBHost)
|
||||
}
|
||||
|
||||
if nginxInflux.InfluxDBServerName != "nginx-test-1" {
|
||||
t.Errorf("expected server name not found. Found %v", nginxInflux.InfluxDBServerName)
|
||||
}
|
||||
}
|
|
@ -516,6 +516,11 @@ type Configuration struct {
|
|||
// DisableLuaRestyWAF disables lua-resty-waf globally regardless
|
||||
// of whether there's an ingress that has enabled the WAF using annotation
|
||||
DisableLuaRestyWAF bool `json:"disable-lua-resty-waf"`
|
||||
|
||||
// EnableInfluxDB enables the nginx InfluxDB extension
|
||||
// http://github.com/influxdata/nginx-influxdb-module/
|
||||
// By default this is disabled
|
||||
EnableInfluxDB bool `json:"enable-influxdb"`
|
||||
}
|
||||
|
||||
// NewDefault returns the default nginx configuration
|
||||
|
|
|
@ -450,6 +450,7 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
|
|||
loc.Logs = anns.Logs
|
||||
loc.GRPC = anns.GRPC
|
||||
loc.LuaRestyWAF = anns.LuaRestyWAF
|
||||
loc.InfluxDB = anns.InfluxDB
|
||||
|
||||
if loc.Redirect.FromToWWW {
|
||||
server.RedirectFromToWWW = true
|
||||
|
@ -486,6 +487,7 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
|
|||
Logs: anns.Logs,
|
||||
GRPC: anns.GRPC,
|
||||
LuaRestyWAF: anns.LuaRestyWAF,
|
||||
InfluxDB: anns.InfluxDB,
|
||||
}
|
||||
|
||||
if loc.Redirect.FromToWWW {
|
||||
|
@ -922,6 +924,7 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
|
|||
defLoc.Denied = anns.Denied
|
||||
defLoc.GRPC = anns.GRPC
|
||||
defLoc.LuaRestyWAF = anns.LuaRestyWAF
|
||||
defLoc.InfluxDB = anns.InfluxDB
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/annotations/authtls"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/connection"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/cors"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/influxdb"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/log"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/luarestywaf"
|
||||
|
@ -271,6 +272,9 @@ type Location struct {
|
|||
GRPC bool `json:"grpc"`
|
||||
// LuaRestyWAF contains parameters to configure lua-resty-waf
|
||||
LuaRestyWAF luarestywaf.Config `json:"luaRestyWAF"`
|
||||
// InfluxDB allows to monitor the incoming request by sending them to an influxdb database
|
||||
// +optional
|
||||
InfluxDB influxdb.Config `json:"influxDB,omitempty"`
|
||||
}
|
||||
|
||||
// SSLPassthroughBackend describes a SSL upstream server configured
|
||||
|
|
|
@ -389,6 +389,10 @@ func (l1 *Location) Equal(l2 *Location) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if !(&l1.InfluxDB).Equal(&l2.InfluxDB) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -980,6 +980,10 @@ stream {
|
|||
{{ template "CORS" $location }}
|
||||
{{ end }}
|
||||
|
||||
{{ if $location.InfluxDB.InfluxDBEnabled }}
|
||||
influxdb server_name=$location.InfluxDB.InfluxDBServerName host=$location.InfluxDB.InfluxDBHost port=$location.InfluxDB.InfluxDBPort measurement=$location.InfluxDB.InfluxDBMeasurement enabled=true;
|
||||
{{ end }}
|
||||
|
||||
{{ if not (empty $location.Redirect.URL) }}
|
||||
if ($uri ~* {{ $path }}) {
|
||||
return {{ $location.Redirect.Code }} {{ $location.Redirect.URL }};
|
||||
|
|
Loading…
Reference in a new issue