Skip to content

Commit e975298

Browse files
Jeff McCormickjmccormick2001jmrodri
authored
add resource pruning docs to best practices section (#5337)
* add resource pruning docs to best practices section * add more realistic preDeleteHook example * update website/content/en/docs/best-practices/resource-pruning.md * add time.Duration link * make Note boldface to draw attention Signed-off-by: Jeff McCormick <[email protected]> Co-authored-by: Jeff McCormick <[email protected]> Co-authored-by: Jesus Rodriguez <[email protected]>
1 parent 99e4731 commit e975298

File tree

1 file changed

+165
-0
lines changed

1 file changed

+165
-0
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
---
2+
title: "Resource pruning"
3+
linkTitle: "Resource Pruning"
4+
weight: 3
5+
description: Recommendations for pruning resources
6+
---
7+
8+
## Overview
9+
10+
Operators can create [Jobs][jobs] or Pods as part of their normal operation, and when those Jobs or Pods
11+
complete, they can remain on the Kubernetes cluster if not specifically removed. These resources
12+
can consume valuable cluster resources like disk storage (e.g. etcd). These resources
13+
are not tied to a Custom Resource using an `ownerReference`.
14+
15+
Operator authors have traditionally had two pruning options:
16+
17+
* leave the resource cleanup to a system admin to perform
18+
* implement some form of pruning within their operator solution
19+
20+
For our purposes when we say, *prune*, we mean to remove a resource (e.g. kubectl delete) from
21+
a Kubernetes cluster for a given namespace.
22+
23+
This documentation describes the pattern and library useful for implementing a solution within an operator.
24+
25+
## operator-lib prune library
26+
27+
A simple pruning implementation can be found in the [operator-lib prune package][operator-lib-prune]. This
28+
package is written in Go and is meant to be used within Go-based operators. This package was
29+
developed to include common pruning strategies as found in common operators. The package also allow
30+
for customization of hooks and strategies.
31+
32+
### Pruning Configuration
33+
34+
Users can configure the pruning library by creating code similar to this example:
35+
```golang
36+
cfg = Config{
37+
log: logf.Log.WithName("prune"),
38+
DryRun: false,
39+
Clientset: client,
40+
LabelSelector: "app=churro",
41+
Resources: []schema.GroupVersionKind{
42+
{Group: "", Version: "", Kind: PodKind},
43+
},
44+
Namespaces: []string{"default"},
45+
Strategy: StrategyConfig{
46+
Mode: MaxCountStrategy,
47+
MaxCountSetting: 1,
48+
},
49+
PreDeleteHook: myhook,
50+
}
51+
```
52+
53+
54+
| Config Field | Description
55+
| ------------ | -----------
56+
| log | a logger to handle library log messages
57+
| DryRun | a boolean determines whether to actually remove resources; `true` means to execute but not to remove resources
58+
| Clientset | a client-go Kubernetes ClientSet that will be used for Kube API calls by the library
59+
| LabelSelector| Kubernetes label selector expression used to find resources to prune
60+
| Resources | Kube resource Kinds, currently PodKind and JobKind are supported by the library
61+
| Namespaces | a list of Kube Namespaces to search for resources
62+
| Strategy | specifies the pruning strategy to execute
63+
| Strategy.Mode| currently MaxCountStrategy, MaxAgeStrategy, or CustomStrategy are supported
64+
| Strategy.MaxCountSetting| integer value for *maxcount* strategy, specifies how many resources should remain after pruning executes
65+
| Strategy.MaxAgeSetting| golang time.Duration string value (e.g. 48h), specifies age of resources to prune
66+
| Strategy.CustomSettings| a golang map of values that can be passed into a Custom strategy function
67+
| PreDeleteHook| optionally specifies a golang function to call before pruning a resource
68+
| CustomStrategy | optionally specifies a golang function that implements a custom pruning strategy
69+
70+
71+
### Pruning Execution
72+
73+
Users can invoke the pruning by running the *Execute* function on the pruning configuration
74+
as follows:
75+
```golang
76+
err := cfg.Execute(ctx)
77+
```
78+
79+
Users might want to implement pruning execution by means of a cron package or simply call the prune
80+
library based on some other triggering event.
81+
82+
## Pruning Strategies
83+
84+
### maxcount Strategy
85+
86+
A strategy of leaving a finite set of resources is implemented called *maxcount*. This strategy
87+
seeks to leave a specific number of resources, sorted by latest, on your cluster. For example, if
88+
you have 10 resources that would be pruned, and you specified a *maxcount* value of 4, then 6
89+
resources would be pruned (removed) from your cluster starting with the oldest resources.
90+
91+
### maxage Strategy
92+
93+
A strategy of removing resources greater than a specific time is called *maxage*. This strategy
94+
seeks to remove resources older than a specified *maxage* duration. For example, a library
95+
user might specify a value of *48h* to indicate that any resource older than 48 hours would be
96+
pruned. Durations are specified using golang's [time.Duration formatting] (e.g. 48h).
97+
98+
## Pruning Customization
99+
100+
### preDelete Hook
101+
102+
Users can provide a *preDelete* hook when using the [operator-lib prune package][operator-lib-prune].
103+
This hook function will be called by the library before removing a resource. This provides a means to examine
104+
the resource logs for example, extracting any valued content, before the resource is removed
105+
from the cluster.
106+
107+
Here is an example of a *preDelete* hook:
108+
```golang
109+
func myhook(cfg Config, x ResourceInfo) error {
110+
fmt.Println("myhook is called ")
111+
if x.GVK.Kind == PodKind {
112+
req := cfg.Clientset.CoreV1().Pods(x.Namespace).GetLogs(x.Name, &v1.PodLogOptions{})
113+
podLogs, err := req.Stream(context.Background())
114+
if err != nil {
115+
return err
116+
}
117+
defer podLogs.Close()
118+
119+
buf := new(bytes.Buffer)
120+
_, err = io.Copy(buf, podLogs)
121+
if err != nil {
122+
return err
123+
}
124+
125+
fmt.Printf("pod log before removing is %s\n", buf.String())
126+
}
127+
return nil
128+
}
129+
```
130+
131+
*Note* if your custom hook returns an error, then the resource will not be removed by the
132+
prune library.
133+
134+
### Custom Strategy
135+
136+
Library users can also write their own custom pruning strategy function to support advanced
137+
cases. Custom strategy functions are passed in the prune configuration and a list of resources selected by
138+
the library. The custom strategy builds up a list of resources to be removed, returning the list to the prune library which
139+
performs the actual resource removal. Here is an example custom strategy:
140+
```golang
141+
func myStrategy(cfg Config, resources []ResourceInfo) (resourcesToRemove []ResourceInfo, err error) {
142+
fmt.Printf("myStrategy is called with resources %v config %v\n", resources, cfg)
143+
if len(resources) != 3 {
144+
return resourcesToRemove, fmt.Errorf("count of resources did not equal our expectation")
145+
}
146+
return resourcesToRemove, nil
147+
}
148+
```
149+
150+
151+
To have your custom strategy invoked, you will specify your function within the prune configuration
152+
as follows:
153+
```golang
154+
cfg.Strategy.Mode = CustomStrategy
155+
cfg.Strategy.CustomSettings = make(map[string]interface{})
156+
cfg.CustomStrategy = myStrategy
157+
```
158+
159+
Notice that you can optionally pass in settings to your custom function as a map using the `cfg.Strategy.CustomSettings` field.
160+
161+
162+
[operator-lib]: https://github.com/operator-framework/operator-lib
163+
[operator-lib-prune]: https://github.com/operator-framework/operator-lib/tree/main/prune
164+
[jobs]: https://kubernetes.io/docs/concepts/workloads/controllers/job/
165+
[time.Duration formatting]: https://pkg.go.dev/time#Duration

0 commit comments

Comments
 (0)