Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: OpenTelemetry module integration #9062

Merged
merged 31 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
edf88a1
OpenTelemetry module integration
esigo Sep 18, 2022
23f64ab
e2e test
esigo Sep 18, 2022
a9a3914
e2e test fix
esigo Sep 23, 2022
2526e49
Merge branch 'kubernetes:main' into otel2
esigo Sep 23, 2022
c8ec79a
default OpentelemetryConfig
esigo Sep 24, 2022
f03a819
e2e values
esigo Sep 24, 2022
840f005
mount otel module for otel test only
esigo Sep 25, 2022
3a9bca3
Merge branch 'kubernetes:main' into otel2
esigo Sep 28, 2022
dc319e7
propagate IS_CHROOT
esigo Sep 29, 2022
2d67d1c
propagate IS_CHROOT e2e test
esigo Sep 29, 2022
4e63238
code doc
esigo Sep 30, 2022
4eb38b8
comments
esigo Oct 1, 2022
5420d9a
golint
esigo Oct 5, 2022
ea3f215
opentelemetry doc
esigo Oct 11, 2022
ac09fcc
zipkin
esigo Oct 16, 2022
d9df16c
zipkin
esigo Oct 16, 2022
2ce5273
typo
esigo Nov 7, 2022
bce3358
Merge remote-tracking branch 'upstream/main' into otel2
esigo Dec 31, 2022
dbc5e4d
update e2e test OpenTelemetry value
esigo Dec 31, 2022
98551fa
Merge remote-tracking branch 'upstream/main' into otel2
esigo Jan 11, 2023
f6d0492
Merge remote-tracking branch 'upstream/main' into otel-9016-3
esigo Jan 15, 2023
4e71867
use opentelemetry value
esigo Jan 15, 2023
f5f3edb
Merge remote-tracking branch 'upstream/main' into otel2
esigo Feb 5, 2023
f3e609a
Merge remote-tracking branch 'upstream/main' into otel-9016-3
esigo Feb 5, 2023
dfb26e9
revert merge conflict
esigo Feb 5, 2023
bfdff0b
fix
esigo Feb 5, 2023
a1d9aab
format
esigo Feb 5, 2023
6b8f0c6
review comments
esigo Mar 21, 2023
8d4a2a1
Merge Documentation
esigo Mar 21, 2023
692bad9
Merge remote-tracking branch 'upstream/main' into otel2
esigo Mar 21, 2023
28372b0
clean
esigo Mar 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build/run-e2e-suite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ kubectl run --rm \
--restart=Never \
--env="E2E_NODES=${E2E_NODES}" \
--env="FOCUS=${FOCUS}" \
--env="IS_CHROOT=${IS_CHROOT:-false}"\
--env="E2E_CHECK_LEAKS=${E2E_CHECK_LEAKS}" \
--env="NGINX_BASE_IMAGE=${NGINX_BASE_IMAGE}" \
--overrides='{ "apiVersion": "v1", "spec":{"serviceAccountName": "ingress-nginx-e2e"}}' \
Expand Down
3 changes: 3 additions & 0 deletions internal/ingress/annotations/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/imdario/mergo"
"k8s.io/ingress-nginx/internal/ingress/annotations/canary"
"k8s.io/ingress-nginx/internal/ingress/annotations/modsecurity"
"k8s.io/ingress-nginx/internal/ingress/annotations/opentelemetry"
"k8s.io/ingress-nginx/internal/ingress/annotations/proxyssl"
"k8s.io/ingress-nginx/internal/ingress/annotations/sslcipher"
"k8s.io/ingress-nginx/internal/ingress/annotations/streamsnippet"
Expand Down Expand Up @@ -93,6 +94,7 @@ type Ingress struct {
EnableGlobalAuth bool
HTTP2PushPreload bool
Opentracing opentracing.Config
Opentelemetry opentelemetry.Config
Proxy proxy.Config
ProxySSL proxyssl.Config
RateLimit ratelimit.Config
Expand Down Expand Up @@ -143,6 +145,7 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
"EnableGlobalAuth": authreqglobal.NewParser(cfg),
"HTTP2PushPreload": http2pushpreload.NewParser(cfg),
"Opentracing": opentracing.NewParser(cfg),
"Opentelemetry": opentelemetry.NewParser(cfg),
"Proxy": proxy.NewParser(cfg),
"ProxySSL": proxyssl.NewParser(cfg),
"RateLimit": ratelimit.NewParser(cfg),
Expand Down
85 changes: 85 additions & 0 deletions internal/ingress/annotations/opentelemetry/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
Copyright 2022 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.
*/
strongjz marked this conversation as resolved.
Show resolved Hide resolved

package opentelemetry

import (
networking "k8s.io/api/networking/v1"

"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)

type opentelemetry 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"`
TrustEnabled bool `json:"trust-enabled"`
TrustSet bool `json:"trust-set"`
OperationName string `json:"operation-name"`
}

// Equal tests for equality between two Config types
func (bd1 *Config) Equal(bd2 *Config) bool {

if bd1.Enabled != bd2.Enabled {
return false
}

if bd1.TrustEnabled != bd2.TrustEnabled {
return false
}

return true
}
strongjz marked this conversation as resolved.
Show resolved Hide resolved

func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return opentelemetry{r}
}

// Parse parses the annotations to look for opentelemetry configurations
func (c opentelemetry) Parse(ing *networking.Ingress) (interface{}, error) {
cfg := Config{}
enabled, err := parser.GetBoolAnnotation("enable-opentelemetry", ing)
if err != nil {
return &cfg, nil
}
cfg.Set = true
cfg.Enabled = enabled
if !enabled {
return &cfg, nil
}

trustEnabled, err := parser.GetBoolAnnotation("opentelemetry-trust-incoming-span", ing)
if err != nil {
operationName, err := parser.GetStringAnnotation("opentelemetry-operation-name", ing)
if err != nil {
return &cfg, nil
}
cfg.OperationName = operationName
return &cfg, nil
}

cfg.TrustSet = true
cfg.TrustEnabled = trustEnabled
operationName, err := parser.GetStringAnnotation("opentelemetry-operation-name", ing)
if err != nil {
return &cfg, nil
}
cfg.OperationName = operationName
return &cfg, nil
}
150 changes: 150 additions & 0 deletions internal/ingress/annotations/opentelemetry/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
Copyright 2022 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 opentelemetry

import (
"testing"

api "k8s.io/api/core/v1"
networking "k8s.io/api/networking/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)

func buildIngress() *networking.Ingress {
defaultBackend := networking.IngressBackend{
Service: &networking.IngressServiceBackend{
Name: "default-backend",
Port: networking.ServiceBackendPort{
Number: 80,
},
},
}

return &networking.Ingress{
ObjectMeta: meta_v1.ObjectMeta{
Name: "foo",
Namespace: api.NamespaceDefault,
},
Spec: networking.IngressSpec{
DefaultBackend: &networking.IngressBackend{
Service: &networking.IngressServiceBackend{
Name: "default-backend",
Port: networking.ServiceBackendPort{
Number: 80,
},
},
},
Rules: []networking.IngressRule{
{
Host: "foo.bar.com",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/foo",
Backend: defaultBackend,
},
},
},
},
},
},
},
}
}

func TestIngressAnnotationOpentelemetrySetTrue(t *testing.T) {
ing := buildIngress()

data := map[string]string{}
data[parser.GetAnnotationWithPrefix("enable-opentelemetry")] = "true"
ing.SetAnnotations(data)

val, _ := NewParser(&resolver.Mock{}).Parse(ing)
openTelemetry, ok := val.(*Config)
if !ok {
t.Errorf("expected a Config type")
}

if !openTelemetry.Enabled {
t.Errorf("expected annotation value to be true, got false")
}
}

func TestIngressAnnotationOpentelemetrySetFalse(t *testing.T) {
ing := buildIngress()

// Test with explicitly set to false
data := map[string]string{}
data[parser.GetAnnotationWithPrefix("enable-opentelemetry")] = "false"
ing.SetAnnotations(data)

val, _ := NewParser(&resolver.Mock{}).Parse(ing)
openTelemetry, ok := val.(*Config)
if !ok {
t.Errorf("expected a Config type")
}

if openTelemetry.Enabled {
t.Errorf("expected annotation value to be false, got true")
}
}

func TestIngressAnnotationOpentelemetryTrustSetTrue(t *testing.T) {
ing := buildIngress()

data := map[string]string{}
opName := "foo-op"
data[parser.GetAnnotationWithPrefix("enable-opentelemetry")] = "true"
data[parser.GetAnnotationWithPrefix("opentelemetry-trust-incoming-span")] = "true"
data[parser.GetAnnotationWithPrefix("opentelemetry-operation-name")] = opName
ing.SetAnnotations(data)

val, _ := NewParser(&resolver.Mock{}).Parse(ing)
openTelemetry, ok := val.(*Config)
if !ok {
t.Errorf("expected a Config type")
}

if !openTelemetry.Enabled {
t.Errorf("expected annotation value to be true, got false")
}

if !openTelemetry.TrustEnabled {
t.Errorf("expected annotation value to be true, got false")
}

if openTelemetry.OperationName != opName {
t.Errorf("expected annotation value to be %v, got %v", opName, openTelemetry.OperationName)
}
}

func TestIngressAnnotationOpentelemetryUnset(t *testing.T) {
ing := buildIngress()

// Test with no annotation specified
data := map[string]string{}
ing.SetAnnotations(data)

val, _ := NewParser(&resolver.Mock{}).Parse(ing)
_, ok := val.(*Config)
if !ok {
t.Errorf("expected a Config type")
}
}
55 changes: 55 additions & 0 deletions internal/ingress/controller/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,54 @@ type Configuration struct {
// Default: true
OpentracingTrustIncomingSpan bool `json:"opentracing-trust-incoming-span"`

// EnableOpentelemetry enables the nginx Opentelemetry extension
// By default this is disabled
EnableOpentelemetry bool `json:"enable-opentelemetry"`

// OpentelemetryConfig sets the opentelemetry config file
// Default: /etc/nginx/opentelemtry.toml
OpentelemetryConfig string `json:"opentelemetry-config"`

// OpentelemetryOperationName specifies a custom name for the server span
OpentelemetryOperationName string `json:"opentelemetry-operation-name"`
strongjz marked this conversation as resolved.
Show resolved Hide resolved

// OpentelemetryTrustIncomingSpan sets whether or not to trust incoming trace spans
// If false, incoming span headers will be rejected
// Default: true
OpentelemetryTrustIncomingSpan bool `json:"opentelemetry-trust-incoming-span"`

// OtlpCollectorHost specifies the host to use when uploading traces
OtlpCollectorHost string `json:"otlp-collector-host"`

// OtlpCollectorPort specifies the port to use when uploading traces
// Default: 4317
OtlpCollectorPort string `json:"otlp-collector-port"`

// OtelServiceName specifies the service name to use for any traces created
// Default: nginx
OtelServiceName string `json:"otel-service-name"`

// OtelSampler specifies the sampler to use for any traces created
// Default: AlwaysOff
OtelSampler string `json:"otel-sampler"`

// OtelSamplerRatio specifies the sampler ratio to use for any traces created
// Default: 0.01
OtelSamplerRatio float32 `json:"otel-sampler-ratio"`

//OtelSamplerParantBased specifies the parent based sampler to be use for any traces created
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//OtelSamplerParantBased specifies the parent based sampler to be use for any traces created
//OtelSamplerParentBased specifies the parent based sampler to be use for any traces created

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks fixed.

// Default: false
OtelSamplerParantBased bool `json:"otel-sampler-parent-based"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
OtelSamplerParantBased bool `json:"otel-sampler-parent-based"`
OtelSamplerParentBased bool `json:"otel-sampler-parent-based"`

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks fixed.


// MaxQueueSize specifies the max queue size for uploading traces
OtelMaxQueueSize int32 `json:"otel-max-queuesize"`

// ScheduleDelayMillis specifies the max delay between uploading traces
OtelScheduleDelayMillis int32 `json:"otel-schedule-delay-millis"`

// MaxExportBatchSize specifies the max export batch size to used when uploading traces
OtelMaxExportBatchSize int32 `json:"otel-max-export-batch-size"`

// ZipkinCollectorHost specifies the host to use when uploading traces
ZipkinCollectorHost string `json:"zipkin-collector-host"`

Expand Down Expand Up @@ -908,6 +956,13 @@ func NewDefault() Configuration {
BindAddressIpv4: defBindAddress,
BindAddressIpv6: defBindAddress,
OpentracingTrustIncomingSpan: true,
OpentelemetryTrustIncomingSpan: true,
OpentelemetryConfig: "/etc/nginx/opentelemtry.toml",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
OpentelemetryConfig: "/etc/nginx/opentelemtry.toml",
OpentelemetryConfig: "/etc/nginx/opentelemetry.toml",

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks fixed.

OtlpCollectorPort: "4317",
OtelServiceName: "nginx",
OtelSampler: "AlwaysOff",
strongjz marked this conversation as resolved.
Show resolved Hide resolved
OtelSamplerRatio: 0.01,
OtelSamplerParantBased: false,
Copy link
Contributor

@pellmont pellmont Nov 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
OtelSamplerParantBased: false,
OtelSamplerParentBased: true,

to reflect otel collectors default?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might also need to be OtelSamplerParentBased?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks OtelSamplerParentBased is false by default. typo fixed.

ZipkinCollectorPort: 9411,
ZipkinServiceName: "nginx",
ZipkinSampleRate: 1.0,
Expand Down
1 change: 1 addition & 0 deletions internal/ingress/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1405,6 +1405,7 @@ func locationApplyAnnotations(loc *ingress.Location, anns *annotations.Ingress)
loc.EnableGlobalAuth = anns.EnableGlobalAuth
loc.HTTP2PushPreload = anns.HTTP2PushPreload
loc.Opentracing = anns.Opentracing
loc.Opentelemetry = anns.Opentelemetry
loc.Proxy = anns.Proxy
loc.ProxySSL = anns.ProxySSL
loc.RateLimit = anns.RateLimit
Expand Down
Loading