Implement garbage collection
- add GarbageCollect predicate - remove the Kubernetes objects previously applied on the cluster, based on the prune label select - add garbage collection spec to docs
This commit is contained in:
parent
c1cb216262
commit
eee47333cf
39
README.md
39
README.md
|
|
@ -1,5 +1,7 @@
|
|||
# kustomize-controller
|
||||
|
||||
[](https://github.com/fluxcd/kustomize-controller/actions)
|
||||
|
||||
The kustomize-controller is a Kubernetes operator that applies kustomizations in-cluster.
|
||||
|
||||

|
||||
|
|
@ -19,7 +21,7 @@ A kustomization object defines the source of Kubernetes manifests by referencing
|
|||
the path to the kustomization file,
|
||||
and a label selector used for garbage collection of resources removed from the Git source.
|
||||
|
||||
Specification:
|
||||
### Specification
|
||||
|
||||
```go
|
||||
// KustomizationSpec defines the desired state of a kustomization.
|
||||
|
|
@ -29,7 +31,7 @@ type KustomizationSpec struct {
|
|||
// +required
|
||||
Path string `json:"path"`
|
||||
|
||||
// Label selector used for prune operations, e.g. env=staging.
|
||||
// Label selector used for garbage collection.
|
||||
// +kubebuilder:validation:Pattern="^.*=.*$"
|
||||
// +optional
|
||||
Prune string `json:"prune,omitempty"`
|
||||
|
|
@ -44,9 +46,27 @@ type KustomizationSpec struct {
|
|||
}
|
||||
```
|
||||
|
||||
Supported source kinds:
|
||||
### Supported source kinds
|
||||
|
||||
* [GitRepository](https://github.com/fluxcd/source-controller/blob/master/docs/spec/v1alpha1/gitrepositories.md)
|
||||
|
||||
### Garbage collection
|
||||
|
||||
Garbage collection means that the Kubernetes objects that were previously applied on the cluster
|
||||
but are missing from the current apply, will be removed. Garbage collection is also performed when a Kustomization
|
||||
object is deleted, triggering a removal of all Kubernetes objects previously applied on the cluster.
|
||||
|
||||
When garbage collection is enabled, all Kubernetes objects must have a common label that matches the `prune`
|
||||
[label selector](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/).
|
||||
|
||||
For example, `prune: env=dev` requires a `kustomization.yaml` with `commonLabels`:
|
||||
```yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
commonLabels:
|
||||
env: dev
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Build prerequisites:
|
||||
|
|
@ -74,6 +94,8 @@ make docker-build docker-push dev-deploy IMG=your-docker-hub-username/kustomize-
|
|||
|
||||
### Define a Git repository source
|
||||
|
||||
Create a source object that points to a Git repository containing Kubernetes and Kustomize manifests:
|
||||
|
||||
```yaml
|
||||
apiVersion: source.fluxcd.io/v1alpha1
|
||||
kind: GitRepository
|
||||
|
|
@ -87,6 +109,9 @@ spec:
|
|||
branch: master
|
||||
```
|
||||
|
||||
For private repositories, SSH or token based authentication can be
|
||||
[configured with Kubernetes secrets](https://github.com/fluxcd/source-controller/blob/master/docs/spec/v1alpha1/gitrepositories.md).
|
||||
|
||||
Save the above file and apply it on the cluster.
|
||||
You can wait for the source controller to assemble an artifact from the head of the repo master branch with:
|
||||
|
||||
|
|
@ -118,9 +143,9 @@ spec:
|
|||
name: podinfo
|
||||
```
|
||||
|
||||
With `spec.path` we tell the controller where to look for the kustomization file and with `spec.prune` we
|
||||
configure garbage collection. With `spec.interval` we tell the controller how often it should reconcile
|
||||
the cluster state.
|
||||
With `spec.path` we tell the controller where to look for the `kustomization.yaml` file.
|
||||
With `spec.prune` we configure garbage collection.
|
||||
With `spec.interval` we tell the controller how often it should reconcile the cluster state.
|
||||
|
||||
Save the above file and apply it on the cluster.
|
||||
You can wait for the kustomize controller to apply the manifest corresponding to the dev overlay with:
|
||||
|
|
@ -201,7 +226,7 @@ spec:
|
|||
Based on the above definition, the kustomize controller will build and apply a kustomization that matches the semver range
|
||||
set in the Git repository manifest.
|
||||
|
||||
## GitOps pipeline
|
||||
## GitOps workflow
|
||||
|
||||
Example:
|
||||
* create a `GitRepository` per app (example repo [podinfo-deploy](https://github.com/stefanprodan/podinfo-deploy))
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ type KustomizationSpec struct {
|
|||
// +required
|
||||
Path string `json:"path"`
|
||||
|
||||
// Label selector used for prune operations, e.g. env=staging.
|
||||
// Label selector used for garbage collection.
|
||||
// +kubebuilder:validation:Pattern="^.*=.*$"
|
||||
// +optional
|
||||
Prune string `json:"prune,omitempty"`
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ spec:
|
|||
pattern: ^\./
|
||||
type: string
|
||||
prune:
|
||||
description: Label selector used for prune operations, e.g. env=staging.
|
||||
description: Label selector used for garbage collection.
|
||||
pattern: ^.*=.*$
|
||||
type: string
|
||||
sourceRef:
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ func (r *KustomizationReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
|
|||
// try git sync
|
||||
syncedKustomization, err := r.sync(ctx, *kustomization.DeepCopy(), source)
|
||||
if err != nil {
|
||||
log.Error(err, "Kustomization sync failed")
|
||||
log.Error(err, "Kustomization apply failed")
|
||||
}
|
||||
|
||||
// update status
|
||||
|
|
@ -101,6 +101,7 @@ func (r *KustomizationReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
|
|||
func (r *KustomizationReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&kustomizev1.Kustomization{}).
|
||||
WithEventFilter(KustomizationGarbageCollectPredicate{Log: r.Log}).
|
||||
WithEventFilter(KustomizationSyncAtPredicate{}).
|
||||
Complete(r)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ limitations under the License.
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
|
||||
|
|
@ -50,3 +54,30 @@ func (KustomizationSyncAtPredicate) Update(e event.UpdateEvent) bool {
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
type KustomizationGarbageCollectPredicate struct {
|
||||
predicate.Funcs
|
||||
Log logr.Logger
|
||||
}
|
||||
|
||||
// Delete removes all Kubernetes objects based on the prune label selector.
|
||||
func (gc KustomizationGarbageCollectPredicate) Delete(e event.DeleteEvent) bool {
|
||||
if k, ok := e.Object.(*kustomizev1.Kustomization); ok {
|
||||
if k.Spec.Prune != "" {
|
||||
cmd := fmt.Sprintf("kubectl delete all --all-namespaces --timeout=%s -l %s",
|
||||
k.Spec.Interval.Duration.String(), k.Spec.Prune)
|
||||
command := exec.Command("/bin/sh", "-c", cmd)
|
||||
if output, err := command.CombinedOutput(); err != nil {
|
||||
gc.Log.Error(err, "Garbage collection failed",
|
||||
"output", string(output),
|
||||
"Kustomization", fmt.Sprintf("%s/%s", k.GetNamespace(), k.GetName()))
|
||||
} else {
|
||||
gc.Log.Info("Garbage collection completed",
|
||||
"output", string(output),
|
||||
"Kustomization", fmt.Sprintf("%s/%s", k.GetNamespace(), k.GetName()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue