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

add k8s events logging to alloy #263

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b276673
add k8s events logging to alloy
QuantumEnigmaa Nov 12, 2024
d1ecc0e
changelog
QuantumEnigmaa Nov 12, 2024
73c3a71
create the events-logger resource : either alloy or grafana-agent
QuantumEnigmaa Nov 14, 2024
c39115a
handle secret for authentication
QuantumEnigmaa Nov 14, 2024
3cfb909
merge with main and resolve conflicts
QuantumEnigmaa Nov 14, 2024
33cce97
fix alloy config property name
QuantumEnigmaa Nov 14, 2024
dedd9ad
merge with main
QuantumEnigmaa Nov 18, 2024
f49f6f3
merge with main
QuantumEnigmaa Nov 18, 2024
2e6c67f
merge with main
QuantumEnigmaa Nov 18, 2024
f09f504
fix build errors
QuantumEnigmaa Nov 18, 2024
9a8454c
rename k8s-events-config package to events-logger-config
QuantumEnigmaa Nov 19, 2024
a62b968
Apply suggestions from code review
QuantumEnigmaa Nov 19, 2024
8e78389
fix error log
QuantumEnigmaa Nov 19, 2024
6776f50
return correct configmap name depending on the events logger
QuantumEnigmaa Nov 19, 2024
27f1aef
return correct secret name depending on the events logger
QuantumEnigmaa Nov 19, 2024
83c572b
add scrapedNamespaces to alloy config create related function in common
QuantumEnigmaa Nov 19, 2024
ab44bc4
add tls config for alloy
QuantumEnigmaa Nov 19, 2024
ad0e906
fix formating in grafana-agent template
QuantumEnigmaa Nov 19, 2024
1469dff
hardcode controller.type and controller.replicas in alloyEvents template
QuantumEnigmaa Nov 19, 2024
25c8cb4
remove unused observabilityBundleVersion parameters and variable in e…
QuantumEnigmaa Nov 19, 2024
e0cb4a7
remove grafanaAgentSecretName and eventsLoggerSecretName from securit…
QuantumEnigmaa Nov 19, 2024
aa6917a
rename variables in events-logger-config's reconciler to a neutral name
QuantumEnigmaa Nov 19, 2024
049d2cc
make several functions private
QuantumEnigmaa Nov 19, 2024
ec83211
hardcode several fields in grafana-agent config template
QuantumEnigmaa Nov 19, 2024
ad971d0
rename comments and logs in agents-toggle's reconciler
QuantumEnigmaa Nov 19, 2024
194d1cc
enable events logger in main.go
QuantumEnigmaa Nov 20, 2024
b3e196e
fix formating in events-logger templates
QuantumEnigmaa Nov 20, 2024
cdc361c
remove unused field in alloy generateAlloyConfig
QuantumEnigmaa Nov 20, 2024
df3a66e
fix alloy-events secret name
QuantumEnigmaa Nov 20, 2024
5d04402
merge with main
QuantumEnigmaa Nov 20, 2024
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add kubernetes events logging in Alloy.
- Add support for Private CAs in alloy logs.
- Add KubeEventsLogger option and related methods in loggedCLuster package.
- Add `events-logger` flag in the operator.
Expand Down
11 changes: 6 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ import (
loggingreconciler "github.com/giantswarm/logging-operator/pkg/logging-reconciler"
"github.com/giantswarm/logging-operator/pkg/reconciler"
agentstoggle "github.com/giantswarm/logging-operator/pkg/resource/agents-toggle"
eventsloggerconfig "github.com/giantswarm/logging-operator/pkg/resource/grafana-agent-config"
eventsloggersecret "github.com/giantswarm/logging-operator/pkg/resource/grafana-agent-secret"
eventsloggerconfig "github.com/giantswarm/logging-operator/pkg/resource/events-logger-config"
eventsloggersecret "github.com/giantswarm/logging-operator/pkg/resource/events-logger-secret"
grafanadatasource "github.com/giantswarm/logging-operator/pkg/resource/grafana-datasource"
loggingconfig "github.com/giantswarm/logging-operator/pkg/resource/logging-config"
loggingcredentials "github.com/giantswarm/logging-operator/pkg/resource/logging-credentials"
Expand Down Expand Up @@ -167,11 +167,12 @@ func main() {
DefaultWorkloadClusterNamespaces: defaultNamespaces,
}

eventsLoggerSecret := eventsloggersecret.Reconciler{
Copy link
Contributor

Choose a reason for hiding this comment

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

You can remove this change I guess :D

Client: mgr.GetClient(),
eventsLoggerConfig := eventsloggerconfig.Reconciler{
Client: mgr.GetClient(),
DefaultWorkloadClusterNamespaces: defaultNamespaces,
QuentinBisson marked this conversation as resolved.
Show resolved Hide resolved
}

eventsLoggerConfig := eventsloggerconfig.Reconciler{
eventsLoggerSecret := eventsloggersecret.Reconciler{
Client: mgr.GetClient(),
}

Expand Down
16 changes: 16 additions & 0 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package common

import (
"context"
"fmt"

"github.com/pkg/errors"
netv1 "k8s.io/api/networking/v1"
Expand Down Expand Up @@ -76,3 +77,18 @@ func ReadProxyIngressURL(ctx context.Context, lc loggedcluster.Interface, client

return ingressURL, nil
}

func FormatScrapedNamespaces(lc loggedcluster.Interface, namespaces []string) string {
scrapedNamespaces := "[]"

if IsWorkloadCluster(lc) {
for i, ns := range namespaces {
if i == len(namespaces)-1 {
scrapedNamespaces += fmt.Sprintf("\"%s\"", ns)
}
scrapedNamespaces += fmt.Sprintf("\"%s\", ", ns)
}
}

return scrapedNamespaces
}
89 changes: 89 additions & 0 deletions pkg/resource/events-logger-config/alloy-events-config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package eventsloggerconfig

import (
"bytes"
_ "embed"
"fmt"
"text/template"

"github.com/Masterminds/sprig/v3"

"github.com/giantswarm/logging-operator/pkg/common"
loggedcluster "github.com/giantswarm/logging-operator/pkg/logged-cluster"
eventsloggersecret "github.com/giantswarm/logging-operator/pkg/resource/events-logger-secret"
loggingsecret "github.com/giantswarm/logging-operator/pkg/resource/logging-secret"
)

var (
//go:embed alloy/events-logger.alloy.template
alloyEvents string
alloyEventsTemplate *template.Template

//go:embed alloy/events-logger-config.alloy.yaml.template
alloyEventsConfig string
alloyEventsConfigTemplate *template.Template
)

func init() {
alloyEventsTemplate = template.Must(template.New("events-logger.alloy").Funcs(sprig.FuncMap()).Parse(alloyEvents))
alloyEventsConfigTemplate = template.Must(template.New("events-logger.alloy.yaml").Funcs(sprig.FuncMap()).Parse(alloyEventsConfig))
}

func GenerateAlloyEventsConfig(lc loggedcluster.Interface, defaultNamespaces []string) (string, error) {
var values bytes.Buffer

alloyConfig, err := generateAlloyConfig(lc, defaultNamespaces)
if err != nil {
return "", err
}

data := struct {
AlloyConfig string
SecretName string
}{
AlloyConfig: alloyConfig,
SecretName: eventsloggersecret.GetEventsLoggerSecretName(lc),
}

err = alloyEventsConfigTemplate.Execute(&values, data)
if err != nil {
return "", err
}

return values.String(), nil
}

func generateAlloyConfig(lc loggedcluster.Interface, defaultNamespaces []string) (string, error) {
var values bytes.Buffer

data := struct {
ClusterID string
Installation string
InsecureSkipVerify string
DefaultWorkloadClusterNamespaces []string
MaxBackoffPeriod string
LokiURLEnvVarName string
TenantIDEnvVarName string
BasicAuthUsernameEnvVarName string
BasicAuthPasswordEnvVarName string
ScrapedNamespaces string
}{
ClusterID: lc.GetClusterName(),
Installation: lc.GetInstallationName(),
InsecureSkipVerify: fmt.Sprintf("%t", lc.IsInsecureCA()),
DefaultWorkloadClusterNamespaces: defaultNamespaces,
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
MaxBackoffPeriod: common.MaxBackoffPeriod,
LokiURLEnvVarName: loggingsecret.AlloyLokiURLEnvVarName,
TenantIDEnvVarName: loggingsecret.AlloyTenantIDEnvVarName,
BasicAuthUsernameEnvVarName: loggingsecret.AlloyBasicAuthUsernameEnvVarName,
BasicAuthPasswordEnvVarName: loggingsecret.AlloyBasicAuthPasswordEnvVarName,
ScrapedNamespaces: common.FormatScrapedNamespaces(lc, defaultNamespaces),
QuentinBisson marked this conversation as resolved.
Show resolved Hide resolved
}

err := alloyEventsTemplate.Execute(&values, data)
if err != nil {
return "", err
}

return values.String(), nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This file was generated by logging-operator.
# It configures Alloy to be used as events logger.
# - configMap is generated from events-logger.alloy.template and passed as a string
# here and will be created by Alloy's chart.
# - Alloy runs as a deployment, with only 1 replica.
alloy:
alloy:
configMap:
create: true
content: |-
{{ .AlloyConfig | indent 8 }}
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
envFrom:
- secretRef:
name: {{ .SecretName }}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: false
runAsUser: 10
runAsGroup: 10
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
controller:
type: deployment
replicas: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
loki.source.kubernetes_events "local" {
namespaces = {{ .ScrapedNamespaces }}
forward_to = [loki.write.default.receiver]
}

// Loki target configuration
loki.write "default" {
endpoint {
url = env("{{ .LokiURLEnvVarName }}")
max_backoff_period = "{{ .MaxBackoffPeriod }}"
tenant_id = env("{{ .TenantIDEnvVarName }}")

basic_auth {
username = env("{{ .BasicAuthUsernameEnvVarName }}")
password = env("{{ .BasicAuthPasswordEnvVarName }}")
}

tls_config {
insecure_skip_verify = {{ .InsecureSkipVerify }}
}
}
external_labels = {
cluster_id = "{{ .ClusterID }}",
installation = "{{ .Installation }}",
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
installation = "{{ .Installation }}",
installation = "{{ .Installation }}",
scrape_job = "kubernetes-events",

Copy link
Contributor

Choose a reason for hiding this comment

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

To match with grafana agent

}
}

logging {
level = "info"
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
format = "logfmt"
}
68 changes: 68 additions & 0 deletions pkg/resource/events-logger-config/events-logger-config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package eventsloggerconfig

import (
"fmt"

"github.com/pkg/errors"

v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/giantswarm/logging-operator/pkg/common"
loggedcluster "github.com/giantswarm/logging-operator/pkg/logged-cluster"
)

const (
eventsLogggerConfigName = "events-logger-config"
grafanaAgentConfigName = "grafana-agent-config"
)

func GenerateEventsLoggerConfig(lc loggedcluster.Interface, defaultNamespaces []string) (v1.ConfigMap, error) {
var values string
var err error

switch lc.GetKubeEventsLogger() {
case common.EventsLoggerGrafanaAgent:
values, err = GenerateGrafanaAgentConfig(lc, defaultNamespaces)
if err != nil {
return v1.ConfigMap{}, err
}
case common.EventsLoggerAlloy:
values, err = GenerateAlloyEventsConfig(lc, defaultNamespaces)
if err != nil {
return v1.ConfigMap{}, err
}
default:
return v1.ConfigMap{}, errors.Errorf("unsupported events logger %q", lc.GetKubeEventsLogger())
}

configmap := v1.ConfigMap{
ObjectMeta: ConfigMeta(lc),
Data: map[string]string{
"values": values,
},
}

return configmap, nil
}

// ConfigMeta returns metadata for the logging-config
func ConfigMeta(lc loggedcluster.Interface) metav1.ObjectMeta {
metadata := metav1.ObjectMeta{
Name: getEventsLoggerConfigName(lc),
Namespace: lc.GetAppsNamespace(),
Labels: map[string]string{},
}

common.AddCommonLabels(metadata.Labels)
return metadata
}

func getEventsLoggerConfigName(lc loggedcluster.Interface) string {
switch lc.GetKubeEventsLogger() {
case common.EventsLoggerGrafanaAgent:
return fmt.Sprintf("%s-%s", lc.GetClusterName(), grafanaAgentConfigName)
default:
return fmt.Sprintf("%s-%s", lc.GetClusterName(), eventsLogggerConfigName)
}
}
86 changes: 86 additions & 0 deletions pkg/resource/events-logger-config/grafana-agent-config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package eventsloggerconfig

import (
"bytes"
_ "embed"
"fmt"
"text/template"

"github.com/Masterminds/sprig/v3"

"github.com/giantswarm/logging-operator/pkg/common"
loggedcluster "github.com/giantswarm/logging-operator/pkg/logged-cluster"
eventsloggersecret "github.com/giantswarm/logging-operator/pkg/resource/events-logger-secret"
)

var (
//go:embed grafana-agent/events-logger.grafanaagent.template
grafanaAgent string
grafanaAgentTemplate *template.Template

//go:embed grafana-agent/events-logger-config.grafanaagent.yaml.template
grafanaAgentConfig string
grafanaAgentConfigTemplate *template.Template
)

func init() {
grafanaAgentTemplate = template.Must(template.New("events-logger.grafanaagent").Funcs(sprig.FuncMap()).Parse(grafanaAgent))
grafanaAgentConfigTemplate = template.Must(template.New("events-logger.grafanaagent.yaml").Funcs(sprig.FuncMap()).Parse(grafanaAgentConfig))
}

// GenerateGrafanaAgentConfig returns a configmap for
// the grafana-agent extra-config
func GenerateGrafanaAgentConfig(lc loggedcluster.Interface, defaultNamespaces []string) (string, error) {
var values bytes.Buffer

grafanaAgentInnerConfig, err := generateGrafanaAgentInnerConfig(lc, defaultNamespaces)
if err != nil {
return "", err
}

data := struct {
GrafanaAgentInnerConfig string
Replicas int
Type string
Create string
}{
GrafanaAgentInnerConfig: grafanaAgentInnerConfig,
Replicas: 1,
Type: "deployment",
Create: "false",
}

err = grafanaAgentConfigTemplate.Execute(&values, data)
if err != nil {
return "", err
}

return values.String(), nil
}

func generateGrafanaAgentInnerConfig(lc loggedcluster.Interface, defaultNamespaces []string) (string, error) {
var values bytes.Buffer

data := struct {
ClusterID string
Installation string
InsecureSkipVerify string
SecretName string
SecretNamespace string
ScrapedNamespaces string
}{
ClusterID: lc.GetClusterName(),
Installation: lc.GetInstallationName(),
InsecureSkipVerify: fmt.Sprintf("%t", lc.IsInsecureCA()),
SecretName: eventsloggersecret.GetEventsLoggerSecretName(lc),
SecretNamespace: lc.GetAppsNamespace(),
ScrapedNamespaces: common.FormatScrapedNamespaces(lc, defaultNamespaces),
}

err := grafanaAgentTemplate.Execute(&values, data)
if err != nil {
return "", err
}

return values.String(), nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# This file was generated by logging-operator.
# It configures the Grafana-agent to be used as events logger.
# - configMap is generated from events-logger.grafanaagent.template and passed as a string
# here and will be created by Grafana-agent's chart.
# - Grafana-agent runs as a deployment, with only 1 replica.
grafana-agent:
agent:
configMap:
content: |-
{{ .GrafanaAgentInnerConfig | indent 8 }}
QuantumEnigmaa marked this conversation as resolved.
Show resolved Hide resolved
controller:
replicas: {{ .Replicas }}
type: {{ .Type }}
crds:
create: {{ .Create }}
Loading