Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ go.work

# Kubeconfig might contain secrets
*.kubeconfig

# Go binary downloads
*.tar.gz
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
> Right now, only Pods, Deployments and ReplicaSets are being watched, slowly but surely, other resources will be watched.
> Right now, Pods, Deployments, ReplicaSets and Nodes are being watched, slowly but surely, other resources will be watched.
> Not only logging, metrics will also be exposed for all resources.
> New functionalities are otw.

# Logger Controller

A Kubernetes **observer-style controller** that watches **Pods**, **Deployments** and **ReplicaSets** and logs their state based on a declarative Custom Resource (`Logger`).
A Kubernetes **observer-style controller** that watches **Pods**, **Deployments**, **ReplicaSets** and **Nodes** and logs their state based on a declarative Custom Resource (`Logger`).

Built using **Kubebuilder / controller-runtime**, this project focuses on reconciliation, watches, and logging patterns rather than resource mutation.

Expand All @@ -13,14 +13,14 @@ Built using **Kubebuilder / controller-runtime**, this project focuses on reconc
## What this controller does

- Defines a `Logger` Custom Resource
- Watches **Pod**, **Deployment** and **ReplicaSet** events (create / update / delete)
- On every Pod/Deployment/ReplicaSet event:
- Watches **Pod**, **Deployment**, **ReplicaSet** and **Node** events (create / update / delete)
- On every Pod/Deployment/ReplicaSet/Node event:
- Reconciles matching `Logger` resources
- Logs the current state of Pods/Deployments
- Logs the current state of Pods/Deployments/ReplicaSets/Nodes
- Supports:
- Namespace-scoped or cluster-scoped logging
- Exclusion of Kubernetes system namespaces
- Does **not** modify Pods/Deployments/Replicasets or any cluster resources
- Does **not** modify Pods/Deployments/ReplicaSets/Nodes or any cluster resources

This is an **observer controller**, not a CRUD controller.

Expand Down Expand Up @@ -67,7 +67,7 @@ Make sure that the context of kubectl is set to your target cluster, if you have
Next, we want to install our CRD into our cluster. For that, an example CRD file has been provided, ```example/crd.yaml```. Make the changes you want and run the
```make install``` command from repo root.

Go ahead and make some resources (Pods/Deployments/Replicasets) on your cluster, which you want observed.
Go ahead and make some resources (Pods/Deployments/ReplicaSets/Nodes) on your cluster, which you want observed.

Then, make CR for you CRD, using the command
```kubectl create -f example/crd.yaml``` from repo root.
Expand Down Expand Up @@ -100,7 +100,8 @@ spec:
resources:
- pods
- deployments
-replicasets
- replicasets
- nodes
trigger: 30s


10 changes: 9 additions & 1 deletion config/samples/logger_v1_logger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,12 @@ metadata:
app.kubernetes.io/managed-by: kustomize
name: logger-sample
spec:
# TODO(user): Add fields here
scope:
type: namespace
namespace: default
resources:
- pods
- deployments
- replicasets
- nodes
trigger: 30s
1 change: 1 addition & 0 deletions example/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ spec:
- pods
- deployments
- replicasets
- nodes
trigger: 30s
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ go 1.25.3
require (
github.com/onsi/ginkgo/v2 v2.27.2
github.com/onsi/gomega v1.38.2
go.uber.org/zap v1.27.0
k8s.io/api v0.35.0
k8s.io/apimachinery v0.35.0
k8s.io/client-go v0.35.0
sigs.k8s.io/controller-runtime v0.23.1
Expand Down Expand Up @@ -64,7 +66,6 @@ require (
go.opentelemetry.io/otel/trace v1.36.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
Expand All @@ -85,7 +86,6 @@ require (
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.35.0 // indirect
k8s.io/apiextensions-apiserver v0.35.0 // indirect
k8s.io/apiserver v0.35.0 // indirect
k8s.io/component-base v0.35.0 // indirect
Expand Down
Binary file removed go1.23.4.linux-amd64.tar.gz
Binary file not shown.
4 changes: 3 additions & 1 deletion internal/controller/logger_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ func rsLine(rs appsv1.ReplicaSet) string {

func nodeLine(node corev1.Node) string {
return "node/" + node.Name + " " +
node.Namespace + " " +
fmt.Sprintf("%v", node.Status.Capacity)
}

Expand Down Expand Up @@ -370,6 +369,9 @@ func (r *LoggerReconciler) SetupWithManager(mgr ctrl.Manager) error {
).Watches(
&appsv1.Deployment{},
handler.EnqueueRequestsFromMapFunc(r.enqueueAllLoggers),
).Watches(
&appsv1.ReplicaSet{},
handler.EnqueueRequestsFromMapFunc(r.enqueueAllLoggers),
).Watches(
&corev1.Node{},
handler.EnqueueRequestsFromMapFunc(r.enqueueAllLoggers),
Expand Down
43 changes: 43 additions & 0 deletions internal/controller/logger_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ func testReplicaSet(name, namespace string) *appsv1.ReplicaSet {
}
}

func testNode(name string) *corev1.Node {
return &corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}
}

func observedCount(ctx context.Context, key types.NamespacedName) int32 {
logger := &loggerv1.Logger{}
if err := k8sClient.Get(ctx, key, logger); err != nil {
Expand Down Expand Up @@ -224,4 +232,39 @@ var _ = Describe("Logger Controller", func() {
}, 5*time.Second, 200*time.Millisecond).
Should(Equal(int32(12)))
})

It("logs nodes when nodes resource is requested", func() {
logger := &loggerv1.Logger{
ObjectMeta: metav1.ObjectMeta{
Name: loggerName,
Namespace: "default",
},
Spec: loggerv1.LoggerSpec{
Scope: loggerv1.ScopeSpec{
Type: "Cluster",
},
Resources: []string{"nodes"},
},
}

Expect(k8sClient.Create(ctx, testNode("node-a"))).To(Succeed())
Expect(k8sClient.Create(ctx, testNode("node-b"))).To(Succeed())

Expect(k8sClient.Create(ctx, logger)).To(Succeed())

reconciler := &LoggerReconciler{
Client: k8sClient,
Scheme: k8sClient.Scheme(),
}

_, err := reconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: loggerKey,
})
Expect(err).NotTo(HaveOccurred())

Eventually(func() int32 {
return observedCount(ctx, loggerKey)
}, 5*time.Second, 200*time.Millisecond).
Should(Equal(int32(2)))
})
})