Provide annotation to control opentracing

By default you might want opentracing off, but on for a particular
ingress.

Similarly, you might want opentracing globally on, but disabled for
a specific endpoint. To achieve this, `opentracing_propagate_context`
cannot be set when combined with `opentracing off`

A new annotation, `enable-opentracing` allows more fine grained control
of opentracing for specific ingresses.
This commit is contained in:
Will Thames 2019-10-30 13:30:01 +10:00
parent 40e0e5bef8
commit 0ae463a5f3
8 changed files with 214 additions and 0 deletions

View file

@ -99,6 +99,7 @@ You can add these Kubernetes annotations to specific Ingress objects to customiz
|[nginx.ingress.kubernetes.io/ssl-ciphers](#ssl-ciphers)|string| |[nginx.ingress.kubernetes.io/ssl-ciphers](#ssl-ciphers)|string|
|[nginx.ingress.kubernetes.io/connection-proxy-header](#connection-proxy-header)|string| |[nginx.ingress.kubernetes.io/connection-proxy-header](#connection-proxy-header)|string|
|[nginx.ingress.kubernetes.io/enable-access-log](#enable-access-log)|"true" or "false"| |[nginx.ingress.kubernetes.io/enable-access-log](#enable-access-log)|"true" or "false"|
|[nginx.ingress.kubernetes.io/enable-opentracing](#enable-opentracing)|"true" or "false"|
|[nginx.ingress.kubernetes.io/lua-resty-waf](#lua-resty-waf)|string| |[nginx.ingress.kubernetes.io/lua-resty-waf](#lua-resty-waf)|string|
|[nginx.ingress.kubernetes.io/lua-resty-waf-debug](#lua-resty-waf)|"true" or "false"| |[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-ignore-rulesets](#lua-resty-waf)|string|
@ -670,6 +671,15 @@ Note that rewrite logs are sent to the error_log file at the notice level. To en
nginx.ingress.kubernetes.io/enable-rewrite-log: "true" nginx.ingress.kubernetes.io/enable-rewrite-log: "true"
``` ```
### Enable Opentracing
Opentracing can be enabled or disabled globally through the ConfigMap but this will sometimes need to be overridden
to enable it or disable it for a specific ingress (e.g. to turn off tracing of external health check endpoints)
```yaml
nginx.ingress.kubernetes.io/enable-opentracing: "true"
```
### X-Forwarded-Prefix Header ### X-Forwarded-Prefix Header
To add the non-standard `X-Forwarded-Prefix` header to the upstream request with a string value, the following annotation can be used: To add the non-standard `X-Forwarded-Prefix` header to the upstream request with a string value, the following annotation can be used:

View file

@ -13,6 +13,15 @@ data:
enable-opentracing: "true" enable-opentracing: "true"
``` ```
To enable or disable instrumentation for a single Ingress, use
the `enable-opentracing` annotation:
```
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/enable-opentracing: "true"
```
We must also set the host to use when uploading traces: We must also set the host to use when uploading traces:
``` ```

View file

@ -47,6 +47,7 @@ import (
"k8s.io/ingress-nginx/internal/ingress/annotations/log" "k8s.io/ingress-nginx/internal/ingress/annotations/log"
"k8s.io/ingress-nginx/internal/ingress/annotations/luarestywaf" "k8s.io/ingress-nginx/internal/ingress/annotations/luarestywaf"
"k8s.io/ingress-nginx/internal/ingress/annotations/mirror" "k8s.io/ingress-nginx/internal/ingress/annotations/mirror"
"k8s.io/ingress-nginx/internal/ingress/annotations/opentracing"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser" "k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/annotations/portinredirect" "k8s.io/ingress-nginx/internal/ingress/annotations/portinredirect"
"k8s.io/ingress-nginx/internal/ingress/annotations/proxy" "k8s.io/ingress-nginx/internal/ingress/annotations/proxy"
@ -90,6 +91,7 @@ type Ingress struct {
ExternalAuth authreq.Config ExternalAuth authreq.Config
EnableGlobalAuth bool EnableGlobalAuth bool
HTTP2PushPreload bool HTTP2PushPreload bool
Opentracing opentracing.Config
Proxy proxy.Config Proxy proxy.Config
ProxySSL proxyssl.Config ProxySSL proxyssl.Config
RateLimit ratelimit.Config RateLimit ratelimit.Config
@ -138,6 +140,7 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
"ExternalAuth": authreq.NewParser(cfg), "ExternalAuth": authreq.NewParser(cfg),
"EnableGlobalAuth": authreqglobal.NewParser(cfg), "EnableGlobalAuth": authreqglobal.NewParser(cfg),
"HTTP2PushPreload": http2pushpreload.NewParser(cfg), "HTTP2PushPreload": http2pushpreload.NewParser(cfg),
"Opentracing": opentracing.NewParser(cfg),
"Proxy": proxy.NewParser(cfg), "Proxy": proxy.NewParser(cfg),
"ProxySSL": proxyssl.NewParser(cfg), "ProxySSL": proxyssl.NewParser(cfg),
"RateLimit": ratelimit.NewParser(cfg), "RateLimit": ratelimit.NewParser(cfg),

View file

@ -0,0 +1,57 @@
/*
Copyright 2019 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 opentracing
import (
networking "k8s.io/api/networking/v1beta1"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)
type opentracing struct {
r resolver.Resolver
}
// Config contains the configuration to be used in the Ingress
type Config struct {
Enabled bool `json:"enabled"`
Set bool `json:"set"`
}
// Equal tests for equality between two Config types
func (bd1 *Config) Equal(bd2 *Config) bool {
if bd1.Set != bd2.Set {
return false
} else if bd1.Enabled != bd2.Enabled {
return false
}
return true
}
// NewParser creates a new serviceUpstream annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return opentracing{r}
}
func (s opentracing) Parse(ing *networking.Ingress) (interface{}, error) {
enabled, err := parser.GetBoolAnnotation("enable-opentracing", ing)
if err != nil {
return &Config{Set: false, Enabled: false}, nil
}
return &Config{Set: true, Enabled: enabled}, nil
}

View file

@ -0,0 +1,121 @@
/*
Copyright 2017 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 opentracing
import (
"testing"
api "k8s.io/api/core/v1"
networking "k8s.io/api/networking/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() *networking.Ingress {
defaultBackend := networking.IngressBackend{
ServiceName: "default-backend",
ServicePort: intstr.FromInt(80),
}
return &networking.Ingress{
ObjectMeta: meta_v1.ObjectMeta{
Name: "foo",
Namespace: api.NamespaceDefault,
},
Spec: networking.IngressSpec{
Backend: &networking.IngressBackend{
ServiceName: "default-backend",
ServicePort: intstr.FromInt(80),
},
Rules: []networking.IngressRule{
{
Host: "foo.bar.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/foo",
Backend: defaultBackend,
},
},
},
},
},
},
},
}
}
func TestIngressAnnotationOpentracingSetTrue(t *testing.T) {
ing := buildIngress()
data := map[string]string{}
data[parser.GetAnnotationWithPrefix("enable-opentracing")] = "true"
ing.SetAnnotations(data)
val, _ := NewParser(&resolver.Mock{}).Parse(ing)
openTracing, ok := val.(*Config)
if !ok {
t.Errorf("expected a Config type")
}
if !openTracing.Set {
t.Errorf("expected annotation value to be set")
}
if !openTracing.Enabled {
t.Errorf("expected annotation value to be true, got false")
}
}
func TestIngressAnnotationOpentracingSetFalse(t *testing.T) {
ing := buildIngress()
// Test with explicitly set to false
data := map[string]string{}
data[parser.GetAnnotationWithPrefix("enable-opentracing")] = "false"
ing.SetAnnotations(data)
val, _ := NewParser(&resolver.Mock{}).Parse(ing)
openTracing, ok := val.(*Config)
if !ok {
t.Errorf("expected a Config type")
}
if !openTracing.Set {
t.Errorf("expected annotation value to be set")
}
if openTracing.Enabled {
t.Errorf("expected annotation value to be false, got true")
}
}
func TestIngressAnnotationOpentracingUnset(t *testing.T) {
ing := buildIngress()
// Test with no annotation specified
data := map[string]string{}
ing.SetAnnotations(data)
val, _ := NewParser(&resolver.Mock{}).Parse(ing)
openTracing, ok := val.(*Config)
if !ok {
t.Errorf("expected a Config type")
}
if openTracing.Set {
t.Errorf("expected annotation value to be unset")
}
}

View file

@ -1169,6 +1169,7 @@ func locationApplyAnnotations(loc *ingress.Location, anns *annotations.Ingress)
loc.ExternalAuth = anns.ExternalAuth loc.ExternalAuth = anns.ExternalAuth
loc.EnableGlobalAuth = anns.EnableGlobalAuth loc.EnableGlobalAuth = anns.EnableGlobalAuth
loc.HTTP2PushPreload = anns.HTTP2PushPreload loc.HTTP2PushPreload = anns.HTTP2PushPreload
loc.Opentracing = anns.Opentracing
loc.Proxy = anns.Proxy loc.Proxy = anns.Proxy
loc.RateLimit = anns.RateLimit loc.RateLimit = anns.RateLimit
loc.Redirect = anns.Redirect loc.Redirect = anns.Redirect

View file

@ -34,6 +34,7 @@ import (
"k8s.io/ingress-nginx/internal/ingress/annotations/luarestywaf" "k8s.io/ingress-nginx/internal/ingress/annotations/luarestywaf"
"k8s.io/ingress-nginx/internal/ingress/annotations/mirror" "k8s.io/ingress-nginx/internal/ingress/annotations/mirror"
"k8s.io/ingress-nginx/internal/ingress/annotations/modsecurity" "k8s.io/ingress-nginx/internal/ingress/annotations/modsecurity"
"k8s.io/ingress-nginx/internal/ingress/annotations/opentracing"
"k8s.io/ingress-nginx/internal/ingress/annotations/proxy" "k8s.io/ingress-nginx/internal/ingress/annotations/proxy"
"k8s.io/ingress-nginx/internal/ingress/annotations/proxyssl" "k8s.io/ingress-nginx/internal/ingress/annotations/proxyssl"
"k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit" "k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit"
@ -333,6 +334,9 @@ type Location struct {
// Mirror allows you to mirror traffic to a "test" backend // Mirror allows you to mirror traffic to a "test" backend
// +optional // +optional
Mirror mirror.Config `json:"mirror,omitempty"` Mirror mirror.Config `json:"mirror,omitempty"`
// Opentracing allows the global opentracing setting to be overridden for a location
// +optional
Opentracing opentracing.Config `json:"opentracing"`
} }
// SSLPassthroughBackend describes a SSL upstream server configured // SSLPassthroughBackend describes a SSL upstream server configured

View file

@ -962,8 +962,17 @@ stream {
set $location_path {{ $location.Path | escapeLiteralDollar | quote }}; set $location_path {{ $location.Path | escapeLiteralDollar | quote }};
{{ if $all.Cfg.EnableOpentracing }} {{ if $all.Cfg.EnableOpentracing }}
{{ if and $location.Opentracing.Set (not $location.Opentracing.Enabled) }}
opentracing off;
{{ else }}
{{ opentracingPropagateContext $location }}; {{ opentracingPropagateContext $location }};
{{ end }} {{ end }}
{{ else }}
{{ if and $location.Opentracing.Set $location.Opentracing.Enabled }}
opentracing on;
{{ opentracingPropagateContext $location }};
{{ end }}
{{ end }}
{{ if $location.Mirror.URI }} {{ if $location.Mirror.URI }}
mirror {{ $location.Mirror.URI }}; mirror {{ $location.Mirror.URI }};