Skip to content

Commit

Permalink
Support monolithic deployment mode (#722)
Browse files Browse the repository at this point in the history
* Support monolithic deployment mode

Signed-off-by: Andreas Gerstmayr <[email protected]>

* Add changelog

Signed-off-by: Andreas Gerstmayr <[email protected]>

* update mutate_test.go

Signed-off-by: Andreas Gerstmayr <[email protected]>

* add webhook tests

Signed-off-by: Andreas Gerstmayr <[email protected]>

* add generated files

Signed-off-by: Andreas Gerstmayr <[email protected]>

* support pruning unmanaged objects

Signed-off-by: Andreas Gerstmayr <[email protected]>

* use common reconcile/prune function

Signed-off-by: Andreas Gerstmayr <[email protected]>

* fix linter

Signed-off-by: Andreas Gerstmayr <[email protected]>

* add sts tests

Signed-off-by: Andreas Gerstmayr <[email protected]>

* add service tests

Signed-off-by: Andreas Gerstmayr <[email protected]>

* add configmap tests

Signed-off-by: Andreas Gerstmayr <[email protected]>

* use a single service, because the monolithic deployment will use a single pod

Signed-off-by: Andreas Gerstmayr <[email protected]>

* drop component from labels

Signed-off-by: Andreas Gerstmayr <[email protected]>

* fix configmap

Signed-off-by: Andreas Gerstmayr <[email protected]>

* TestBuildAll()

Signed-off-by: Andreas Gerstmayr <[email protected]>

* add e2e test

Signed-off-by: Andreas Gerstmayr <[email protected]>

* drop defaulter webhook for TempoMonolithic

Signed-off-by: Andreas Gerstmayr <[email protected]>

* delete operator namespace and webhooks in make run

Signed-off-by: Andreas Gerstmayr <[email protected]>

* change the way to include .env file

Signed-off-by: Andreas Gerstmayr <[email protected]>

* rebuild bundle, fix linter

Signed-off-by: Andreas Gerstmayr <[email protected]>

* fix typo in jaeger-grpc port name

Signed-off-by: Andreas Gerstmayr <[email protected]>

* add warning when overriding tempo config

Signed-off-by: Andreas Gerstmayr <[email protected]>

* specify default value of storage.traces.backend

Signed-off-by: Andreas Gerstmayr <[email protected]>

* update storage docs

Signed-off-by: Andreas Gerstmayr <[email protected]>

* drop .env file

Signed-off-by: Andreas Gerstmayr <[email protected]>

* reconcile: retry on conflict

Signed-off-by: Andreas Gerstmayr <[email protected]>

* update changelog, set size defaults, add api docs

Signed-off-by: Andreas Gerstmayr <[email protected]>

* update changelog

Signed-off-by: Andreas Gerstmayr <[email protected]>

* fix test

Signed-off-by: Andreas Gerstmayr <[email protected]>

* add controller test

Signed-off-by: Andreas Gerstmayr <[email protected]>

* enable OTLP/HTTP by default

Signed-off-by: Andreas Gerstmayr <[email protected]>

* drop TLS struct (will reuse TLS struct from TempoStack in follow-up PR)

Signed-off-by: Andreas Gerstmayr <[email protected]>

* add comment to default function

Signed-off-by: Andreas Gerstmayr <[email protected]>

* show diff using cmp.Diff() in logs when immutable field is changed

Signed-off-by: Andreas Gerstmayr <[email protected]>

* re-use ExtraConfig from TempoStack

Signed-off-by: Andreas Gerstmayr <[email protected]>

* add comment on exported function

Signed-off-by: Andreas Gerstmayr <[email protected]>

---------

Signed-off-by: Andreas Gerstmayr <[email protected]>
  • Loading branch information
andreasgerstmayr authored Jan 26, 2024
1 parent 2d4c168 commit d8afdec
Show file tree
Hide file tree
Showing 68 changed files with 5,713 additions and 759 deletions.
18 changes: 18 additions & 0 deletions .chloggen/monolithic_mode.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. operator, github action)
component: operator

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Support monolithic deployment mode

# One or more tracking issues related to the change
issues: [710]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext: |
The operator exposes a new CRD `TempoMonolithic`, which manages a Tempo instance in monolithic mode.
The monolithic mode supports the following additional storage backends: in-memory and file system (persistent volume).
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ cmctl:
}

.PHONY: api-docs
api-docs: docs/operator/api.md docs/operator/feature-gates.md docs/spec/tempo.grafana.com_tempostacks.yaml
api-docs: docs/operator/api.md docs/operator/feature-gates.md docs/spec/tempo.grafana.com_tempostacks.yaml docs/spec/tempo.grafana.com_tempomonolithics.yaml

TYPES_TARGET := $(shell find apis/tempo -type f -iname "*_types.go")
docs/operator/api.md: $(TYPES_TARGET) gen-crd-api-reference-docs
Expand Down
13 changes: 13 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,17 @@ resources:
defaulting: true
validation: true
webhookVersion: v1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: grafana.com
group: tempo
kind: TempoMonolithic
path: github.com/grafana/tempo-operator/api/v1alpha1
version: v1alpha1
webhooks:
defaulting: true
validation: true
webhookVersion: v1
version: "3"
236 changes: 236 additions & 0 deletions apis/tempo/v1alpha1/tempomonolithic_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
package v1alpha1

import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// TempoMonolithicSpec defines the desired state of TempoMonolithic.
type TempoMonolithicSpec struct {
// Storage defines the backend storage configuration
//
// +kubebuilder:validation:Optional
Storage *MonolithicStorageSpec `json:"storage,omitempty"`

// Ingestion defines the trace ingestion configuration
//
// +kubebuilder:validation:Optional
Ingestion *MonolithicIngestionSpec `json:"ingestion,omitempty"`

// JaegerUI defines the Jaeger UI configuration
//
// +kubebuilder:validation:Optional
JaegerUI *MonolithicJaegerUISpec `json:"jaegerui,omitempty"`

// ManagementState defines whether this instance is managed by the operator or self-managed
//
// +kubebuilder:validation:Optional
Management ManagementStateType `json:"management,omitempty"`

// Observability defines observability configuration for the Tempo deployment
//
// +kubebuilder:validation:Optional
Observability *MonolithicObservabilitySpec `json:"observability,omitempty"`

// ExtraConfig defines any extra (overlay) configuration for components
//
// +kubebuilder:validation:Optional
ExtraConfig *ExtraConfigSpec `json:"extraConfig,omitempty"`
}

// MonolithicStorageSpec defines the storage for the Tempo deployment.
type MonolithicStorageSpec struct {
// Traces defines the backend storage configuration for traces
//
// +kubebuilder:validation:Required
Traces MonolithicTracesStorageSpec `json:"traces"`
}

// MonolithicTracesStorageSpec defines the traces storage for the Tempo deployment.
type MonolithicTracesStorageSpec struct {
// Backend defines the backend for storing traces. Default: memory
//
// +kubebuilder:validation:Required
// +kubebuilder:default=memory
Backend MonolithicTracesStorageBackend `json:"backend"`

// WAL defines the write-ahead logging (WAL) configuration
//
// +kubebuilder:validation:Optional
WAL *MonolithicTracesStorageWALSpec `json:"wal,omitempty"`

// PV defines the Persistent Volume configuration
//
// +kubebuilder:validation:Optional
PV *MonolithicTracesStoragePVSpec `json:"pv,omitempty"`
}

// MonolithicTracesStorageBackend defines the backend storage for traces.
//
// +kubebuilder:validation:Enum=memory;pv
type MonolithicTracesStorageBackend string

const (
// MonolithicTracesStorageBackendMemory defines storing traces in a tmpfs (in-memory filesystem).
MonolithicTracesStorageBackendMemory MonolithicTracesStorageBackend = "memory"
// MonolithicTracesStorageBackendPV defines storing traces in a Persistent Volume.
MonolithicTracesStorageBackendPV MonolithicTracesStorageBackend = "pv"
)

// MonolithicTracesStorageWALSpec defines the write-ahead logging (WAL) configuration.
type MonolithicTracesStorageWALSpec struct {
// Size defines the size of the Persistent Volume for storing the WAL. Defaults to 10Gi.
//
// +kubebuilder:validation:Required
// +kubebuilder:default="10Gi"
Size resource.Quantity `json:"size"`
}

// MonolithicTracesStoragePVSpec defines the Persistent Volume configuration.
type MonolithicTracesStoragePVSpec struct {
// Size defines the size of the Persistent Volume for storing the traces. Defaults to 10Gi.
//
// +kubebuilder:validation:Required
// +kubebuilder:default="10Gi"
Size resource.Quantity `json:"size"`
}

// MonolithicIngestionSpec defines the ingestion settings.
type MonolithicIngestionSpec struct {
// OTLP defines the ingestion configuration for OTLP
//
// +kubebuilder:validation:Optional
OTLP *MonolithicIngestionOTLPSpec `json:"otlp,omitempty"`
}

// MonolithicIngestionOTLPSpec defines the settings for OTLP ingestion.
type MonolithicIngestionOTLPSpec struct {
// GRPC defines the OTLP/gRPC configuration
//
// +kubebuilder:validation:Optional
GRPC *MonolithicIngestionOTLPProtocolsGRPCSpec `json:"grpc,omitempty"`

// HTTP defines the OTLP/HTTP configuration
//
// +kubebuilder:validation:Optional
HTTP *MonolithicIngestionOTLPProtocolsHTTPSpec `json:"http,omitempty"`
}

// MonolithicIngestionOTLPProtocolsGRPCSpec defines the settings for OTLP ingestion over GRPC.
type MonolithicIngestionOTLPProtocolsGRPCSpec struct {
// Enabled defines if OTLP over gRPC is enabled
//
// +kubebuilder:validation:Required
// +kubebuilder:default=true
Enabled bool `json:"enabled"`
}

// MonolithicIngestionOTLPProtocolsHTTPSpec defines the settings for OTLP ingestion over HTTP.
type MonolithicIngestionOTLPProtocolsHTTPSpec struct {
// Enabled defines if OTLP over HTTP is enabled
//
// +kubebuilder:validation:Required
Enabled bool `json:"enabled"`
}

// MonolithicJaegerUISpec defines the settings for the Jaeger UI.
type MonolithicJaegerUISpec struct {
// Enabled defines if the Jaeger UI should be enabled
//
// +kubebuilder:validation:Required
Enabled bool `json:"enabled"`

// Ingress defines the ingress configuration for Jaeger UI
//
// +kubebuilder:validation:Optional
Ingress *MonolithicJaegerUIIngressSpec `json:"ingress,omitempty"`

// Route defines the route configuration for Jaeger UI
//
// +kubebuilder:validation:Optional
Route *MonolithicJaegerUIRouteSpec `json:"route,omitempty"`
}

// MonolithicJaegerUIIngressSpec defines the settings for the Jaeger UI ingress.
type MonolithicJaegerUIIngressSpec struct {
// Enabled defines if an Ingress object should be created for Jaeger UI
//
// +kubebuilder:validation:Required
Enabled bool `json:"enabled"`
}

// MonolithicJaegerUIRouteSpec defines the settings for the Jaeger UI route.
type MonolithicJaegerUIRouteSpec struct {
// Enabled defines if a Route object should be created for Jaeger UI
//
// +kubebuilder:validation:Required
Enabled bool `json:"enabled"`
}

// MonolithicObservabilitySpec defines the observability settings of the Tempo deployment.
type MonolithicObservabilitySpec struct {
// Metrics defines the metrics configuration of the Tempo deployment
//
// +kubebuilder:validation:Optional
Metrics *MonolithicObservabilityMetricsSpec `json:"metrics,omitempty"`
}

// MonolithicObservabilityMetricsSpec defines the metrics settings of the Tempo deployment.
type MonolithicObservabilityMetricsSpec struct {
// ServiceMonitors defines the ServiceMonitor configuration
//
// +kubebuilder:validation:Optional
ServiceMonitors *MonolithicObservabilityMetricsServiceMonitorsSpec `json:"serviceMonitors,omitempty"`

// ServiceMonitors defines the PrometheusRule configuration
//
// +kubebuilder:validation:Optional
PrometheusRules *MonolithicObservabilityMetricsPrometheusRulesSpec `json:"prometheusRules,omitempty"`
}

// MonolithicObservabilityMetricsServiceMonitorsSpec defines the ServiceMonitor settings.
type MonolithicObservabilityMetricsServiceMonitorsSpec struct {
// Enabled defines if the operator should create ServiceMonitors for this Tempo deployment
//
// +kubebuilder:validation:Required
Enabled bool `json:"enabled"`
}

// MonolithicObservabilityMetricsPrometheusRulesSpec defines the PrometheusRules settings.
type MonolithicObservabilityMetricsPrometheusRulesSpec struct {
// Enabled defines if the operator should create PrometheusRules for this Tempo deployment
//
// +kubebuilder:validation:Required
Enabled bool `json:"enabled"`
}

// TempoMonolithicStatus defines the observed state of TempoMonolithic.
type TempoMonolithicStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
}

//+kubebuilder:object:root=true
//+kubebuilder:subresource:status

// TempoMonolithic is the Schema for the tempomonolithics API.
type TempoMonolithic struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec TempoMonolithicSpec `json:"spec,omitempty"`
Status TempoMonolithicStatus `json:"status,omitempty"`
}

//+kubebuilder:object:root=true

// TempoMonolithicList contains a list of TempoMonolithic.
type TempoMonolithicList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []TempoMonolithic `json:"items"`
}

func init() {
SchemeBuilder.Register(&TempoMonolithic{}, &TempoMonolithicList{})
}
96 changes: 96 additions & 0 deletions apis/tempo/v1alpha1/tempomonolithic_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package v1alpha1

import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

// SetupWebhookWithManager will setup the manager to manage the webhooks.
func (r *TempoMonolithic) SetupWebhookWithManager(mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}

// Default sets all default values in a central place, instead of setting it at every place where the value is accessed.
// NOTE: This function is called inside the Reconcile loop, NOT in the webhook.
// We want to keep the CR as minimal as the user configures it, and not modify it in any way (except for upgrades).
func (r *TempoMonolithic) Default() {
if r.Spec.Storage == nil {
r.Spec.Storage = &MonolithicStorageSpec{}
}

if r.Spec.Storage.Traces.Backend == "" {
r.Spec.Storage.Traces.Backend = MonolithicTracesStorageBackendMemory
}

if r.Spec.Storage.Traces.Backend != MonolithicTracesStorageBackendMemory && r.Spec.Storage.Traces.WAL == nil {
r.Spec.Storage.Traces.WAL = &MonolithicTracesStorageWALSpec{
Size: tenGBQuantity,
}
}

if r.Spec.Storage.Traces.Backend == MonolithicTracesStorageBackendPV && r.Spec.Storage.Traces.PV == nil {
r.Spec.Storage.Traces.PV = &MonolithicTracesStoragePVSpec{
Size: tenGBQuantity,
}
}

if r.Spec.Ingestion == nil {
r.Spec.Ingestion = &MonolithicIngestionSpec{}
}
if r.Spec.Ingestion.OTLP == nil {
r.Spec.Ingestion.OTLP = &MonolithicIngestionOTLPSpec{}
}
if r.Spec.Ingestion.OTLP.GRPC == nil {
r.Spec.Ingestion.OTLP.GRPC = &MonolithicIngestionOTLPProtocolsGRPCSpec{
Enabled: true,
}
}
if r.Spec.Ingestion.OTLP.HTTP == nil {
r.Spec.Ingestion.OTLP.HTTP = &MonolithicIngestionOTLPProtocolsHTTPSpec{
Enabled: true,
}
}
}

//+kubebuilder:webhook:path=/validate-tempo-grafana-com-v1alpha1-tempomonolithic,mutating=false,failurePolicy=fail,sideEffects=None,groups=tempo.grafana.com,resources=tempomonolithics,verbs=create;update,versions=v1alpha1,name=vtempomonolithic.kb.io,admissionReviewVersions=v1

var _ webhook.Validator = &TempoMonolithic{}

// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
func (r *TempoMonolithic) ValidateCreate() (admission.Warnings, error) {
return r.validate()
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
func (r *TempoMonolithic) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
return r.validate()
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
func (r *TempoMonolithic) ValidateDelete() (admission.Warnings, error) {
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
return r.validate()
}

func (tempo *TempoMonolithic) validate() (admission.Warnings, error) {
log := ctrl.Log.WithName("tempomonolithic-webhook")
log.V(1).Info("running validating webhook", "name", tempo.Name)

allWarnings := admission.Warnings{}
allErrors := field.ErrorList{}

if tempo.Spec.ExtraConfig != nil && len(tempo.Spec.ExtraConfig.Tempo.Raw) > 0 {
allWarnings = append(allWarnings, "overriding Tempo configuration could potentially break the deployment, use it carefully")
}

if len(allErrors) == 0 {
return allWarnings, nil
}
return allWarnings, apierrors.NewInvalid(tempo.GroupVersionKind().GroupKind(), tempo.Name, allErrors)
}
Loading

0 comments on commit d8afdec

Please sign in to comment.